summaryrefslogtreecommitdiffstats
path: root/core/jni/android_util_Binder.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/jni/android_util_Binder.cpp')
-rw-r--r--core/jni/android_util_Binder.cpp52
1 files changed, 37 insertions, 15 deletions
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index b432d65..b8f2d6f 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -385,7 +385,8 @@ class JavaDeathRecipient : public IBinder::DeathRecipient
{
public:
JavaDeathRecipient(JNIEnv* env, jobject object, const sp<DeathRecipientList>& list)
- : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)), mList(list)
+ : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)),
+ mObjectWeak(NULL), mList(list)
{
// These objects manage their own lifetimes so are responsible for final bookkeeping.
// The list holds a strong reference to this object.
@@ -398,16 +399,23 @@ public:
void binderDied(const wp<IBinder>& who)
{
- JNIEnv* env = javavm_to_jnienv(mVM);
-
LOGDEATH("Receiving binderDied() on JavaDeathRecipient %p\n", this);
+ if (mObject != NULL) {
+ JNIEnv* env = javavm_to_jnienv(mVM);
+
+ env->CallStaticVoidMethod(gBinderProxyOffsets.mClass,
+ gBinderProxyOffsets.mSendDeathNotice, mObject);
+ jthrowable excep = env->ExceptionOccurred();
+ if (excep) {
+ report_exception(env, excep,
+ "*** Uncaught exception returned from death notification!");
+ }
- env->CallStaticVoidMethod(gBinderProxyOffsets.mClass,
- gBinderProxyOffsets.mSendDeathNotice, mObject);
- jthrowable excep = env->ExceptionOccurred();
- if (excep) {
- report_exception(env, excep,
- "*** Uncaught exception returned from death notification!");
+ // Demote from strong ref to weak after binderDied() has been delivered,
+ // to allow the DeathRecipient and BinderProxy to be GC'd if no longer needed.
+ mObjectWeak = env->NewWeakGlobalRef(mObject);
+ env->DeleteGlobalRef(mObject);
+ mObject = NULL;
}
}
@@ -423,8 +431,17 @@ public:
}
bool matches(jobject obj) {
+ bool result;
JNIEnv* env = javavm_to_jnienv(mVM);
- return env->IsSameObject(obj, mObject);
+
+ if (mObject != NULL) {
+ result = env->IsSameObject(obj, mObject);
+ } else {
+ jobject me = env->NewLocalRef(mObjectWeak);
+ result = env->IsSameObject(obj, me);
+ env->DeleteLocalRef(me);
+ }
+ return result;
}
protected:
@@ -433,12 +450,17 @@ protected:
//LOGI("Removing death ref: recipient=%p\n", mObject);
android_atomic_dec(&gNumDeathRefs);
JNIEnv* env = javavm_to_jnienv(mVM);
- env->DeleteGlobalRef(mObject);
+ if (mObject != NULL) {
+ env->DeleteGlobalRef(mObject);
+ } else {
+ env->DeleteWeakGlobalRef(mObjectWeak);
+ }
}
private:
- JavaVM* const mVM;
- jobject const mObject;
+ JavaVM* const mVM;
+ jobject mObject;
+ jweak mObjectWeak; // will be a weak ref to the same VM-side DeathRecipient after binderDied()
wp<DeathRecipientList> mList;
};
@@ -512,7 +534,7 @@ jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
if (val->checkSubclass(&gBinderOffsets)) {
// One of our own!
jobject object = static_cast<JavaBBinder*>(val.get())->object();
- //printf("objectForBinder %p: it's our own %p!\n", val.get(), object);
+ LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
return object;
}
@@ -528,7 +550,7 @@ jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
LOGV("objectForBinder %p: found existing %p!\n", val.get(), res);
return res;
}
- LOGV("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());
+ LOGDEATH("Proxy object %p of IBinder %p no longer in working set!!!", object, val.get());
android_atomic_dec(&gNumProxyRefs);
val->detachObject(&gBinderProxyOffsets);
env->DeleteGlobalRef(object);