Merge changes I119cf83a,Icc5a1e38,If07a04d3
* changes: Binder: Update to new ScopedLocalRef Binder: Clean up JNI code Binder: Change reaction to Error
This commit is contained in:
@@ -20,8 +20,6 @@
|
||||
#include "android_os_Parcel.h"
|
||||
#include "android_util_Binder.h"
|
||||
|
||||
#include <nativehelper/JNIHelp.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
@@ -44,8 +42,9 @@
|
||||
#include <utils/SystemClock.h>
|
||||
#include <utils/threads.h>
|
||||
|
||||
#include <nativehelper/ScopedUtfChars.h>
|
||||
#include <nativehelper/JNIHelp.h>
|
||||
#include <nativehelper/ScopedLocalRef.h>
|
||||
#include <nativehelper/ScopedUtfChars.h>
|
||||
|
||||
#include "core_jni_helpers.h"
|
||||
|
||||
@@ -133,6 +132,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,69 +173,93 @@ 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 will terminate the runtime by
|
||||
// calling FatalError with a message derived from the given error.
|
||||
static void report_java_lang_error_fatal_error(JNIEnv* env, jthrowable error,
|
||||
const char* msg)
|
||||
{
|
||||
// Report an error: reraise the exception and ask the runtime to abort.
|
||||
|
||||
// Try to get the exception string. Sometimes logcat isn't available,
|
||||
// so try to add it to the abort message.
|
||||
std::string exc_msg = "(Unknown exception message)";
|
||||
{
|
||||
ScopedLocalRef<jclass> exc_class(env, env->GetObjectClass(error));
|
||||
jmethodID method_id = env->GetMethodID(exc_class.get(), "toString",
|
||||
"()Ljava/lang/String;");
|
||||
ScopedLocalRef<jstring> jstr(
|
||||
env,
|
||||
reinterpret_cast<jstring>(
|
||||
env->CallObjectMethod(error, method_id)));
|
||||
env->ExceptionClear(); // Just for good measure.
|
||||
if (jstr.get() != nullptr) {
|
||||
ScopedUtfChars jstr_utf(env, jstr.get());
|
||||
if (jstr_utf.c_str() != nullptr) {
|
||||
exc_msg = jstr_utf.c_str();
|
||||
} else {
|
||||
env->ExceptionClear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
env->Throw(error);
|
||||
ALOGE("java.lang.Error thrown during binder transaction (stack trace follows) : ");
|
||||
env->ExceptionDescribe();
|
||||
|
||||
std::string error_msg = base::StringPrintf(
|
||||
"java.lang.Error thrown during binder transaction: %s",
|
||||
exc_msg.c_str());
|
||||
env->FatalError(error_msg.c_str());
|
||||
}
|
||||
|
||||
// Report a java.lang.Error (or subclass). This will terminate the runtime, either by
|
||||
// the uncaught exception handler, or explicitly by calling
|
||||
// report_java_lang_error_fatal_error.
|
||||
static void report_java_lang_error(JNIEnv* env, jthrowable error, const char* msg)
|
||||
{
|
||||
// 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). As the binder code cannot handle Errors, attempt to log the error and
|
||||
// abort.
|
||||
env->ExceptionClear();
|
||||
report_java_lang_error_fatal_error(env, error, msg);
|
||||
}
|
||||
|
||||
static void report_exception(JNIEnv* env, jthrowable excep, const char* msg)
|
||||
{
|
||||
env->ExceptionClear();
|
||||
|
||||
jstring tagstr = env->NewStringUTF(LOG_TAG);
|
||||
jstring msgstr = NULL;
|
||||
if (tagstr != NULL) {
|
||||
msgstr = env->NewStringUTF(msg);
|
||||
ScopedLocalRef<jstring> tagstr(env, env->NewStringUTF(LOG_TAG));
|
||||
ScopedLocalRef<jstring> msgstr(env);
|
||||
if (tagstr != nullptr) {
|
||||
msgstr.reset(env->NewStringUTF(msg));
|
||||
}
|
||||
|
||||
if ((tagstr == NULL) || (msgstr == NULL)) {
|
||||
if ((tagstr != nullptr) && (msgstr != nullptr)) {
|
||||
env->CallStaticIntMethod(gLogOffsets.mClass, gLogOffsets.mLogE,
|
||||
tagstr.get(), msgstr.get(), excep);
|
||||
if (env->ExceptionCheck()) {
|
||||
// Attempting to log the failure has failed.
|
||||
ALOGW("Failed trying to log exception, msg='%s'\n", msg);
|
||||
env->ExceptionClear();
|
||||
}
|
||||
} else {
|
||||
env->ExceptionClear(); /* assume exception (OOM?) was thrown */
|
||||
ALOGE("Unable to call Log.e()\n");
|
||||
ALOGE("%s", msg);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
env->CallStaticIntMethod(
|
||||
gLogOffsets.mClass, gLogOffsets.mLogE, tagstr, msgstr, excep);
|
||||
if (env->ExceptionCheck()) {
|
||||
/* attempting to log the failure has failed */
|
||||
ALOGW("Failed trying to log exception, msg='%s'\n", msg);
|
||||
env->ExceptionClear();
|
||||
}
|
||||
|
||||
if (env->IsInstanceOf(excep, gErrorOffsets.mClass)) {
|
||||
/*
|
||||
* It's an Error: Reraise the exception and ask the runtime to abort.
|
||||
*/
|
||||
|
||||
// Try to get the exception string. Sometimes logcat isn't available,
|
||||
// so try to add it to the abort message.
|
||||
std::string exc_msg = "(Unknown exception message)";
|
||||
{
|
||||
ScopedLocalRef<jclass> exc_class(env, env->GetObjectClass(excep));
|
||||
jmethodID method_id = env->GetMethodID(exc_class.get(),
|
||||
"toString",
|
||||
"()Ljava/lang/String;");
|
||||
ScopedLocalRef<jstring> jstr(
|
||||
env,
|
||||
reinterpret_cast<jstring>(
|
||||
env->CallObjectMethod(excep, method_id)));
|
||||
env->ExceptionClear(); // Just for good measure.
|
||||
if (jstr.get() != nullptr) {
|
||||
ScopedUtfChars jstr_utf(env, jstr.get());
|
||||
exc_msg = jstr_utf.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
env->Throw(excep);
|
||||
ALOGE("java.lang.Error thrown during binder transaction (stack trace follows) : ");
|
||||
env->ExceptionDescribe();
|
||||
|
||||
std::string error_msg = base::StringPrintf(
|
||||
"java.lang.Error thrown during binder transaction: %s",
|
||||
exc_msg.c_str());
|
||||
env->FatalError(error_msg.c_str());
|
||||
report_java_lang_error(env, excep, msg);
|
||||
}
|
||||
|
||||
bail:
|
||||
/* discard local refs created for us by VM */
|
||||
env->DeleteLocalRef(tagstr);
|
||||
env->DeleteLocalRef(msgstr);
|
||||
}
|
||||
|
||||
class JavaBBinderHolder;
|
||||
@@ -280,14 +311,11 @@ protected:
|
||||
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
jthrowable excep = env->ExceptionOccurred();
|
||||
report_exception(env, excep,
|
||||
ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred());
|
||||
report_exception(env, excep.get(),
|
||||
"*** Uncaught remote exception! "
|
||||
"(Exceptions are not yet supported across processes.)");
|
||||
res = JNI_FALSE;
|
||||
|
||||
/* clean up JNI local ref -- we don't return to Java code */
|
||||
env->DeleteLocalRef(excep);
|
||||
}
|
||||
|
||||
// Check if the strict mode state changed while processing the
|
||||
@@ -299,11 +327,9 @@ protected:
|
||||
}
|
||||
|
||||
if (env->ExceptionCheck()) {
|
||||
jthrowable excep = env->ExceptionOccurred();
|
||||
report_exception(env, excep,
|
||||
ScopedLocalRef<jthrowable> excep(env, env->ExceptionOccurred());
|
||||
report_exception(env, excep.get(),
|
||||
"*** Uncaught exception in onBinderStrictModePolicyChange");
|
||||
/* clean up JNI local ref -- we don't return to Java code */
|
||||
env->DeleteLocalRef(excep);
|
||||
}
|
||||
|
||||
// Need to always call through the native implementation of
|
||||
@@ -446,9 +472,8 @@ public:
|
||||
if (mObject != NULL) {
|
||||
result = env->IsSameObject(obj, mObject);
|
||||
} else {
|
||||
jobject me = env->NewLocalRef(mObjectWeak);
|
||||
result = env->IsSameObject(obj, me);
|
||||
env->DeleteLocalRef(me);
|
||||
ScopedLocalRef<jobject> me(env, env->NewLocalRef(mObjectWeak));
|
||||
result = env->IsSameObject(obj, me.get());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1337,5 +1362,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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user