android linkToDeath内存泄露分析

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();
    }
}
​
相关推荐
黄林晴3 小时前
如何判断手机是否是纯血鸿蒙系统
android
火柴就是我3 小时前
flutter 之真手势冲突处理
android·flutter
法的空间3 小时前
Flutter JsonToDart 支持 JsonSchema
android·flutter·ios
循环不息优化不止3 小时前
深入解析安卓 Handle 机制
android
恋猫de小郭3 小时前
Android 将强制应用使用主题图标,你怎么看?
android·前端·flutter
jctech4 小时前
这才是2025年的插件化!ComboLite 2.0:为Compose开发者带来极致“爽”感
android·开源
用户2018792831674 小时前
为何Handler的postDelayed不适合精准定时任务?
android
叽哥4 小时前
Kotlin学习第 8 课:Kotlin 进阶特性:简化代码与提升效率
android·java·kotlin
Cui晨4 小时前
Android RecyclerView展示List<View> Adapter的数据源使用View
android
氦客4 小时前
Android Doze低电耗休眠模式 与 WorkManager
android·suspend·休眠模式·workmanager·doze·低功耗模式·state_doze