Add back the dalvik-style JNI logging and tracing.
Change-Id: I3f8f50c9f9f2cb36f1668150c5e19f6225d15bbb
diff --git a/src/check_jni.cc b/src/check_jni.cc
index 88f3fec..3037eea 100644
--- a/src/check_jni.cc
+++ b/src/check_jni.cc
@@ -28,17 +28,21 @@
namespace art {
void JniAbort(const char* jni_function_name) {
- std::stringstream os;
+ Thread* self = Thread::Current();
+ const Method* current_method = self->GetCurrentMethod();
- // dvmDumpThread(dvmThreadSelf(), false);
+ std::stringstream os;
os << "JNI app bug detected";
if (jni_function_name != NULL) {
os << "\n in call to " << jni_function_name;
}
- // TODO: say what native method we're in...
- //const Method* method = dvmGetCurrentJNIMethod();
- //os << "\n in " << PrettyMethod(method);
+ // TODO: is this useful given that we're about to dump the calling thread's stack?
+ if (current_method != NULL) {
+ os << "\n from " << PrettyMethod(current_method);
+ }
+ os << "\n";
+ self->Dump(os);
JavaVMExt* vm = Runtime::Current()->GetJavaVM();
if (vm->check_jni_abort_hook != NULL) {
@@ -267,17 +271,53 @@
#define kFlag_Invocation 0x8000 /* Part of the invocation interface (JavaVM*) */
+static const char* gBuiltInPrefixes[] = {
+ "Landroid/",
+ "Lcom/android/",
+ "Lcom/google/android/",
+ "Ldalvik/",
+ "Ljava/",
+ "Ljavax/",
+ "Llibcore/",
+ "Lorg/apache/harmony/",
+ NULL
+};
+
+bool ShouldTrace(JavaVMExt* vm, const Method* method) {
+ // If both "-Xcheck:jni" and "-Xjnitrace:" are enabled, we print trace messages
+ // when a native method that matches the -Xjnitrace argument calls a JNI function
+ // such as NewByteArray.
+ // If -verbose:third-party-jni is on, we want to log any JNI function calls
+ // made by a third-party native method.
+ std::string classNameStr(method->GetDeclaringClass()->GetDescriptor()->ToModifiedUtf8());
+ if (!vm->trace.empty() && classNameStr.find(vm->trace) != std::string::npos) {
+ return true;
+ }
+ if (vm->log_third_party_jni) {
+ // Return true if we're trying to log all third-party JNI activity and 'method' doesn't look
+ // like part of Android.
+ StringPiece className(classNameStr);
+ for (size_t i = 0; gBuiltInPrefixes[i] != NULL; ++i) {
+ if (className.starts_with(gBuiltInPrefixes[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
class ScopedCheck {
public:
// For JNIEnv* functions.
explicit ScopedCheck(JNIEnv* env, int flags, const char* functionName) {
- init(env, flags, functionName, true);
+ init(env, reinterpret_cast<JNIEnvExt*>(env)->vm, flags, functionName, true);
checkThread(flags);
}
// For JavaVM* functions.
- explicit ScopedCheck(bool hasMethod, const char* functionName) {
- init(NULL, kFlag_Invocation, functionName, hasMethod);
+ explicit ScopedCheck(JavaVM* vm, bool hasMethod, const char* functionName) {
+ init(NULL, vm, kFlag_Invocation, functionName, hasMethod);
}
bool forceCopy() {
@@ -501,31 +541,17 @@
void check(bool entry, const char* fmt0, ...) {
va_list ap;
- bool shouldTrace = false;
- const Method* method = NULL;
-#if 0
- if ((gDvm.jniTrace || gDvmJni.logThirdPartyJni) && mHasMethod) {
+ const Method* traceMethod = NULL;
+ if ((!mVm->trace.empty() || mVm->log_third_party_jni) && mHasMethod) {
// We need to guard some of the invocation interface's calls: a bad caller might
// use DetachCurrentThread or GetEnv on a thread that's not yet attached.
- if ((mFlags & kFlag_Invocation) == 0 || dvmThreadSelf() != NULL) {
- method = dvmGetCurrentJNIMethod();
+ Thread* self = Thread::Current();
+ if ((mFlags & kFlag_Invocation) == 0 || self != NULL) {
+ traceMethod = self->GetCurrentMethod();
}
}
- if (method != NULL) {
- // If both "-Xcheck:jni" and "-Xjnitrace:" are enabled, we print trace messages
- // when a native method that matches the Xjnitrace argument calls a JNI function
- // such as NewByteArray.
- if (gDvm.jniTrace && strstr(method->clazz->descriptor, gDvm.jniTrace) != NULL) {
- shouldTrace = true;
- }
- // If -Xjniopts:logThirdPartyJni is on, we want to log any JNI function calls
- // made by a third-party native method.
- if (gDvmJni.logThirdPartyJni) {
- shouldTrace |= method->shouldTrace;
- }
- }
-#endif
- if (shouldTrace) {
+
+ if (traceMethod != NULL && ShouldTrace(mVm, traceMethod)) {
va_start(ap, fmt0);
std::string msg;
for (const char* fmt = fmt0; *fmt;) {
@@ -644,7 +670,7 @@
if (entry) {
if (mHasMethod) {
- std::string methodName(PrettyMethod(method, false));
+ std::string methodName(PrettyMethod(traceMethod, false));
LOG(INFO) << "JNI: " << methodName << " -> " << mFunctionName << "(" << msg << ")";
mIndent = methodName.size() + 1;
} else {
@@ -704,8 +730,9 @@
return Decode<Method*>(ts, reinterpret_cast<jweak>(mid));
}
- void init(JNIEnv* env, int flags, const char* functionName, bool hasMethod) {
+ void init(JNIEnv* env, JavaVM* vm, int flags, const char* functionName, bool hasMethod) {
mEnv = reinterpret_cast<JNIEnvExt*>(env);
+ mVm = reinterpret_cast<JavaVMExt*>(vm);
mFlags = flags;
mFunctionName = functionName;
@@ -989,6 +1016,7 @@
}
JNIEnvExt* mEnv;
+ JavaVMExt* mVm;
const char* mFunctionName;
int mFlags;
bool mHasMethod;
@@ -2140,31 +2168,31 @@
class CheckJII {
public:
static jint DestroyJavaVM(JavaVM* vm) {
- ScopedCheck sc(false, __FUNCTION__);
+ ScopedCheck sc(vm, false, __FUNCTION__);
sc.check(true, "v", vm);
return CHECK_JNI_EXIT("I", baseVm(vm)->DestroyJavaVM(vm));
}
static jint AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
- ScopedCheck sc(false, __FUNCTION__);
+ ScopedCheck sc(vm, false, __FUNCTION__);
sc.check(true, "vpp", vm, p_env, thr_args);
return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThread(vm, p_env, thr_args));
}
static jint AttachCurrentThreadAsDaemon(JavaVM* vm, JNIEnv** p_env, void* thr_args) {
- ScopedCheck sc(false, __FUNCTION__);
+ ScopedCheck sc(vm, false, __FUNCTION__);
sc.check(true, "vpp", vm, p_env, thr_args);
return CHECK_JNI_EXIT("I", baseVm(vm)->AttachCurrentThreadAsDaemon(vm, p_env, thr_args));
}
static jint DetachCurrentThread(JavaVM* vm) {
- ScopedCheck sc(true, __FUNCTION__);
+ ScopedCheck sc(vm, true, __FUNCTION__);
sc.check(true, "v", vm);
return CHECK_JNI_EXIT("I", baseVm(vm)->DetachCurrentThread(vm));
}
static jint GetEnv(JavaVM* vm, void** env, jint version) {
- ScopedCheck sc(true, __FUNCTION__);
+ ScopedCheck sc(vm, true, __FUNCTION__);
sc.check(true, "v", vm);
return CHECK_JNI_EXIT("I", baseVm(vm)->GetEnv(vm, env, version));
}