From ac5e350e567c7a257ced37dd4e8ca0f4c95f7e81 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Thu, 25 Aug 2011 15:48:09 -0700 Subject: [PATCH] Warn if we're tearing down "live" DeathRecipient content [take 2] If the native-side bookkeeping still has strong references to VM-side DeathRecipient objects at the time when it's being torn down, that suggests that the app is doing unwholesome. Log a warning to that effect, with the class name of the objects to try to help the developer figure out what they're mishandling. Fixes bug 5202777 -- in particular, it no longer logs in the working-as-intended case following delivery of the death notices, when we've got the existing list shell but the weak refs have properly cleared. Also step down from "error" to "warning" logging as befits the nature of the actual situation now being described. This new patch fixes the JNI bug present in the earlier version. Change-Id: I095862777a8d0e3905cb7f416af658878280041d --- core/jni/android_util_Binder.cpp | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index b8f2d6f2e0681..4cf4afabec14f 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -39,6 +39,9 @@ #include #include +#include +#include + #include //#undef LOGV @@ -444,6 +447,30 @@ public: return result; } + void warnIfStillLive() { + if (mObject != NULL) { + // Okay, something is wrong -- we have a hard reference to a live death + // recipient on the VM side, but the list is being torn down. + JNIEnv* env = javavm_to_jnienv(mVM); + ScopedLocalRef classRef(env, env->GetObjectClass(mObject)); + jmethodID getnameMethod = env->GetMethodID(classRef.get(), + "getName", "()Ljava/lang/String;"); + if (getnameMethod) { + ScopedLocalRef nameRef(env, + (jstring) env->CallObjectMethod(classRef.get(), getnameMethod)); + ScopedUtfChars nameUtf(env, nameRef.get()); + if (nameUtf.c_str() != NULL) { + LOGW("BinderProxy is being destroyed but the application did not call " + "unlinkToDeath to unlink all of its death recipients beforehand. " + "Releasing leaked death recipient: %s", nameUtf.c_str()); + } else { + LOGW("BinderProxy being destroyed; unable to get DR object name"); + env->ExceptionClear(); + } + } else LOGW("BinderProxy being destroyed; unable to find DR class getName"); + } + } + protected: virtual ~JavaDeathRecipient() { @@ -478,7 +505,10 @@ DeathRecipientList::~DeathRecipientList() { // to the list are holding references on the list object. Only when they are torn // down can the list header be destroyed. if (mList.size() > 0) { - LOGE("Retiring DRL %p with extant death recipients\n", this); + List< sp >::iterator iter; + for (iter = mList.begin(); iter != mList.end(); iter++) { + (*iter)->warnIfStillLive(); + } } }