summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Tate <ctate@google.com>2011-02-28 12:50:09 -0800
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-02-28 12:50:09 -0800
commitd5dac80fed2a85944060e8b1192eff9dee77ac4d (patch)
tree98936c1d2f117bac7988a0e88442b13c77c0ae84
parent8c8cfec0eade40b94f8151eb2e8e438837f896a5 (diff)
parent0b41448506610f73302cc631677823fd8b865ea5 (diff)
downloadframeworks_base-d5dac80fed2a85944060e8b1192eff9dee77ac4d.zip
frameworks_base-d5dac80fed2a85944060e8b1192eff9dee77ac4d.tar.gz
frameworks_base-d5dac80fed2a85944060e8b1192eff9dee77ac4d.tar.bz2
Merge "Binder linkage no longer depends on JNI objrefs as persistent tokens"
-rw-r--r--core/jni/android_util_Binder.cpp200
-rw-r--r--include/binder/IBinder.h2
2 files changed, 150 insertions, 52 deletions
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 7a53874..ef3c31a 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -31,6 +31,8 @@
#include <binder/IPCThreadState.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>
+#include <utils/List.h>
+#include <utils/KeyedVector.h>
#include <cutils/logger.h>
#include <binder/Parcel.h>
#include <binder/ProcessState.h>
@@ -322,25 +324,15 @@ private:
class JavaBBinderHolder : public RefBase
{
public:
- JavaBBinderHolder(JNIEnv* env, jobject object)
- : mObject(object)
- {
- LOGV("Creating JavaBBinderHolder for Object %p\n", object);
- }
- ~JavaBBinderHolder()
- {
- LOGV("Destroying JavaBBinderHolder for Object %p\n", mObject);
- }
-
- sp<JavaBBinder> get(JNIEnv* env)
+ sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
- b = new JavaBBinder(env, mObject);
+ b = new JavaBBinder(env, obj);
mBinder = b;
LOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%d\n",
- b.get(), b->getWeakRefs(), mObject, b->getWeakRefs()->getWeakCount());
+ b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
}
return b;
@@ -354,20 +346,41 @@ public:
private:
Mutex mLock;
- jobject mObject;
wp<JavaBBinder> mBinder;
};
// ----------------------------------------------------------------------------
+// Per-IBinder death recipient bookkeeping. This is how we reconcile local jobject
+// death recipient references passed in through JNI with the permanent corresponding
+// JavaDeathRecipient objects.
+
+class JavaDeathRecipient;
+
+class DeathRecipientList : public RefBase {
+ List< sp<JavaDeathRecipient> > mList;
+ Mutex mLock;
+
+public:
+ ~DeathRecipientList();
+
+ void add(const sp<JavaDeathRecipient>& recipient);
+ void remove(const sp<JavaDeathRecipient>& recipient);
+ sp<JavaDeathRecipient> find(jobject recipient);
+};
+
+// ----------------------------------------------------------------------------
+
class JavaDeathRecipient : public IBinder::DeathRecipient
{
public:
- JavaDeathRecipient(JNIEnv* env, jobject object)
- : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)),
- mHoldsRef(true)
+ JavaDeathRecipient(JNIEnv* env, jobject object, sp<DeathRecipientList>& list)
+ : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object)), mList(list)
{
- incStrong(this);
+ // These objects manage their own lifetimes so are responsible for final bookkeeping.
+ // The list holds a strong reference to this object.
+ mList->add(this);
+
android_atomic_inc(&gNumDeathRefs);
incRefsCreated(env);
}
@@ -391,16 +404,12 @@ public:
void clearReference()
{
- bool release = false;
- mLock.lock();
- if (mHoldsRef) {
- mHoldsRef = false;
- release = true;
- }
- mLock.unlock();
- if (release) {
- decStrong(this);
- }
+ mList->remove(this);
+ }
+
+ bool matches(jobject obj) {
+ JNIEnv* env = javavm_to_jnienv(mVM);
+ return env->IsSameObject(obj, mObject);
}
protected:
@@ -415,12 +424,57 @@ protected:
private:
JavaVM* const mVM;
jobject const mObject;
- Mutex mLock;
- bool mHoldsRef;
+ sp<DeathRecipientList> mList;
};
// ----------------------------------------------------------------------------
+DeathRecipientList::~DeathRecipientList() {
+ AutoMutex _l(mLock);
+
+ // Should never happen -- the JavaDeathRecipient objects that have added themselves
+ // 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 binder %p with extant death recipients\n", this);
+ }
+}
+
+void DeathRecipientList::add(const sp<JavaDeathRecipient>& recipient) {
+ AutoMutex _l(mLock);
+
+ mList.push_back(recipient);
+}
+
+void DeathRecipientList::remove(const sp<JavaDeathRecipient>& recipient) {
+ AutoMutex _l(mLock);
+
+ List< sp<JavaDeathRecipient> >::iterator iter;
+ for (iter = mList.begin(); iter != mList.end(); iter++) {
+ if (*iter == recipient) {
+ mList.erase(iter);
+ return;
+ }
+ }
+}
+
+sp<JavaDeathRecipient> DeathRecipientList::find(jobject recipient) {
+ AutoMutex _l(mLock);
+
+ List< sp<JavaDeathRecipient> >::iterator iter;
+ for (iter = mList.begin(); iter != mList.end(); iter++) {
+ if ((*iter)->matches(recipient)) {
+ return *iter;
+ }
+ }
+ return NULL;
+}
+
+static KeyedVector<IBinder*, sp<DeathRecipientList> > gDeathRecipientsByIBinder;
+static Mutex gDeathRecipientMapLock;
+
+// ----------------------------------------------------------------------------
+
namespace android {
static void proxy_cleanup(const void* id, void* obj, void* cleanupCookie)
@@ -490,7 +544,7 @@ sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetIntField(obj, gBinderOffsets.mObject);
- return jbh != NULL ? jbh->get(env) : NULL;
+ return jbh != NULL ? jbh->get(env, obj) : NULL;
}
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
@@ -621,26 +675,26 @@ static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz)
IPCThreadState::self()->flushCommands();
}
-static void android_os_Binder_init(JNIEnv* env, jobject clazz)
+static void android_os_Binder_init(JNIEnv* env, jobject obj)
{
- JavaBBinderHolder* jbh = new JavaBBinderHolder(env, clazz);
+ JavaBBinderHolder* jbh = new JavaBBinderHolder();
if (jbh == NULL) {
jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
return;
}
- LOGV("Java Binder %p: acquiring first ref on holder %p", clazz, jbh);
- jbh->incStrong(clazz);
- env->SetIntField(clazz, gBinderOffsets.mObject, (int)jbh);
+ LOGV("Java Binder %p: acquiring first ref on holder %p", obj, jbh);
+ jbh->incStrong((void*)android_os_Binder_init);
+ env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
}
-static void android_os_Binder_destroy(JNIEnv* env, jobject clazz)
+static void android_os_Binder_destroy(JNIEnv* env, jobject obj)
{
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
- env->GetIntField(clazz, gBinderOffsets.mObject);
+ env->GetIntField(obj, gBinderOffsets.mObject);
if (jbh != NULL) {
- env->SetIntField(clazz, gBinderOffsets.mObject, 0);
- LOGV("Java Binder %p: removing ref on holder %p", clazz, jbh);
- jbh->decStrong(clazz);
+ env->SetIntField(obj, gBinderOffsets.mObject, 0);
+ LOGV("Java Binder %p: removing ref on holder %p", obj, jbh);
+ jbh->decStrong((void*)android_os_Binder_init);
} else {
// Encountering an uninitialized binder is harmless. All it means is that
// the Binder was only partially initialized when its finalizer ran and called
@@ -648,7 +702,7 @@ static void android_os_Binder_destroy(JNIEnv* env, jobject clazz)
// For example, a Binder subclass constructor might have thrown an exception before
// it could delegate to its superclass's constructor. Consequently init() would
// not have been called and the holder pointer would remain NULL.
- LOGV("Java Binder %p: ignoring uninitialized binder", clazz);
+ LOGV("Java Binder %p: ignoring uninitialized binder", obj);
}
}
@@ -973,8 +1027,25 @@ static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj,
LOGV("linkToDeath: binder=%p recipient=%p\n", target, recipient);
if (!target->localBinder()) {
- sp<JavaDeathRecipient> jdr = new JavaDeathRecipient(env, recipient);
- status_t err = target->linkToDeath(jdr, recipient, flags);
+ sp<JavaDeathRecipient> jdr;
+
+ {
+ sp<DeathRecipientList> list;
+ AutoMutex _maplocker(gDeathRecipientMapLock);
+
+ ssize_t listIndex = gDeathRecipientsByIBinder.indexOfKey(target);
+ if (listIndex < 0) {
+ // Set up the death notice bookkeeping for this binder lazily
+ list = new DeathRecipientList;
+ gDeathRecipientsByIBinder.add(target, list);
+ } else {
+ list = gDeathRecipientsByIBinder.valueAt(listIndex);
+ }
+
+ jdr = new JavaDeathRecipient(env, recipient, list);
+ }
+
+ status_t err = target->linkToDeath(jdr, NULL, flags);
if (err != NO_ERROR) {
// Failure adding the death recipient, so clear its reference
// now.
@@ -1003,15 +1074,33 @@ static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj,
LOGV("unlinkToDeath: binder=%p recipient=%p\n", target, recipient);
if (!target->localBinder()) {
- wp<IBinder::DeathRecipient> dr;
- status_t err = target->unlinkToDeath(NULL, recipient, flags, &dr);
- if (err == NO_ERROR && dr != NULL) {
- sp<IBinder::DeathRecipient> sdr = dr.promote();
- JavaDeathRecipient* jdr = static_cast<JavaDeathRecipient*>(sdr.get());
- if (jdr != NULL) {
- jdr->clearReference();
+ status_t err = NAME_NOT_FOUND;
+ sp<JavaDeathRecipient> origJDR;
+ {
+ AutoMutex _maplocker(gDeathRecipientMapLock);
+ ssize_t listIndex = gDeathRecipientsByIBinder.indexOfKey(target);
+ if (listIndex >= 0) {
+ sp<DeathRecipientList> list = gDeathRecipientsByIBinder.valueAt(listIndex);
+ origJDR = list->find(recipient);
+ } else {
+ // If there is no DeathRecipientList for this binder, it means the binder
+ // is dead and in the process of being cleaned up.
+ err = DEAD_OBJECT;
+ }
+ }
+ // If we found the matching recipient, proceed to unlink using that
+ if (origJDR != NULL) {
+ wp<IBinder::DeathRecipient> dr;
+ err = target->unlinkToDeath(origJDR, NULL, flags, &dr);
+ if (err == NO_ERROR && dr != NULL) {
+ sp<IBinder::DeathRecipient> sdr = dr.promote();
+ JavaDeathRecipient* jdr = static_cast<JavaDeathRecipient*>(sdr.get());
+ if (jdr != NULL) {
+ jdr->clearReference();
+ }
}
}
+
if (err == NO_ERROR || err == DEAD_OBJECT) {
res = JNI_TRUE;
} else {
@@ -1031,6 +1120,15 @@ static void android_os_BinderProxy_destroy(JNIEnv* env, jobject obj)
env->SetIntField(obj, gBinderProxyOffsets.mObject, 0);
b->decStrong(obj);
IPCThreadState::self()->flushCommands();
+
+ // tear down the death recipient bookkeeping
+ {
+ AutoMutex _maplocker(gDeathRecipientMapLock);
+ ssize_t listIndex = gDeathRecipientsByIBinder.indexOfKey(b);
+ if (listIndex >= 0) {
+ gDeathRecipientsByIBinder.removeItemsAt((size_t)listIndex);
+ }
+ }
}
// ----------------------------------------------------------------------------
diff --git a/include/binder/IBinder.h b/include/binder/IBinder.h
index 749a977..81b56c2 100644
--- a/include/binder/IBinder.h
+++ b/include/binder/IBinder.h
@@ -98,7 +98,7 @@ public:
* Register the @a recipient for a notification if this binder
* goes away. If this binder object unexpectedly goes away
* (typically because its hosting process has been killed),
- * then DeathRecipient::binderDied() will be called with a referene
+ * then DeathRecipient::binderDied() will be called with a reference
* to this.
*
* The @a cookie is optional -- if non-NULL, it should be a