OSDN Git Service

Binder: Change reaction to Error
authorAndreas Gampe <agampe@google.com>
Sat, 9 Sep 2017 00:44:05 +0000 (17:44 -0700)
committerAndreas Gampe <agampe@google.com>
Wed, 25 Oct 2017 00:08:18 +0000 (17:08 -0700)
Instead of aborting immediately with a native error, try to call
Thread.dispatchUncaughtException to trigger a Java-side abort.
Only fall back to the old strategy if this fails.

(cherry picked from commit 1cd76f5c93bc1e2409c880cade19a323cd999aed)

Bug: 64689630
Test: m
Test: manual test
Merged-In: If07a04d3769f3b9181c4736220333df9a2871a16
Change-Id: If07a04d3769f3b9181c4736220333df9a2871a16

core/jni/android_util_Binder.cpp

index 768f53f..a5a83f3 100644 (file)
@@ -133,6 +133,14 @@ static struct strict_mode_callback_offsets_t
     jmethodID mCallback;
 } gStrictModeCallbackOffsets;
 
+static struct thread_dispatch_offsets_t
+{
+    // Class state.
+    jclass mClass;
+    jmethodID mDispatchUncaughtException;
+    jmethodID mCurrentThread;
+} gThreadDispatchOffsets;
+
 // ****************************************************************************
 // ****************************************************************************
 // ****************************************************************************
@@ -166,6 +174,23 @@ static JNIEnv* javavm_to_jnienv(JavaVM* vm)
     return vm->GetEnv((void **)&env, JNI_VERSION_1_4) >= 0 ? env : NULL;
 }
 
+// Report a java.lang.Error (or subclass). This may terminate the runtime.
+static void report_java_lang_error(JNIEnv* env, jthrowable error)
+{
+    // Try to run the uncaught exception machinery.
+    jobject thread = env->CallStaticObjectMethod(gThreadDispatchOffsets.mClass,
+            gThreadDispatchOffsets.mCurrentThread);
+    if (thread != nullptr) {
+        env->CallVoidMethod(thread, gThreadDispatchOffsets.mDispatchUncaughtException,
+                error);
+        // Should not return here, unless more errors occured.
+    }
+    // Some error occurred that meant that either dispatchUncaughtException could not be
+    // called or that it had an error itself (as this should be unreachable under normal
+    // conditions). Clear the exception.
+    env->ExceptionClear();
+}
+
 static void report_exception(JNIEnv* env, jthrowable excep, const char* msg)
 {
     env->ExceptionClear();
@@ -192,6 +217,10 @@ static void report_exception(JNIEnv* env, jthrowable excep, const char* msg)
     }
 
     if (env->IsInstanceOf(excep, gErrorOffsets.mClass)) {
+        // Try to report the error. This should not return under normal circumstances.
+        report_java_lang_error(env, excep);
+        // The traditional handling: re-raise and abort.
+
         /*
          * It's an Error: Reraise the exception and ask the runtime to abort.
          */
@@ -1337,5 +1366,12 @@ int register_android_os_Binder(JNIEnv* env)
     gStrictModeCallbackOffsets.mCallback = GetStaticMethodIDOrDie(env, clazz,
             "onBinderStrictModePolicyChange", "(I)V");
 
+    clazz = FindClassOrDie(env, "java/lang/Thread");
+    gThreadDispatchOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
+    gThreadDispatchOffsets.mDispatchUncaughtException = GetMethodIDOrDie(env, clazz,
+            "dispatchUncaughtException", "(Ljava/lang/Throwable;)V");
+    gThreadDispatchOffsets.mCurrentThread = GetStaticMethodIDOrDie(env, clazz, "currentThread",
+            "()Ljava/lang/Thread;");
+
     return 0;
 }