Register the recipient for a notification if this binder goes away. //注册binder死亡的通知
public void linkToDeath(@NonNull DeathRecipient recipient, int flags) throws RemoteException;
现场复现
提供给三方应用的sdk中的实现,而对外提供的是一个Manager 单例
java
private final IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
bindService(); //在service死亡的时候重新拉起保活
}
};
发现三方应用actiivty在销毁后有内存泄漏,持有引用的是deathReceipent
java
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
try {
iBinder.linkToDeath(mDeathRecipient, 0);
} catch (Throwable e) {
Log.e(TAG, "linkToDeath fail : ", e);
}
}
}
这里service重新链接的时候,之前已经链接的java对象iBinder会被回收,而注册到iBinder的deathRecipient没有被回收导致内存泄漏
疑问
iBinder释放的时候是否是unlink DeathRecipient,如果主动释放就不会存在内存泄漏的问题
BinderProxy.java
java
public static final long sNativeFinalizer = getNativeFinalizer();
/* Returns the native free function 随java对象一起释放的native对象 */
private static native long getNativeFinalizer();
public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
BinderProxy.class.getClassLoader(), sNativeFinalizer, NATIVE_ALLOCATION_SIZE);
frameworks/base/core/jni/android_util_Binder.cpp
cpp
JNIEXPORT jlong JNICALL android_os_BinderProxy_getNativeFinalizer(JNIEnv*, jclass) {
return (jlong) BinderProxy_destroy;
}
static void BinderProxy_destroy(void* rawNativeData)
{
BinderProxyNativeData * nativeData = (BinderProxyNativeData *) rawNativeData;
LOGDEATH("Destroying BinderProxy: binder=%p drl=%p\n",
nativeData->mObject.get(), nativeData->mOrgue.get());
delete nativeData;
IPCThreadState::self()->flushCommands();
--gNumProxies;
}
struct BinderProxyNativeData {
// Both fields are constant and not null once javaObjectForIBinder returns this as
// part of a BinderProxy.
// The native IBinder proxied by this BinderProxy.
sp<IBinder> mObject;
// Death recipients for mObject. Reference counted only because DeathRecipients
// hold a weak reference that can be temporarily promoted.
sp<DeathRecipientList> mOrgue; // Death recipients for mObject.
};
如上,iBinder销毁只是简单调用了BinderProxyNativeData析构函数,并没有将JavaDeathRecipient从List中移除,
如果发现binderProxy销毁了,并且List不为空,则会发出内存泄露警告
cpp
DeathRecipientList::~DeathRecipientList() {
LOGDEATH("Destroy DRL @ %p", this);
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) {
List< sp<JavaDeathRecipient> >::iterator iter;
for (iter = mList.begin(); iter != mList.end(); iter++) {
(*iter)->warnIfStillLive();
}
}
}
class JavaDeathRecipient : public IBinder::DeathRecipient
{
public:
JavaDeathRecipient(JNIEnv* env, jobject object, const sp<DeathRecipientList>& 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.
LOGDEATH("Adding JDR %p to DRL %p", this, list.get());
list->add(this);
gNumDeathRefsCreated.fetch_add(1, std::memory_order_relaxed);
gcIfManyNewRefs(env);
}
void clearReference()
{
sp<DeathRecipientList> list = mList.promote();
if (list != NULL) {
LOGDEATH("Removing JDR %p from DRL %p", this, list.get());
list->remove(this);
} else {
LOGDEATH("clearReference() on JDR %p but DRL wp purged", this);
}
}
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> objClassRef(env, env->GetObjectClass(mObject));
ScopedLocalRef<jstring> nameRef(env,
(jstring) env->CallObjectMethod(objClassRef.get(), gClassOffsets.mGetName));
ScopedUtfChars nameUtf(env, nameRef.get());
if (nameUtf.c_str() != NULL) {
ALOGW("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 {
ALOGW("BinderProxy being destroyed; unable to get DR object name");
env->ExceptionClear();
}
}
}
}
List添加是在JavaDeathRecipient构造函数中, 移除只有在unlinkToDeath的时候调用clearReference会从list中移除
cpp
static jboolean android_os_BinderProxy_unlinkToDeath(JNIEnv* env, jobject obj,
jobject recipient, jint flags)
{
jboolean res = JNI_FALSE;
if (recipient == NULL) {
jniThrowNullPointerException(env, NULL);
return res;
}
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;
}
LOGDEATH("unlinkToDeath: binder=%p recipient=%p\n", target, recipient);
if (!target->localBinder()) {
status_t err = NAME_NOT_FOUND;
// If we find the matching recipient, proceed to unlink using that
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) {
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();//从list中移除
}
}
}
if (err == NO_ERROR || err == DEAD_OBJECT) {
res = JNI_TRUE;
} else {
jniThrowException(env, "java/util/NoSuchElementException",
base::StringPrintf("Death link does not exist (%s)",
statusToString(err).c_str())
.c_str());
}
}
return res;
}
解决方案
在收到binderDied通知后主动调用unlinkToDeath
java
private static class DeathRecipient implements IBinder.DeathRecipient {
private IBinder mBinder;
private Manager mManager;
public DeathRecipient(IBinder iBinder, Manager manager) {
mBinder = iBinder;
mManager = manager;
}
@Override
public void binderDied() {
mBinder.unlinkToDeath(this, 0);
mManager.bindService();
}
}