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..ac5dba7d76928909f6d2bbc0a2a08d960ca75c69 100644 |
--- a/base/android/linker/linker_jni.cc |
+++ b/base/android/linker/linker_jni.cc |
@@ -140,6 +140,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. |
@@ -282,6 +301,81 @@ jboolean LoadLibrary(JNIEnv* env, |
return true; |
} |
+// Class to support simple callbacks from the Java side. Hold a pointer |
+// to a function taking a single void* argument, and an argument value. |
+struct callback_t { |
+ public: |
+ callback_t() : handler(NULL), opaque(NULL) { } |
+ |
+ void (*handler)(void*); |
+ void* opaque; |
+}; |
+ |
+// 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 callback_t. |
+void ReceiveCallbackFromMainThread(JNIEnv* env, jclass clazz, jlong arg) { |
+ callback_t* callback = reinterpret_cast<callback_t*>(arg); |
+ |
+ LOG_INFO("%s: Called back from java with handler %p, opaque %p", |
+ __FUNCTION__, callback->handler, callback->opaque); |
+ |
+ (*callback->handler)(callback->opaque); |
+ delete callback; |
+} |
+ |
+// Class holding the Java class and method ID for the Java side Linker |
+// PostCallbackOnMainThread method. Like crazy_context_t, there is |
+// only one of these, requiring no locking. |
+struct callback_refs_t { |
+ public: |
+ callback_refs_t() : clazz(NULL), method_id(NULL) { } |
+ |
+ jclass clazz; |
+ jmethodID method_id; |
+}; |
+ |
+static callback_refs_t s_callback_refs; |
+ |
+// Request a callback from Java. Constructs a new callback_t and calls |
+// the Java side's PostCallbackOnMainThread, which will some time later |
+// call back to our ReceiveCallbackFromMainThread. |
+// |handler| is a handler function, taking a single void* argument. |
+// |opaque| is the argument to supply to the handler when run in the callback. |
+// Returns true if the callback request succeeded. |
+static bool PostForLaterExecution(void (*handler)(void*), void *opaque) { |
bulach
2014/04/15 13:58:14
nit: s/void *opaque/void* opaque/
simonb1
2014/04/17 14:45:43
Done.
|
+ 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; |
+ } |
+ |
+ callback_t* callback = new callback_t(); |
+ callback->handler = handler; |
+ callback->opaque = opaque; |
+ |
+ 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); |
bulach
2014/04/15 13:58:14
need to clear any java exception (assuming it's sa
simonb1
2014/04/17 14:45:43
Done.
|
+ return true; |
+} |
+ |
jboolean CreateSharedRelro(JNIEnv* env, |
jclass clazz, |
jstring library_name, |
@@ -391,6 +485,12 @@ const JNINativeMethod kNativeMethods[] = { |
")" |
"Z", |
reinterpret_cast<void*>(&LoadLibrary)}, |
+ {"nativeReceiveCallbackFromMainThread", |
+ "(" |
+ "J" |
+ ")" |
+ "V", |
+ reinterpret_cast<void*>(&ReceiveCallbackFromMainThread)}, |
{"nativeCreateSharedRelro", |
"(" |
"Ljava/lang/String;" |
@@ -416,7 +516,6 @@ const JNINativeMethod kNativeMethods[] = { |
")" |
"J", |
reinterpret_cast<void*>(&GetPageSize)}, }; |
- |
} // namespace |
// JNI_OnLoad() hook called when the linker library is loaded through |
@@ -433,8 +532,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__); |
@@ -452,6 +552,21 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) { |
crazy_context_t* context = GetCrazyContext(); |
crazy_context_set_java_vm(context, vm, JNI_VERSION_1_4); |
+ // Resolve the Java side Linker callback method. |
+ jmethodID method_id; |
+ if (!InitStaticMethodId(env, |
+ linker_class, |
+ "PostCallbackOnMainThread", |
+ "(J)V", |
+ &method_id)) |
+ return -1; |
+ |
+ // Save the callback class and method, and register the function that |
+ // the crazy linker can call to post code for later execution. |
+ s_callback_refs.clazz = linker_class; |
+ s_callback_refs.method_id = method_id; |
+ crazy_context_set_post_for_later_execution(context, &PostForLaterExecution); |
+ |
LOG_INFO("%s: Done", __FUNCTION__); |
return JNI_VERSION_1_4; |
} |