Loading core/java/android/os/Binder.java +48 −33 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import com.android.internal.util.FunctionalUtils.ThrowingRunnable; import com.android.internal.util.FunctionalUtils.ThrowingSupplier; import libcore.io.IoUtils; import libcore.util.NativeAllocationRegistry; import java.io.FileDescriptor; import java.io.FileOutputStream; Loading Loading @@ -90,6 +91,20 @@ public class Binder implements IBinder { */ private static volatile TransactionTracker sTransactionTracker = null; /** * Guestimate of native memory associated with a Binder. */ private static final int NATIVE_ALLOCATION_SIZE = 500; private static native long getNativeFinalizer(); // Use a Holder to allow static initialization of Binder in the boot image, and // possibly to avoid some initialization ordering issues. private static class NoImagePreloadHolder { public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( Binder.class.getClassLoader(), getNativeFinalizer(), NATIVE_ALLOCATION_SIZE); } // Transaction tracking code. /** Loading Loading @@ -188,8 +203,11 @@ public class Binder implements IBinder { } } /* mObject is used by native code, do not remove or rename */ private long mObject; /** * Raw native pointer to JavaBBinderHolder object. Owned by this Java object. Not null. */ private final long mObject; private IInterface mOwner; private String mDescriptor; Loading Loading @@ -360,7 +378,8 @@ public class Binder implements IBinder { * Default constructor initializes the object. */ public Binder() { init(); mObject = getNativeBBinderHolder(); NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mObject); if (FIND_POTENTIAL_LEAKS) { final Class<? extends Binder> klass = getClass(); Loading Loading @@ -643,14 +662,6 @@ public class Binder implements IBinder { return true; } protected void finalize() throws Throwable { try { destroyBinder(); } finally { super.finalize(); } } static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) { if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) { // Trying to send > 800k, this is way too much Loading @@ -674,8 +685,8 @@ public class Binder implements IBinder { } } private native final void init(); private native final void destroyBinder(); private static native long getNativeBBinderHolder(); private static native long getFinalizer(); // Entry point from android_util_Binder.cpp's onTransact private boolean execTransact(int code, long dataObj, long replyObj, Loading Loading @@ -736,11 +747,25 @@ public class Binder implements IBinder { */ final class BinderProxy implements IBinder { // See android_util_Binder.cpp for the native half of this. // TODO: Consider using NativeAllocationRegistry instead of finalization. // Assume the process-wide default value when created volatile boolean mWarnOnBlocking = Binder.sWarnOnBlocking; /** * Guestimate of native memory associated with a BinderProxy. * This includes the underlying IBinder, associated DeathRecipientList, and KeyedVector * that points back to us. We guess high since it includes a GlobalRef, which * may be in short supply. */ private static final int NATIVE_ALLOCATION_SIZE = 1000; // Use a Holder to allow static initialization of BinderProxy in the boot image, and // to avoid some initialization ordering issues. private static class NoImagePreloadHolder { public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( BinderProxy.class.getClassLoader(), getNativeFinalizer(), NATIVE_ALLOCATION_SIZE); } public native boolean pingBinder(); public native boolean isBinderAlive(); Loading Loading @@ -776,6 +801,7 @@ final class BinderProxy implements IBinder { } } private static native long getNativeFinalizer(); public native String getInterfaceDescriptor() throws RemoteException; public native boolean transactNative(int code, Parcel data, Parcel reply, int flags) throws RemoteException; Loading Loading @@ -830,21 +856,12 @@ final class BinderProxy implements IBinder { } } BinderProxy() { BinderProxy(long nativeData) { mNativeData = nativeData; NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeData); mSelf = new WeakReference(this); } @Override protected void finalize() throws Throwable { try { destroy(); } finally { super.finalize(); } } private native final void destroy(); private static final void sendDeathNotice(DeathRecipient recipient) { if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient); try { Loading @@ -864,11 +881,9 @@ final class BinderProxy implements IBinder { // TODO: Consider making the extra native-to-java call to compute this on the fly. final private WeakReference mSelf; // Native pointer to the wrapped native IBinder object. Counted as strong reference. private long mObject; // Native pointer to native DeathRecipientList. Counted as strong reference. // Basically owned by the JavaProxy object. Reference counted only because DeathRecipients // hold a weak reference that can be temporarily promoted. private long mOrgue; /** * C++ pointer to BinderProxyNativeData. That consists of strong pointers to the * native IBinder object, and a DeathRecipientList. */ private final long mNativeData; } core/jni/android_util_Binder.cpp +65 −76 Original line number Diff line number Diff line Loading @@ -100,9 +100,8 @@ static struct binderproxy_offsets_t jmethodID mSendDeathNotice; // Object state. jfieldID mObject; jfieldID mSelf; jfieldID mOrgue; jfieldID mNativeData; // Field holds native pointer to BinderProxyNativeData. jfieldID mSelf; // Field holds Java pointer to WeakReference to BinderProxy. } gBinderProxyOffsets; Loading Loading @@ -356,7 +355,7 @@ private: // ---------------------------------------------------------------------------- class JavaBBinderHolder : public RefBase class JavaBBinderHolder { public: sp<JavaBBinder> get(JNIEnv* env, jobject obj) Loading Loading @@ -514,7 +513,7 @@ protected: private: JavaVM* const mVM; jobject mObject; // Initial strong ref to Java-side DeathRecipient. Cleared on binderDied(). jweak mObjectWeak; // weak ref to the same Java-side DeathRecipient after binderDied(). jweak mObjectWeak; // Weak ref to the same Java-side DeathRecipient after binderDied(). wp<DeathRecipientList> mList; }; Loading Loading @@ -586,6 +585,25 @@ static void proxy_cleanup(const void* id, void* obj, void* cleanupCookie) env->DeleteGlobalRef((jobject)obj); } // We aggregate native pointer fields for BinderProxy in a single object to allow // management with a single NativeAllocationRegistry, and to reduce the number of JNI // Java field accesses. This costs us some extra indirections here. struct BinderProxyNativeData { // The native IBinder proxied by this BinderProxy. const sp<IBinder> mObject; // Death recipients for mObject. Reference counted only because DeathRecipients // hold a weak reference that can be temporarily promoted. const sp<DeathRecipientList> mOrgue; // Death recipients for mObject. BinderProxyNativeData(const sp<IBinder> &obj, DeathRecipientList *drl) : mObject(obj), mOrgue(drl) {}; }; BinderProxyNativeData* getBPNativeData(JNIEnv* env, jobject obj) { return (BinderProxyNativeData *) env->GetLongField(obj, gBinderProxyOffsets.mNativeData); } static Mutex gProxyLock; jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) Loading Loading @@ -617,25 +635,22 @@ jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) env->DeleteGlobalRef(object); } object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor); DeathRecipientList* drl = new DeathRecipientList; BinderProxyNativeData* nativeData = new BinderProxyNativeData(val, drl); object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor, (jlong)nativeData); if (object != NULL) { LOGDEATH("objectForBinder %p: created new proxy %p !\n", val.get(), object); // The proxy holds a reference to the native object. env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get()); val->incStrong((void*)javaObjectForIBinder); // The native object needs to hold a weak reference back to the // proxy, so we can retrieve the same proxy if it is still active. // A JNI WeakGlobalRef would not currently work here, since it may be cleared // after the Java object has been condemned, and can thus yield a stale reference. jobject refObject = env->NewGlobalRef( env->GetObjectField(object, gBinderProxyOffsets.mSelf)); val->attachObject(&gBinderProxyOffsets, refObject, jnienv_to_javavm(env), proxy_cleanup); // Also remember the death recipients registered on this proxy sp<DeathRecipientList> drl = new DeathRecipientList; drl->incStrong((void*)javaObjectForIBinder); env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get())); // Note that a new object reference has been created. android_atomic_inc(&gNumProxyRefs); incRefsCreated(env); Loading @@ -651,12 +666,11 @@ sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj) if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) { JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetLongField(obj, gBinderOffsets.mObject); return jbh != NULL ? jbh->get(env, obj) : NULL; return jbh->get(env, obj); } if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) { return (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); return getBPNativeData(env, obj)->mObject; } ALOGW("ibinderForJavaObject: %p is not a Binder object", obj); Loading Loading @@ -849,35 +863,21 @@ static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz) IPCThreadState::self()->flushCommands(); } static void android_os_Binder_init(JNIEnv* env, jobject obj) static jlong android_os_Binder_getNativeBBinderHolder(JNIEnv* env, jobject clazz) { JavaBBinderHolder* jbh = new JavaBBinderHolder(); if (jbh == NULL) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); return; } ALOGV("Java Binder %p: acquiring first ref on holder %p", obj, jbh); jbh->incStrong((void*)android_os_Binder_init); env->SetLongField(obj, gBinderOffsets.mObject, (jlong)jbh); return (jlong) jbh; } static void android_os_Binder_destroyBinder(JNIEnv* env, jobject obj) static void Binder_destroy(void* rawJbh) { JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetLongField(obj, gBinderOffsets.mObject); if (jbh != NULL) { env->SetLongField(obj, gBinderOffsets.mObject, 0); ALOGV("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 // destroyBinder(). The Binder could be partially initialized for several reasons. // 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. ALOGV("Java Binder %p: ignoring uninitialized binder", obj); JavaBBinderHolder* jbh = (JavaBBinderHolder*) rawJbh; ALOGV("Java Binder: deleting holder %p", jbh); delete jbh; } JNIEXPORT jlong JNICALL android_os_Binder_getNativeFinalizer(JNIEnv*, jclass) { return (jlong) Binder_destroy; } static void android_os_Binder_blockUntilThreadAvailable(JNIEnv* env, jobject clazz) Loading @@ -896,8 +896,8 @@ static const JNINativeMethod gBinderMethods[] = { { "setThreadStrictModePolicy", "(I)V", (void*)android_os_Binder_setThreadStrictModePolicy }, { "getThreadStrictModePolicy", "()I", (void*)android_os_Binder_getThreadStrictModePolicy }, { "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands }, { "init", "()V", (void*)android_os_Binder_init }, { "destroyBinder", "()V", (void*)android_os_Binder_destroyBinder }, { "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder }, { "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer }, { "blockUntilThreadAvailable", "()V", (void*)android_os_Binder_blockUntilThreadAvailable } }; Loading Loading @@ -1004,8 +1004,7 @@ static int int_register_android_os_BinderInternal(JNIEnv* env) static jboolean android_os_BinderProxy_pingBinder(JNIEnv* env, jobject obj) { IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); IBinder* target = getBPNativeData(env, obj)->mObject.get(); if (target == NULL) { return JNI_FALSE; } Loading @@ -1015,7 +1014,7 @@ static jboolean android_os_BinderProxy_pingBinder(JNIEnv* env, jobject obj) static jstring android_os_BinderProxy_getInterfaceDescriptor(JNIEnv* env, jobject obj) { IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); IBinder* target = getBPNativeData(env, obj)->mObject.get(); if (target != NULL) { const String16& desc = target->getInterfaceDescriptor(); return env->NewString(reinterpret_cast<const jchar*>(desc.string()), Loading @@ -1028,8 +1027,7 @@ static jstring android_os_BinderProxy_getInterfaceDescriptor(JNIEnv* env, jobjec static jboolean android_os_BinderProxy_isBinderAlive(JNIEnv* env, jobject obj) { IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); IBinder* target = getBPNativeData(env, obj)->mObject.get(); if (target == NULL) { return JNI_FALSE; } Loading Loading @@ -1151,8 +1149,7 @@ static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj, return JNI_FALSE; } IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); IBinder* target = getBPNativeData(env, obj)->mObject.get(); if (target == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!"); return JNI_FALSE; Loading Loading @@ -1202,8 +1199,8 @@ static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj, return; } IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); BinderProxyNativeData *nd = getBPNativeData(env, obj); IBinder* target = nd->mObject.get(); if (target == NULL) { ALOGW("Binder has been finalized when calling linkToDeath() with recip=%p)\n", recipient); assert(false); Loading @@ -1212,8 +1209,7 @@ static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj, LOGDEATH("linkToDeath: binder=%p recipient=%p\n", target, recipient); if (!target->localBinder()) { DeathRecipientList* list = (DeathRecipientList*) env->GetLongField(obj, gBinderProxyOffsets.mOrgue); DeathRecipientList* list = nd->mOrgue.get(); sp<JavaDeathRecipient> jdr = new JavaDeathRecipient(env, recipient, list); status_t err = target->linkToDeath(jdr, NULL, flags); if (err != NO_ERROR) { Loading @@ -1234,8 +1230,8 @@ static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj, return res; } IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); BinderProxyNativeData* nd = getBPNativeData(env, obj); IBinder* target = nd->mObject.get(); if (target == NULL) { ALOGW("Binder has been finalized when calling linkToDeath() with recip=%p)\n", recipient); return JNI_FALSE; Loading @@ -1247,8 +1243,7 @@ static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj, status_t err = NAME_NOT_FOUND; // If we find the matching recipient, proceed to unlink using that DeathRecipientList* list = (DeathRecipientList*) env->GetLongField(obj, gBinderProxyOffsets.mOrgue); DeathRecipientList* list = nd->mOrgue.get(); sp<JavaDeathRecipient> origJDR = list->find(recipient); LOGDEATH(" unlink found list %p and JDR %p", list, origJDR.get()); if (origJDR != NULL) { Loading @@ -1274,25 +1269,20 @@ static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj, return res; } static void android_os_BinderProxy_destroy(JNIEnv* env, jobject obj) static void BinderProxy_destroy(void* rawNativeData) { // Don't race with construction/initialization AutoMutex _l(gProxyLock); IBinder* b = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); DeathRecipientList* drl = (DeathRecipientList*) env->GetLongField(obj, gBinderProxyOffsets.mOrgue); LOGDEATH("Destroying BinderProxy %p: binder=%p drl=%p\n", obj, b, drl); if (b != nullptr) { env->SetLongField(obj, gBinderProxyOffsets.mObject, 0); env->SetLongField(obj, gBinderProxyOffsets.mOrgue, 0); drl->decStrong((void*)javaObjectForIBinder); b->decStrong((void*)javaObjectForIBinder); BinderProxyNativeData * nativeData = (BinderProxyNativeData *) rawNativeData; LOGDEATH("Destroying BinderProxy: binder=%p drl=%p\n", nativeData->mObject.get(), nativeData->mOrgue.get()); delete (BinderProxyNativeData *) rawNativeData; IPCThreadState::self()->flushCommands(); } IPCThreadState::self()->flushCommands(); JNIEXPORT jlong JNICALL android_os_BinderProxy_getNativeFinalizer(JNIEnv*, jclass) { return (jlong) BinderProxy_destroy; } // ---------------------------------------------------------------------------- Loading @@ -1305,7 +1295,7 @@ static const JNINativeMethod gBinderProxyMethods[] = { {"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact}, {"linkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath}, {"unlinkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath}, {"destroy", "()V", (void*)android_os_BinderProxy_destroy}, {"getNativeFinalizer", "()J", (void*)android_os_BinderProxy_getNativeFinalizer}, }; const char* const kBinderProxyPathName = "android/os/BinderProxy"; Loading @@ -1317,14 +1307,13 @@ static int int_register_android_os_BinderProxy(JNIEnv* env) clazz = FindClassOrDie(env, kBinderProxyPathName); gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz); gBinderProxyOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>", "()V"); gBinderProxyOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>", "(J)V"); gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice", "(Landroid/os/IBinder$DeathRecipient;)V"); gBinderProxyOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J"); gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J"); gBinderProxyOffsets.mSelf = GetFieldIDOrDie(env, clazz, "mSelf", "Ljava/lang/ref/WeakReference;"); gBinderProxyOffsets.mOrgue = GetFieldIDOrDie(env, clazz, "mOrgue", "J"); clazz = FindClassOrDie(env, "java/lang/Class"); gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;"); Loading Loading
core/java/android/os/Binder.java +48 −33 Original line number Diff line number Diff line Loading @@ -27,6 +27,7 @@ import com.android.internal.util.FunctionalUtils.ThrowingRunnable; import com.android.internal.util.FunctionalUtils.ThrowingSupplier; import libcore.io.IoUtils; import libcore.util.NativeAllocationRegistry; import java.io.FileDescriptor; import java.io.FileOutputStream; Loading Loading @@ -90,6 +91,20 @@ public class Binder implements IBinder { */ private static volatile TransactionTracker sTransactionTracker = null; /** * Guestimate of native memory associated with a Binder. */ private static final int NATIVE_ALLOCATION_SIZE = 500; private static native long getNativeFinalizer(); // Use a Holder to allow static initialization of Binder in the boot image, and // possibly to avoid some initialization ordering issues. private static class NoImagePreloadHolder { public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( Binder.class.getClassLoader(), getNativeFinalizer(), NATIVE_ALLOCATION_SIZE); } // Transaction tracking code. /** Loading Loading @@ -188,8 +203,11 @@ public class Binder implements IBinder { } } /* mObject is used by native code, do not remove or rename */ private long mObject; /** * Raw native pointer to JavaBBinderHolder object. Owned by this Java object. Not null. */ private final long mObject; private IInterface mOwner; private String mDescriptor; Loading Loading @@ -360,7 +378,8 @@ public class Binder implements IBinder { * Default constructor initializes the object. */ public Binder() { init(); mObject = getNativeBBinderHolder(); NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mObject); if (FIND_POTENTIAL_LEAKS) { final Class<? extends Binder> klass = getClass(); Loading Loading @@ -643,14 +662,6 @@ public class Binder implements IBinder { return true; } protected void finalize() throws Throwable { try { destroyBinder(); } finally { super.finalize(); } } static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) { if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) { // Trying to send > 800k, this is way too much Loading @@ -674,8 +685,8 @@ public class Binder implements IBinder { } } private native final void init(); private native final void destroyBinder(); private static native long getNativeBBinderHolder(); private static native long getFinalizer(); // Entry point from android_util_Binder.cpp's onTransact private boolean execTransact(int code, long dataObj, long replyObj, Loading Loading @@ -736,11 +747,25 @@ public class Binder implements IBinder { */ final class BinderProxy implements IBinder { // See android_util_Binder.cpp for the native half of this. // TODO: Consider using NativeAllocationRegistry instead of finalization. // Assume the process-wide default value when created volatile boolean mWarnOnBlocking = Binder.sWarnOnBlocking; /** * Guestimate of native memory associated with a BinderProxy. * This includes the underlying IBinder, associated DeathRecipientList, and KeyedVector * that points back to us. We guess high since it includes a GlobalRef, which * may be in short supply. */ private static final int NATIVE_ALLOCATION_SIZE = 1000; // Use a Holder to allow static initialization of BinderProxy in the boot image, and // to avoid some initialization ordering issues. private static class NoImagePreloadHolder { public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( BinderProxy.class.getClassLoader(), getNativeFinalizer(), NATIVE_ALLOCATION_SIZE); } public native boolean pingBinder(); public native boolean isBinderAlive(); Loading Loading @@ -776,6 +801,7 @@ final class BinderProxy implements IBinder { } } private static native long getNativeFinalizer(); public native String getInterfaceDescriptor() throws RemoteException; public native boolean transactNative(int code, Parcel data, Parcel reply, int flags) throws RemoteException; Loading Loading @@ -830,21 +856,12 @@ final class BinderProxy implements IBinder { } } BinderProxy() { BinderProxy(long nativeData) { mNativeData = nativeData; NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativeData); mSelf = new WeakReference(this); } @Override protected void finalize() throws Throwable { try { destroy(); } finally { super.finalize(); } } private native final void destroy(); private static final void sendDeathNotice(DeathRecipient recipient) { if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient); try { Loading @@ -864,11 +881,9 @@ final class BinderProxy implements IBinder { // TODO: Consider making the extra native-to-java call to compute this on the fly. final private WeakReference mSelf; // Native pointer to the wrapped native IBinder object. Counted as strong reference. private long mObject; // Native pointer to native DeathRecipientList. Counted as strong reference. // Basically owned by the JavaProxy object. Reference counted only because DeathRecipients // hold a weak reference that can be temporarily promoted. private long mOrgue; /** * C++ pointer to BinderProxyNativeData. That consists of strong pointers to the * native IBinder object, and a DeathRecipientList. */ private final long mNativeData; }
core/jni/android_util_Binder.cpp +65 −76 Original line number Diff line number Diff line Loading @@ -100,9 +100,8 @@ static struct binderproxy_offsets_t jmethodID mSendDeathNotice; // Object state. jfieldID mObject; jfieldID mSelf; jfieldID mOrgue; jfieldID mNativeData; // Field holds native pointer to BinderProxyNativeData. jfieldID mSelf; // Field holds Java pointer to WeakReference to BinderProxy. } gBinderProxyOffsets; Loading Loading @@ -356,7 +355,7 @@ private: // ---------------------------------------------------------------------------- class JavaBBinderHolder : public RefBase class JavaBBinderHolder { public: sp<JavaBBinder> get(JNIEnv* env, jobject obj) Loading Loading @@ -514,7 +513,7 @@ protected: private: JavaVM* const mVM; jobject mObject; // Initial strong ref to Java-side DeathRecipient. Cleared on binderDied(). jweak mObjectWeak; // weak ref to the same Java-side DeathRecipient after binderDied(). jweak mObjectWeak; // Weak ref to the same Java-side DeathRecipient after binderDied(). wp<DeathRecipientList> mList; }; Loading Loading @@ -586,6 +585,25 @@ static void proxy_cleanup(const void* id, void* obj, void* cleanupCookie) env->DeleteGlobalRef((jobject)obj); } // We aggregate native pointer fields for BinderProxy in a single object to allow // management with a single NativeAllocationRegistry, and to reduce the number of JNI // Java field accesses. This costs us some extra indirections here. struct BinderProxyNativeData { // The native IBinder proxied by this BinderProxy. const sp<IBinder> mObject; // Death recipients for mObject. Reference counted only because DeathRecipients // hold a weak reference that can be temporarily promoted. const sp<DeathRecipientList> mOrgue; // Death recipients for mObject. BinderProxyNativeData(const sp<IBinder> &obj, DeathRecipientList *drl) : mObject(obj), mOrgue(drl) {}; }; BinderProxyNativeData* getBPNativeData(JNIEnv* env, jobject obj) { return (BinderProxyNativeData *) env->GetLongField(obj, gBinderProxyOffsets.mNativeData); } static Mutex gProxyLock; jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) Loading Loading @@ -617,25 +635,22 @@ jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val) env->DeleteGlobalRef(object); } object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor); DeathRecipientList* drl = new DeathRecipientList; BinderProxyNativeData* nativeData = new BinderProxyNativeData(val, drl); object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor, (jlong)nativeData); if (object != NULL) { LOGDEATH("objectForBinder %p: created new proxy %p !\n", val.get(), object); // The proxy holds a reference to the native object. env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get()); val->incStrong((void*)javaObjectForIBinder); // The native object needs to hold a weak reference back to the // proxy, so we can retrieve the same proxy if it is still active. // A JNI WeakGlobalRef would not currently work here, since it may be cleared // after the Java object has been condemned, and can thus yield a stale reference. jobject refObject = env->NewGlobalRef( env->GetObjectField(object, gBinderProxyOffsets.mSelf)); val->attachObject(&gBinderProxyOffsets, refObject, jnienv_to_javavm(env), proxy_cleanup); // Also remember the death recipients registered on this proxy sp<DeathRecipientList> drl = new DeathRecipientList; drl->incStrong((void*)javaObjectForIBinder); env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get())); // Note that a new object reference has been created. android_atomic_inc(&gNumProxyRefs); incRefsCreated(env); Loading @@ -651,12 +666,11 @@ sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj) if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) { JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetLongField(obj, gBinderOffsets.mObject); return jbh != NULL ? jbh->get(env, obj) : NULL; return jbh->get(env, obj); } if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) { return (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); return getBPNativeData(env, obj)->mObject; } ALOGW("ibinderForJavaObject: %p is not a Binder object", obj); Loading Loading @@ -849,35 +863,21 @@ static void android_os_Binder_flushPendingCommands(JNIEnv* env, jobject clazz) IPCThreadState::self()->flushCommands(); } static void android_os_Binder_init(JNIEnv* env, jobject obj) static jlong android_os_Binder_getNativeBBinderHolder(JNIEnv* env, jobject clazz) { JavaBBinderHolder* jbh = new JavaBBinderHolder(); if (jbh == NULL) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); return; } ALOGV("Java Binder %p: acquiring first ref on holder %p", obj, jbh); jbh->incStrong((void*)android_os_Binder_init); env->SetLongField(obj, gBinderOffsets.mObject, (jlong)jbh); return (jlong) jbh; } static void android_os_Binder_destroyBinder(JNIEnv* env, jobject obj) static void Binder_destroy(void* rawJbh) { JavaBBinderHolder* jbh = (JavaBBinderHolder*) env->GetLongField(obj, gBinderOffsets.mObject); if (jbh != NULL) { env->SetLongField(obj, gBinderOffsets.mObject, 0); ALOGV("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 // destroyBinder(). The Binder could be partially initialized for several reasons. // 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. ALOGV("Java Binder %p: ignoring uninitialized binder", obj); JavaBBinderHolder* jbh = (JavaBBinderHolder*) rawJbh; ALOGV("Java Binder: deleting holder %p", jbh); delete jbh; } JNIEXPORT jlong JNICALL android_os_Binder_getNativeFinalizer(JNIEnv*, jclass) { return (jlong) Binder_destroy; } static void android_os_Binder_blockUntilThreadAvailable(JNIEnv* env, jobject clazz) Loading @@ -896,8 +896,8 @@ static const JNINativeMethod gBinderMethods[] = { { "setThreadStrictModePolicy", "(I)V", (void*)android_os_Binder_setThreadStrictModePolicy }, { "getThreadStrictModePolicy", "()I", (void*)android_os_Binder_getThreadStrictModePolicy }, { "flushPendingCommands", "()V", (void*)android_os_Binder_flushPendingCommands }, { "init", "()V", (void*)android_os_Binder_init }, { "destroyBinder", "()V", (void*)android_os_Binder_destroyBinder }, { "getNativeBBinderHolder", "()J", (void*)android_os_Binder_getNativeBBinderHolder }, { "getNativeFinalizer", "()J", (void*)android_os_Binder_getNativeFinalizer }, { "blockUntilThreadAvailable", "()V", (void*)android_os_Binder_blockUntilThreadAvailable } }; Loading Loading @@ -1004,8 +1004,7 @@ static int int_register_android_os_BinderInternal(JNIEnv* env) static jboolean android_os_BinderProxy_pingBinder(JNIEnv* env, jobject obj) { IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); IBinder* target = getBPNativeData(env, obj)->mObject.get(); if (target == NULL) { return JNI_FALSE; } Loading @@ -1015,7 +1014,7 @@ static jboolean android_os_BinderProxy_pingBinder(JNIEnv* env, jobject obj) static jstring android_os_BinderProxy_getInterfaceDescriptor(JNIEnv* env, jobject obj) { IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); IBinder* target = getBPNativeData(env, obj)->mObject.get(); if (target != NULL) { const String16& desc = target->getInterfaceDescriptor(); return env->NewString(reinterpret_cast<const jchar*>(desc.string()), Loading @@ -1028,8 +1027,7 @@ static jstring android_os_BinderProxy_getInterfaceDescriptor(JNIEnv* env, jobjec static jboolean android_os_BinderProxy_isBinderAlive(JNIEnv* env, jobject obj) { IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); IBinder* target = getBPNativeData(env, obj)->mObject.get(); if (target == NULL) { return JNI_FALSE; } Loading Loading @@ -1151,8 +1149,7 @@ static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj, return JNI_FALSE; } IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); IBinder* target = getBPNativeData(env, obj)->mObject.get(); if (target == NULL) { jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!"); return JNI_FALSE; Loading Loading @@ -1202,8 +1199,8 @@ static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj, return; } IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); BinderProxyNativeData *nd = getBPNativeData(env, obj); IBinder* target = nd->mObject.get(); if (target == NULL) { ALOGW("Binder has been finalized when calling linkToDeath() with recip=%p)\n", recipient); assert(false); Loading @@ -1212,8 +1209,7 @@ static void android_os_BinderProxy_linkToDeath(JNIEnv* env, jobject obj, LOGDEATH("linkToDeath: binder=%p recipient=%p\n", target, recipient); if (!target->localBinder()) { DeathRecipientList* list = (DeathRecipientList*) env->GetLongField(obj, gBinderProxyOffsets.mOrgue); DeathRecipientList* list = nd->mOrgue.get(); sp<JavaDeathRecipient> jdr = new JavaDeathRecipient(env, recipient, list); status_t err = target->linkToDeath(jdr, NULL, flags); if (err != NO_ERROR) { Loading @@ -1234,8 +1230,8 @@ static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj, return res; } IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); BinderProxyNativeData* nd = getBPNativeData(env, obj); IBinder* target = nd->mObject.get(); if (target == NULL) { ALOGW("Binder has been finalized when calling linkToDeath() with recip=%p)\n", recipient); return JNI_FALSE; Loading @@ -1247,8 +1243,7 @@ static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj, status_t err = NAME_NOT_FOUND; // If we find the matching recipient, proceed to unlink using that DeathRecipientList* list = (DeathRecipientList*) env->GetLongField(obj, gBinderProxyOffsets.mOrgue); DeathRecipientList* list = nd->mOrgue.get(); sp<JavaDeathRecipient> origJDR = list->find(recipient); LOGDEATH(" unlink found list %p and JDR %p", list, origJDR.get()); if (origJDR != NULL) { Loading @@ -1274,25 +1269,20 @@ static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj, return res; } static void android_os_BinderProxy_destroy(JNIEnv* env, jobject obj) static void BinderProxy_destroy(void* rawNativeData) { // Don't race with construction/initialization AutoMutex _l(gProxyLock); IBinder* b = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject); DeathRecipientList* drl = (DeathRecipientList*) env->GetLongField(obj, gBinderProxyOffsets.mOrgue); LOGDEATH("Destroying BinderProxy %p: binder=%p drl=%p\n", obj, b, drl); if (b != nullptr) { env->SetLongField(obj, gBinderProxyOffsets.mObject, 0); env->SetLongField(obj, gBinderProxyOffsets.mOrgue, 0); drl->decStrong((void*)javaObjectForIBinder); b->decStrong((void*)javaObjectForIBinder); BinderProxyNativeData * nativeData = (BinderProxyNativeData *) rawNativeData; LOGDEATH("Destroying BinderProxy: binder=%p drl=%p\n", nativeData->mObject.get(), nativeData->mOrgue.get()); delete (BinderProxyNativeData *) rawNativeData; IPCThreadState::self()->flushCommands(); } IPCThreadState::self()->flushCommands(); JNIEXPORT jlong JNICALL android_os_BinderProxy_getNativeFinalizer(JNIEnv*, jclass) { return (jlong) BinderProxy_destroy; } // ---------------------------------------------------------------------------- Loading @@ -1305,7 +1295,7 @@ static const JNINativeMethod gBinderProxyMethods[] = { {"transactNative", "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact}, {"linkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath}, {"unlinkToDeath", "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath}, {"destroy", "()V", (void*)android_os_BinderProxy_destroy}, {"getNativeFinalizer", "()J", (void*)android_os_BinderProxy_getNativeFinalizer}, }; const char* const kBinderProxyPathName = "android/os/BinderProxy"; Loading @@ -1317,14 +1307,13 @@ static int int_register_android_os_BinderProxy(JNIEnv* env) clazz = FindClassOrDie(env, kBinderProxyPathName); gBinderProxyOffsets.mClass = MakeGlobalRefOrDie(env, clazz); gBinderProxyOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>", "()V"); gBinderProxyOffsets.mConstructor = GetMethodIDOrDie(env, clazz, "<init>", "(J)V"); gBinderProxyOffsets.mSendDeathNotice = GetStaticMethodIDOrDie(env, clazz, "sendDeathNotice", "(Landroid/os/IBinder$DeathRecipient;)V"); gBinderProxyOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J"); gBinderProxyOffsets.mNativeData = GetFieldIDOrDie(env, clazz, "mNativeData", "J"); gBinderProxyOffsets.mSelf = GetFieldIDOrDie(env, clazz, "mSelf", "Ljava/lang/ref/WeakReference;"); gBinderProxyOffsets.mOrgue = GetFieldIDOrDie(env, clazz, "mOrgue", "J"); clazz = FindClassOrDie(env, "java/lang/Class"); gClassOffsets.mGetName = GetMethodIDOrDie(env, clazz, "getName", "()Ljava/lang/String;"); Loading