Chromium Code Reviews| 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..b208a56255e0136611c84dd2304f55b96ddcf03a 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 CallbackRefs_class { |
|
bulach
2014/05/07 16:10:53
nit: the name should be CallbackRefsClass. however
simonb1
2014/05/07 17:25:24
Done.
|
| + jclass clazz; |
| + jmethodID method_id; |
| + |
| + // Initialize an instance. |
| + bool Init(JNIEnv* env, jclass linker_class) { |
| + clazz = linker_class; |
|
bulach
2014/05/07 16:10:53
nit: theoretically linker_class is a "localref" th
simonb1
2014/05/07 17:25:24
Done.
|
| + return InitStaticMethodId(env, |
| + linker_class, |
| + "postCallbackOnMainThread", |
| + "(J)V", |
| + &method_id); |
| + } |
| +}; |
| + |
| +static CallbackRefs_class s_callback_refs; |
| + |
| +// 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_callback_refs.clazz, s_callback_refs.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 references", __FUNCTION__); |
| + if (!s_callback_refs.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; |
| } |