diff options
| -rw-r--r-- | core/java/android/os/Binder.java | 81 | ||||
| -rw-r--r-- | core/jni/android_util_Binder.cpp | 141 |
2 files changed, 113 insertions, 109 deletions
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java index 5d28251a43e8..a6dd862564e7 100644 --- a/core/java/android/os/Binder.java +++ b/core/java/android/os/Binder.java @@ -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; @@ -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. /** @@ -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; @@ -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(); @@ -638,14 +657,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 @@ -669,8 +680,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, @@ -738,11 +749,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(); @@ -778,6 +803,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; @@ -832,21 +858,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 { @@ -866,11 +883,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; } diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 7908c9d2b609..74031910fac6 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -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; @@ -356,7 +355,7 @@ private: // ---------------------------------------------------------------------------- -class JavaBBinderHolder : public RefBase +class JavaBBinderHolder { public: sp<JavaBBinder> get(JNIEnv* env, jobject obj) @@ -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; }; @@ -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) @@ -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); @@ -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); @@ -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) @@ -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 } }; @@ -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; } @@ -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()), @@ -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; } @@ -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; @@ -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); @@ -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) { @@ -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; @@ -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) { @@ -1274,27 +1269,22 @@ 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(); } +JNIEXPORT jlong JNICALL android_os_BinderProxy_getNativeFinalizer(JNIEnv*, jclass) { + return (jlong) BinderProxy_destroy; +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gBinderProxyMethods[] = { @@ -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"; @@ -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;"); |