Skip to content

Commit

Permalink
gapii: Pass the path of libinterceptor down in the header.
Browse files Browse the repository at this point in the history
This moves the loading of libinteceptor.so from jdwp_loader.go (gapit) to gapii.

It appears that on some devices dlopen() will not find libraries loaded by a prior call to System.loadLibrary(). Instead, pass the absolute path of libinteceptor.so down to libgapii.so and load it directly there.

Fixes: #1026
  • Loading branch information
ben-clayton committed Aug 30, 2017
1 parent 304f4b9 commit c3020cf
Show file tree
Hide file tree
Showing 10 changed files with 69 additions and 60 deletions.
3 changes: 2 additions & 1 deletion gapii/cc/android/gvr_install.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@

namespace gapii {

class Installer;
class GvrImports;

// install_gvr installs interceptor hooks into all the GVR functions.
bool install_gvr(void* gvr_lib, GvrImports* imports);
bool install_gvr(Installer* installer, void* gvr_lib, GvrImports* imports);

} // namespace gapii

Expand Down
33 changes: 6 additions & 27 deletions gapii/cc/android/installer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*/

#include "installer.h"
#include "../gles_exports.h"

#include "core/cc/assert.h"
Expand Down Expand Up @@ -117,27 +118,16 @@ void recordInterceptorError(void*, const char* message) {
GAPID_WARNING("Interceptor error: %s", message);
}

class Installer {
public:
Installer();
~Installer();

void* install(void* func_import, const void* func_export);
} // anonymous namespace

