| Index: base/android/linker/linker_jni.cc
|
| diff --git a/base/android/linker/linker_jni.cc b/base/android/linker/linker_jni.cc
|
| index 0222e49b344b695f4049aa375ebaffa0f225a416..46aa45d6da754c993929b5cdf649e46065050918 100644
|
| --- a/base/android/linker/linker_jni.cc
|
| +++ b/base/android/linker/linker_jni.cc
|
| @@ -71,31 +71,6 @@ String::String(JNIEnv* env, jstring str) {
|
| env->ReleaseStringUTFChars(str, bytes);
|
| }
|
|
|
| -// A scoped crazy_library_t that automatically closes the handle
|
| -// on scope exit, unless Release() has been called.
|
| -class ScopedLibrary {
|
| - public:
|
| - ScopedLibrary() : lib_(NULL) {}
|
| -
|
| - ~ScopedLibrary() {
|
| - if (lib_)
|
| - crazy_library_close(lib_);
|
| - }
|
| -
|
| - crazy_library_t* Get() { return lib_; }
|
| -
|
| - crazy_library_t** GetPtr() { return &lib_; }
|
| -
|
| - crazy_library_t* Release() {
|
| - crazy_library_t* ret = lib_;
|
| - lib_ = NULL;
|
| - return ret;
|
| - }
|
| -
|
| - private:
|
| - crazy_library_t* lib_;
|
| -};
|
| -
|
| // Return a pointer to the base name from an input |path| string.
|
| const char* GetBaseNamePtr(const char* path) {
|
| const char* p = strrchr(path, '/');
|
| @@ -140,6 +115,25 @@ bool InitFieldId(JNIEnv* env,
|
| return true;
|
| }
|
|
|
| +// Initialize a jmethodID corresponding to the static method of a given
|
| +// |clazz|, with name |method_name| and signature |method_sig|.
|
| +// |env| is the current JNI environment handle.
|
| +// On success, return true and set |*method_id|.
|
| +bool InitStaticMethodId(JNIEnv* env,
|
| + jclass clazz,
|
| + const char* method_name,
|
| + const char* method_sig,
|
| + jmethodID* method_id) {
|
| + *method_id = env->GetStaticMethodID(clazz, method_name, method_sig);
|
| + if (!*method_id) {
|
| + LOG_ERROR("Could not find ID for static method '%s'", method_name);
|
| + return false;
|
| + }
|
| + LOG_INFO("%s: Found ID %p for static method '%s'",
|
| + __FUNCTION__, *method_id, method_name);
|
| + return true;
|
| +}
|
| +
|
| // A class used to model the field IDs of the org.chromium.base.Linker
|
| // LibInfo inner class, used to communicate data with the Java side
|
| // of the linker.
|
| @@ -221,6 +215,31 @@ crazy_context_t* GetCrazyContext() {
|
| return s_crazy_context;
|
| }
|
|
|
| +// A scoped crazy_library_t that automatically closes the handle
|
| +// on scope exit, unless Release() has been called.
|
| +class ScopedLibrary {
|
| + public:
|
| + ScopedLibrary() : lib_(NULL) {}
|
| +
|
| + ~ScopedLibrary() {
|
| + if (lib_)
|
| + crazy_library_close_with_context(lib_, GetCrazyContext());
|
| + }
|
| +
|
| + crazy_library_t* Get() { return lib_; }
|
| +
|
| + crazy_library_t** GetPtr() { return &lib_; }
|
| +
|
| + crazy_library_t* Release() {
|
| + crazy_library_t* ret = lib_;
|
| + lib_ = NULL;
|
| + return ret;
|
| + }
|
| +
|
| + private:
|
| + crazy_library_t* lib_;
|
| +};
|
| +
|
| // Load a library with the chromium linker. This will also call its
|
| // JNI_OnLoad() method, which shall register its methods. Note that
|
| // lazy native method resolution will _not_ work after this, because
|
| @@ -282,6 +301,89 @@ jboolean LoadLibrary(JNIEnv* env,
|
| return true;
|
| }
|
|
|
| +// Class holding the Java class and method ID for the Java side Linker
|
| +// postCallbackOnMainThread method.
|
| +struct JavaCallbackBindings_class {
|
| + jclass clazz;
|
| + jmethodID method_id;
|
| +
|
| + // Initialize an instance.
|
| + bool Init(JNIEnv* env, jclass linker_class) {
|
| + clazz = reinterpret_cast<jclass>(env->NewGlobalRef(linker_class));
|
| + return InitStaticMethodId(env,
|
| + linker_class,
|
| + "postCallbackOnMainThread",
|
| + "(J)V",
|
| + &method_id);
|
| + }
|
| +};
|
| +
|
| +static JavaCallbackBindings_class s_java_callback_bindings;
|
| +
|
| +// Designated receiver function for callbacks from Java. Its name is known
|
| +// to the Java side.
|
| +// |env| is the current JNI environment handle and is ignored here.
|
| +// |clazz| is the static class handle for org.chromium.base.Linker,
|
| +// and is ignored here.
|
| +// |arg| is a pointer to an allocated crazy_callback_t, deleted after use.
|
| +void RunCallbackOnUiThread(JNIEnv* env, jclass clazz, jlong arg) {
|
| + crazy_callback_t* callback = reinterpret_cast<crazy_callback_t*>(arg);
|
| +
|
| + LOG_INFO("%s: Called back from java with handler %p, opaque %p",
|
| + __FUNCTION__, callback->handler, callback->opaque);
|
| +
|
| + crazy_callback_run(callback);
|
| + delete callback;
|
| +}
|
| +
|
| +// Request a callback from Java. The supplied crazy_callback_t is valid only
|
| +// for the duration of this call, so we copy it to a newly allocated
|
| +// crazy_callback_t and then call the Java side's postCallbackOnMainThread.
|
| +// This will call back to to our RunCallbackOnUiThread some time
|
| +// later on the UI thread.
|
| +// |callback_request| is a crazy_callback_t.
|
| +// |poster_opaque| is unused.
|
| +// Returns true if the callback request succeeds.
|
| +static bool PostForLaterExecution(crazy_callback_t* callback_request,
|
| + void* poster_opaque UNUSED) {
|
| + crazy_context_t* context = GetCrazyContext();
|
| +
|
| + JavaVM* vm;
|
| + int minimum_jni_version;
|
| + crazy_context_get_java_vm(context,
|
| + reinterpret_cast<void**>(&vm),
|
| + &minimum_jni_version);
|
| +
|
| + // Do not reuse JNIEnv from JNI_OnLoad, but retrieve our own.
|
| + JNIEnv* env;
|
| + if (JNI_OK != vm->GetEnv(
|
| + reinterpret_cast<void**>(&env), minimum_jni_version)) {
|
| + LOG_ERROR("Could not create JNIEnv");
|
| + return false;
|
| + }
|
| +
|
| + // Copy the callback; the one passed as an argument may be temporary.
|
| + crazy_callback_t* callback = new crazy_callback_t();
|
| + *callback = *callback_request;
|
| +
|
| + LOG_INFO("%s: Calling back to java with handler %p, opaque %p",
|
| + __FUNCTION__, callback->handler, callback->opaque);
|
| +
|
| + jlong arg = static_cast<jlong>(reinterpret_cast<intptr_t>(callback));
|
| + env->CallStaticVoidMethod(
|
| + s_java_callback_bindings.clazz, s_java_callback_bindings.method_id, arg);
|
| +
|
| + // Back out and return false if we encounter a JNI exception.
|
| + if (env->ExceptionCheck() == JNI_TRUE) {
|
| + env->ExceptionDescribe();
|
| + env->ExceptionClear();
|
| + delete callback;
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| jboolean CreateSharedRelro(JNIEnv* env,
|
| jclass clazz,
|
| jstring library_name,
|
| @@ -391,6 +493,12 @@ const JNINativeMethod kNativeMethods[] = {
|
| ")"
|
| "Z",
|
| reinterpret_cast<void*>(&LoadLibrary)},
|
| + {"nativeRunCallbackOnUiThread",
|
| + "("
|
| + "J"
|
| + ")"
|
| + "V",
|
| + reinterpret_cast<void*>(&RunCallbackOnUiThread)},
|
| {"nativeCreateSharedRelro",
|
| "("
|
| "Ljava/lang/String;"
|
| @@ -433,8 +541,9 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
|
|
| // Register native methods.
|
| jclass linker_class;
|
| - if (!InitClassReference(
|
| - env, "org/chromium/base/library_loader/Linker", &linker_class))
|
| + if (!InitClassReference(env,
|
| + "org/chromium/base/library_loader/Linker",
|
| + &linker_class))
|
| return -1;
|
|
|
| LOG_INFO("%s: Registering native methods", __FUNCTION__);
|
| @@ -448,10 +557,20 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
| return -1;
|
| }
|
|
|
| + // Resolve and save the Java side Linker callback class and method.
|
| + LOG_INFO("%s: Resolving callback bindings", __FUNCTION__);
|
| + if (!s_java_callback_bindings.Init(env, linker_class)) {
|
| + return -1;
|
| + }
|
| +
|
| // Save JavaVM* handle into context.
|
| crazy_context_t* context = GetCrazyContext();
|
| crazy_context_set_java_vm(context, vm, JNI_VERSION_1_4);
|
|
|
| + // Register the function that the crazy linker can call to post code
|
| + // for later execution.
|
| + crazy_context_set_callback_poster(context, &PostForLaterExecution, NULL);
|
| +
|
| LOG_INFO("%s: Done", __FUNCTION__);
|
| return JNI_VERSION_1_4;
|
| }
|
|
|