Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ac5e350e authored by Christopher Tate's avatar Christopher Tate
Browse files

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
parent 829559d2
Loading
Loading
Loading
Loading
+31 −1
Original line number Diff line number Diff line
@@ -39,6 +39,9 @@
#include <binder/IServiceManager.h>
#include <utils/threads.h>

#include <ScopedUtfChars.h>
#include <ScopedLocalRef.h>

#include <android_runtime/AndroidRuntime.h>

//#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<jclass> classRef(env, env->GetObjectClass(mObject));
            jmethodID getnameMethod = env->GetMethodID(classRef.get(),
                    "getName", "()Ljava/lang/String;");
            if (getnameMethod) {
                ScopedLocalRef<jstring> 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<JavaDeathRecipient> >::iterator iter;
        for (iter = mList.begin(); iter != mList.end(); iter++) {
            (*iter)->warnIfStillLive();
        }
    }
}