private:
void install_gles();
};
namespace gapii {

Installer::Installer() {
Installer::Installer(const char* libInterceptorPath) {
GAPID_INFO("Installing GAPII hooks...")

auto lib = dlopen("libinterceptor.so.4", RTLD_NOW);
auto lib = dlopen(libInterceptorPath, RTLD_NOW);
if (lib == nullptr) {
// Older versions of Android use the filename instead of the SONAME from the executable.
lib = dlopen("libinterceptor.so", RTLD_NOW);
}
if (lib == nullptr) {
GAPID_FATAL("Couldn't resolve the interceptor library.");
GAPID_FATAL("Couldn't load interceptor library from: %s", libInterceptorPath);
}

gInitializeInterceptor = reinterpret_cast<InitializeInterceptorFunc*>(dlsym(lib, "InitializeInterceptor"));
Expand Down Expand Up @@ -239,15 +229,4 @@ void Installer::install_gles() {
}
}

// The installer global instance.
Installer gInstaller;

} // anonymous namespace

namespace gapii {

void* install_function(void* func_import, const void* func_export) {
return gInstaller.install(func_import, func_export);
}

} // namespace gapii
17 changes: 13 additions & 4 deletions gapii/cc/android/installer.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,19 @@

namespace gapii {

// install_function installs a hook into func_import to call func_export.
// The returned function allows func_export to call back to the original
// function that was at func_import.
void* install_function(void* func_import, const void* func_export);
class Installer {
public:
Installer(const char* libInterceptorPath);
~Installer();

// install_function installs a hook into func_import to call func_export.
// The returned function allows func_export to call back to the original
// function that was at func_import.
void* install(void* func_import, const void* func_export);

private:
void install_gles();
};

} // namespace gapii

Expand Down
3 changes: 2 additions & 1 deletion gapii/cc/connection_header.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ bool ConnectionHeader::read(core::StreamReader* reader) {
!reader->read(mNumFrames) ||
!reader->read(mAPIs) ||
!reader->read(mFlags) ||
!reader->read(mGvrHandle)) {
!reader->read(mGvrHandle) ||
!reader->read(mLibInterceptorPath)) {
return false;
}

Expand Down
22 changes: 13 additions & 9 deletions gapii/cc/connection_header.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#ifndef GAPII_CONNECTION_HEADER_H
#define GAPII_CONNECTION_HEADER_H

#include <stddef.h>
#include <stdint.h>

namespace core {
Expand All @@ -35,6 +36,8 @@ class ConnectionHeader {
public:
ConnectionHeader();

static const size_t MAX_PATH = 512;

// Fakes no support for PCS, forcing the app to share shader source.
static const uint32_t FLAG_DISABLE_PRECOMPILED_SHADERS = 0x00000001;
// Driver errors are queried after each call and stored as extras.
Expand All @@ -46,15 +49,16 @@ class ConnectionHeader {
// on success or false on error.
bool read(core::StreamReader* reader);

uint8_t mMagic[4]; // 's', 'p', 'y', '0'
uint32_t mVersion; // 1
uint32_t mObserveFrameFrequency; // non-zero == enabled.
uint32_t mObserveDrawFrequency; // non-zero == enabled.
uint32_t mStartFrame; // non-zero == Frame to start at.
uint32_t mNumFrames; // non-zero == Number of frames to capture.
uint32_t mAPIs; // Bitset of APIS to enable.
uint32_t mFlags; // Combination of FLAG_XX bits.
uint64_t mGvrHandle; // Handle of GVR library.
uint8_t mMagic[4]; // 's', 'p', 'y', '0'
uint32_t mVersion; // 1
uint32_t mObserveFrameFrequency; // non-zero == enabled.
uint32_t mObserveDrawFrequency; // non-zero == enabled.
uint32_t mStartFrame; // non-zero == Frame to start at.
uint32_t mNumFrames; // non-zero == Number of frames to capture.
uint32_t mAPIs; // Bitset of APIS to enable.
uint32_t mFlags; // Combination of FLAG_XX bits.
uint64_t mGvrHandle; // Handle of GVR library.
char mLibInterceptorPath[MAX_PATH]; // Path of libinterceptor.so.
};

} // namespace gapii
Expand Down
10 changes: 9 additions & 1 deletion gapii/cc/spy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,15 @@
#endif // TARGET_OS == GAPID_OS_WINDOWS

#if TARGET_OS == GAPID_OS_ANDROID
#include "gapii/cc/android/installer.h"
#include "gapii/cc/android/gvr_install.h"

#include <sys/prctl.h>
#include <jni.h>

static std::unique_ptr<gapii::Installer> gInstaller;
static JavaVM* gJavaVM = nullptr;

extern "C"
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
GAPID_INFO("JNI_OnLoad() was called. vm = %p", vm);
Expand Down Expand Up @@ -188,10 +191,15 @@ Spy::Spy()
mCaptureFrames = header.mNumFrames;
mSuspendCaptureFrames.store((header.mFlags & ConnectionHeader::FLAG_DEFER_START)?
kSuspendIndefinitely: mSuspendCaptureFrames.load());
#if TARGET_OS == GAPID_OS_ANDROID
if (strlen(header.mLibInterceptorPath) > 0) {
gInstaller = std::unique_ptr<Installer>(new Installer(header.mLibInterceptorPath));
}
if (header.mGvrHandle != 0) {
auto gvr_lib = reinterpret_cast<void*>(header.mGvrHandle);
ANDROID_ONLY(install_gvr(gvr_lib, &this->GvrSpy::mImports));
install_gvr(gInstaller.get(), gvr_lib, &this->GvrSpy::mImports);
}
#endif // TARGET_OS == GAPID_OS_ANDROID
} else {
GAPID_FATAL("Failed to read connection header");
}
Expand Down
6 changes: 3 additions & 3 deletions gapii/client/capture.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func (s siSize) String() string {
return fmt.Sprintf(f, v)
}

func (p *Process) connect(ctx context.Context, gvrHandle uint64) error {
func (p *Process) connect(ctx context.Context, gvrHandle uint64, interceptorPath string) error {
log.I(ctx, "Waiting for connection to localhost:%d...", p.Port)

// ADB has an annoying tendancy to insta-close forwarded sockets when
Expand All @@ -103,7 +103,7 @@ func (p *Process) connect(ctx context.Context, gvrHandle uint64) error {
log.D(ctx, "Dial failed: %v", err)
return err
}
if err := sendHeader(conn, p.Options, gvrHandle); err != nil {
if err := sendHeader(conn, p.Options, gvrHandle, interceptorPath); err != nil {
log.D(ctx, "Failed to send header: %v", err)
conn.Close()
return err
Expand Down Expand Up @@ -134,7 +134,7 @@ func (c bufConn) Read(b []byte) (n int, err error) { return c.r.Read(b) }
// until s is fired.
func (p *Process) Capture(ctx context.Context, s task.Signal, w io.Writer) (int64, error) {
if p.conn == nil {
if err := p.connect(ctx, 0); err != nil {
if err := p.connect(ctx, 0, ""); err != nil {
return 0, err
}
}
Expand Down
26 changes: 16 additions & 10 deletions gapii/client/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,26 @@ const version = 1

// The GAPII header is defined as:
//
// const size_t MAX_PATH = 512;
//
// struct ConnectionHeader {
// uint8_t mMagic[4]; // 's', 'p', 'y', '0'
// uint32_t mVersion; // 1
// uint32_t mObserveFrameFrequency; // non-zero == enabled.
// uint32_t mObserveDrawFrequency; // non-zero == enabled.
// uint32_t mStartFrame; // non-zero == Frame to start at.
// uint32_t mNumFrames; // non-zero == Number of frames to capture.
// uint32_t mAPIs; // Bitset of APIS to enable.
// uint32_t mFlags; // Combination of FLAG_XX bits.
// uint8_t mMagic[4]; // 's', 'p', 'y', '0'
// uint32_t mVersion; // 1
// uint32_t mObserveFrameFrequency; // non-zero == enabled.
// uint32_t mObserveDrawFrequency; // non-zero == enabled.
// uint32_t mStartFrame; // non-zero == Frame to start at.
// uint32_t mNumFrames; // non-zero == Number of frames to capture.
// uint32_t mAPIs; // Bitset of APIS to enable.
// uint32_t mFlags; // Combination of FLAG_XX bits.
// char mLibInterceptorPath[MAX_PATH]; // Path to libinterceptor.so
// };
//
// All fields are encoded little-endian with no compression, regardless of
// architecture. All changes must be kept in sync with:
// platform/tools/gpu/gapii/cc/connection_header.h

func sendHeader(out io.Writer, options Options, gvrHandle uint64) error {
func sendHeader(out io.Writer, options Options, gvrHandle uint64, libInterceptorPath string) error {
const maxPath = 512
w := endian.Writer(out, device.LittleEndian)
for _, m := range magic {
w.Uint8(m)
Expand All @@ -55,6 +59,8 @@ func sendHeader(out io.Writer, options Options, gvrHandle uint64) error {
w.Uint32(options.APIs)
w.Uint32(uint32(options.Flags))
w.Uint64(gvrHandle)

var path [maxPath]byte
copy(path[:], libInterceptorPath)
w.Data(path[:])
return w.Error()
}
5 changes: 3 additions & 2 deletions gapii/client/jdwp_loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,22 +195,23 @@ func (p *Process) loadAndConnectViaJDWP(
// This has to be done on a separate go-routine as the call to load gapii
// will block until a connection is made.
connErr := make(chan error)
go func() { connErr <- p.connect(ctx, gvrHandle) }()

// Load GAPII library.
err = jdbg.Do(conn, onCreate.Thread, func(j *jdbg.JDbg) error {
abi, err := processABI(j)
if err != nil {
return err
}

interceptorPath := gapidAPK.LibInterceptorPath(abi)
go func() { connErr <- p.connect(ctx, gvrHandle, interceptorPath) }()

gapiiPath := gapidAPK.LibGAPIIPath(abi)
ctx = log.V{"gapii.so": gapiiPath, "process abi": abi.Name}.Bind(ctx)

// Load the library.
log.D(ctx, "Loading GAPII library...")
// Work around for loading libraries in the N previews. See b/29441142.
j.Class("java.lang.Runtime").Call("getRuntime").Call("doLoad", interceptorPath, nil)
j.Class("java.lang.Runtime").Call("getRuntime").Call("doLoad", gapiiPath, nil)
log.D(ctx, "Library loaded")
return nil
Expand Down
4 changes: 2 additions & 2 deletions gapis/api/gvr/templates/api_install.cpp.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
namespace gapii {«
bool install_gvr(void* gvr_lib, GvrImports* imports) {
bool install_gvr(Installer* installer, void* gvr_lib, GvrImports* imports) {
struct func_t {
const char* name;
void** imp;
Expand All @@ -54,7 +54,7 @@ bool install_gvr(void* gvr_lib, GvrImports* imports) {
for (auto func : funcs) {
if (auto import = dlsym(gvr_lib, func.name)) {
GAPID_INFO("Installing '%s'...", func.name);
*func.imp = gapii::install_function(import, func.exp);
*func.imp = installer->install(import, func.exp);
} else {
GAPID_WARNING("Could not find GVR function '%s'", func.name);
}
Expand Down

0 comments on commit c3020cf

Please sign in to comment.