Skip to content

Binder代理生命周期

从接口转换到 handle 代理、Parcel 对象复用、远程调用、代理死亡和 native 清理,追踪 Binder 代理的完整生命周期。

基于android-17.0.0_r1
AndroidBinderBpBinderBinderProxy源码阅读

Binder代理生命周期 ​

代理模式不是“把远程对象包装一下”这么简单。一次远程 Binder 引用至少经过 C++ 接口层的 BpInterface、native 传输层的 BpBinder、Java 桥接层的 BinderProxy,以及内核进程中的 binder_ref。

本文面向已经读过 Binder的C/S模型 的读者,专门追踪远程代理从 形成到失效的生命周期:接口转换为何先尝试本地短路,handle 如何缓存成 BpBinder,Java 如何复用 BinderProxy,Parcel 如何携带代理,transact 如何调用,以及 GC、服务死亡和 native finalizer 如何收束引用。

1. 代理边界 ​

四层对象 ​

层对象所有状态失效信号
C++接口BpInterfaceremote IBindertransact status
native代理BpBinderhandle、mAlive、ObjectManagerDEAD_OBJECT
Java代理BinderProxynativeData、弱引用表、监听器RemoteException
内核引用binder_refdesc、strong/weak、目标 noderef/node 清理

BpInterface 让生成接口方法具有本地调用形状;BpBinder 才持有内核 handle;BinderProxy 是 Java 对 native IBinder 的托管包装。代理保存引用和入口,但不拥有服务线程。

2. 接口转换 ​

本地短路 ​

源码文件:frameworks/native/libs/binder/include/binder/IInterface.h

相关宏:DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0()

cpp
#define DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(ITYPE, INAME, BPTYPE) \
    ::android::sp<ITYPE> ITYPE::asInterface( \
            const ::android::sp<::android::IBinder>& obj) { \
        ::android::sp<ITYPE> intr; \
        if (obj != nullptr) { \
            intr = ::android::sp<ITYPE>::cast( \
                    obj->queryLocalInterface(ITYPE::descriptor)); \
            if (intr == nullptr) \
                intr = ::android::sp<BPTYPE>::make(obj); \
        } \
        return intr; \
    }

asInterface 的第一步不是创建代理,而是 queryLocalInterface。如果对象属于本进程且 descriptor 匹配,调用直接落到本地接口;没有跨进程、Parcel 或 handle。

远程接口 ​

源码文件:frameworks/native/libs/binder/include/binder/IInterface.h

cpp
template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(
        const sp<IBinder>& remote)
    : BpRefBase(remote)
{
}

template<typename INTERFACE>
inline IBinder* BpInterface<INTERFACE>::onAsBinder()
{
    return remote();
}

远程 queryLocalInterface 返回空,asInterface 才创建 BpInterface。透明只覆盖接口形状,不代表 同步、异常、身份和线程语义与本地调用相同。

3. Native代理 ​

创建句柄 ​

源码文件:frameworks/native/libs/binder/BpBinder.cpp

相关函数:BpBinder::BpBinder()、binderHandle()、remoteBinder()

cpp
BpBinder::BpBinder(BinderHandle&& handle, int32_t trackedUid)
    : BpBinder(Handle(handle))
{
    mTrackedUid = trackedUid;
    IPCThreadState::self()->incWeakHandle(
            this->binderHandle(), this);
}

int32_t BpBinder::binderHandle() const {
    return std::get<BinderHandle>(mHandle).handle;
}

BpBinder* BpBinder::remoteBinder() {
    return this;
}

构造函数记录 handle,并向驱动发送弱引用增加命令。remoteBinder 返回自身,使通用 IBinder 代码可以取得代理;服务端 BBinder 则走 localBinder。

进程缓存 ​

源码文件:frameworks/native/libs/binder/ProcessState.cpp

相关函数:getStrongProxyForHandle()、expungeHandle()

cpp
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    std::function<void()> postTask;
    std::unique_lock<std::mutex> lock(mLock);
    handle_entry* entry = lookupHandleLocked(handle);
    if (entry == nullptr)
        return nullptr;

    IBinder* binder = entry->binder;
    if (binder == nullptr || !entry->refs->attemptIncWeak(this)) {
        sp<BpBinder> proxy = BpBinder::PrivateAccessor::create(
                handle, &postTask);
        entry->binder = proxy.get();
        if (proxy)
            entry->refs = proxy->getWeakRefs();
        result = proxy;
    } else {
        result.force_set(binder);
        entry->refs->decWeak(this);
    }
    lock.unlock();
    if (postTask)
        postTask();
    return result;
}

handle 表是 native 代理复用边界:同一进程再次收到同一 handle 时,优先提升已有弱引用;代理 无法提升时才新建 BpBinder。实际源码还包含 handle 0 的 context manager 探测分支。

源码文件:frameworks/native/libs/binder/ProcessState.cpp

cpp
void ProcessState::expungeHandle(int32_t handle, IBinder* binder)
{
    std::unique_lock<std::mutex> lock(mLock);
    handle_entry* entry = lookupHandleLocked(handle);
    if (entry && entry->binder == binder)
        entry->binder = nullptr;
}

条件判断避免旧代理析构时误清掉已经替换的新代理。

附加状态 ​

源码文件:frameworks/native/libs/binder/BpBinder.cpp

相关类型:BpBinder::ObjectManager

cpp
void* BpBinder::ObjectManager::attach(const void* objectID,
        void* object, void* cleanupCookie,
        IBinder::object_cleanup_func func) {
    entry_t entry{object, cleanupCookie, func};
    if (mObjects.find(objectID) != mObjects.end())
        return mObjects[objectID].object;
    mObjects.insert({objectID, entry});
    return nullptr;
}

BpBinder::ObjectManager::~ObjectManager() {
    for (auto item : mObjects) {
        const entry_t& entry = item.second;
        if (entry.func != nullptr)
            entry.func(item.first, entry.object,
                    entry.cleanupCookie);
    }
    mObjects.clear();
}

ObjectManager 附加的是单个 native 代理的辅助状态,不是全局缓存。attach 不覆盖相同 objectID, detach 不执行 cleanup;析构时才处理仍留在 map 中的回调。

4. Java代理 ​

NativeData ​

源码文件:frameworks/base/core/jni/android_util_Binder.cpp

相关类型:BinderProxyNativeData、javaObjectForIBinder()

cpp
struct BinderProxyNativeData {
    sp<IBinder> mObject;
    sp<DeathRecipientList> mOrgue;
    sp<FrozenStateChangeCallbackList>
            mFrozenStateChangeCallbackList;
};

jobject javaObjectForIBinder(JNIEnv* env,
        const sp<IBinder>& value)
{
    if (value == nullptr)
        return nullptr;
    if (value->checkSubclass(
            android::internal::JavaBBinderBase::getExtSubclassID())) {
        return static_cast<JavaBBinderExt*>(
                value.get())->object();
    }

    BinderProxyNativeData* nativeData =
            new BinderProxyNativeData;
    nativeData->mObject = value;
    nativeData->mOrgue = sp<DeathRecipientList>::make();
    nativeData->mFrozenStateChangeCallbackList =
            sp<FrozenStateChangeCallbackList>::make();

    jobject object = env->CallStaticObjectMethod(
            gBinderProxyOffsets.mClass,
            gBinderProxyOffsets.mGetInstance,
            reinterpret_cast<jlong>(nativeData),
            reinterpret_cast<jlong>(value.get()));
    BinderProxyNativeData* actualNativeData =
            getBPNativeData(env, object);
    if (actualNativeData == nativeData) {
        nativeData->tryTagObject();
    } else {
        delete nativeData;
    }
    return object;
}

native 对象本来是 JavaBBinderExt 时直接返回原 Java Binder;否则创建 nativeData 并进入 BinderProxy 复用表。这个分叉保证本地 Java Binder 不会被错误包装成远程代理。

Java复用 ​

源码文件:frameworks/base/core/java/android/os/BinderProxy.java

相关函数:getInstance()

java
private static BinderProxy getInstance(
        long nativeData, long iBinder) {
    synchronized (sProxyMap) {
        BinderProxy result = sProxyMap.get(iBinder);
        if (result != null)
            return result;
        result = new BinderProxy(nativeData);
        NoImagePreloadHolder.sRegistry.registerNativeAllocation(
                result, nativeData);
        sProxyMap.set(iBinder, result);
        return result;
    }
}

Java 表以 native IBinder 地址为 key,并用弱引用保存 BinderProxy。已有代理存活时直接复用; JNI 随后比较返回对象实际持有的 nativeData,删除竞争失败的新 nativeData。

调用监听 ​

源码文件:frameworks/base/core/java/android/os/BinderProxy.java

java
public boolean transact(int code, Parcel data,
        Parcel reply, int flags) throws RemoteException {
    Binder.checkParcel(this, code, data,
            "Unreasonably large binder buffer");
    final Binder.ProxyTransactListener listener =
            sTransactListener;
    Object session = listener != null
            ? listener.onTransactStarted(this, code, flags)
            : null;
    try {
        return transactNative(code, data, reply, flags);
    } finally {
        if (listener != null)
            listener.onTransactEnded(session);
    }
}

BinderProxy 不解释业务 code;它在 Java 侧包住检查、监听、trace、AppOps 和异常转换,真正 事务仍由 native BpBinder 发出。

5. Parcel引用 ​

写入形态 ​

源码文件:frameworks/native/libs/binder/Parcel.cpp

相关函数:flattenBinder()

cpp
status_t Parcel::flattenBinder(const sp<IBinder>& binder)
{
    flat_binder_object obj;
    BBinder* local = binder ? binder->localBinder() : nullptr;
    if (local) {
        obj.hdr.type = BINDER_TYPE_BINDER;
        obj.binder = reinterpret_cast<uintptr_t>(
                local->getWeakRefs());
        obj.cookie = reinterpret_cast<uintptr_t>(local);
    } else {
        BpBinder* proxy =
                binder ? binder->remoteBinder() : nullptr;
        obj.hdr.type = BINDER_TYPE_HANDLE;
        obj.binder = 0;
        obj.handle = proxy ? proxy->binderHandle() : 0;
        obj.cookie = 0;
    }
    return writeObject(obj, false);
}

本地对象写 ptr/cookie,远程代理写 handle。Parcel 传递的是引用描述,不是对象内存副本。

读取形态 ​

源码文件:frameworks/native/libs/binder/Parcel.cpp

相关函数:unflattenBinder()

cpp
const flat_binder_object* flat = readObject(false);
switch (flat->hdr.type) {
    case BINDER_TYPE_BINDER: {
        sp<IBinder> binder = sp<IBinder>::fromExisting(
                reinterpret_cast<IBinder*>(flat->cookie));
        return finishUnflattenBinder(binder, out);
    }
    case BINDER_TYPE_HANDLE: {
        sp<IBinder> binder =
                ProcessState::self()->getStrongProxyForHandle(
                        flat->handle);
        return finishUnflattenBinder(binder, out);
    }
}

BINDER_TYPE_BINDER 恢复本地对象;BINDER_TYPE_HANDLE 进入 ProcessState handle 表。于是同一个 远程引用经多次 Parcel 往返时,可以回到已有 BpBinder 和 BinderProxy,而不必每次新建。

6. 远程调用 ​

转发入口 ​

源码文件:frameworks/native/libs/binder/BpBinder.cpp

cpp
status_t BpBinder::transact(uint32_t code,
        const Parcel& data, Parcel* reply, uint32_t flags)
{
    if (!mAlive)
        return DEAD_OBJECT;

    status_t status;
    if (isRpcBinder()) {
        status = rpcSession()->transact(
                sp<IBinder>::fromExisting(this),
                code, data, reply, flags);
    } else {
        status = IPCThreadState::self()->transact(
                binderHandle(), code, data, reply, flags);
    }

    if (status == DEAD_OBJECT)
        mAlive = 0;
    return status;
}

代理只负责选择 kernel Binder 或 RPC Binder 分支并保存最后已知死亡状态。服务线程、buffer 和 reply 等待属于更下层 owner。

透明限制 ​

代理保持方法形状一致,但不会消除这些差异:

  • 远程同步调用会阻塞当前线程;
  • 服务实现运行在另一个进程和线程;
  • 调用方身份由驱动交付;
  • reply 与异常需要序列化;
  • 本地短路没有驱动和死亡语义。

7. 代理失效 ​

死亡标记 ​

源码文件:frameworks/native/libs/binder/BpBinder.cpp

cpp
if (status == DEAD_OBJECT)
    mAlive = 0;

if (!mAlive)
    return DEAD_OBJECT;

mAlive 是最近一次事务得到的已知状态,不是实时探针。服务重启不会让旧 BpBinder 自动指向 新 node;上层必须重新查找服务。

Java清理 ​

源码文件:frameworks/base/core/jni/android_util_Binder.cpp

相关函数:BinderProxy_destroy()

cpp
static void BinderProxy_destroy(void* rawNativeData)
{
    BinderProxyNativeData* nativeData =
            static_cast<BinderProxyNativeData*>(
                    rawNativeData);
    delete nativeData;
    IPCThreadState::self()->flushCommands();
}

Java BinderProxy 被 GC 后,nativeData 释放其 IBinder 强引用和回调列表,再 flush 当前线程命令。 BpBinder 析构与驱动 ref 减少可能发生得更晚;Java GC、native 引用和内核引用不是同一时刻。

Native析构 ​

源码文件:frameworks/native/libs/binder/BpBinder.cpp

cpp
BpBinder::~BpBinder() {
    if (isRpcBinder())
        return;

    IPCThreadState* ipc = IPCThreadState::self();
    if (ipc) {
        ipc->expungeHandle(binderHandle(), this);
        ipc->decWeakHandle(binderHandle());
    }
}

实际析构还处理代理计数、obituary 和附加对象;核心清理是减少 handle 弱引用并从 ProcessState 缓存中移除当前实例。

8. 失败竞态 ​

代理竞争 ​

Java ProxyMap 和 native handle 表都采用弱引用复用。旧 Java 包装可能已被 GC,而 BpBinder 仍被其他 native owner 持有;新包装会竞争同一 native IBinder,失败创建的 nativeData 必须 立即清理。

服务替换 ​

服务名重新注册并不改变旧代理。旧 BpBinder 仍指向原 node,死亡后返回 DEAD_OBJECT;重新执行 ServiceManager 查询才可能获得新代理。服务缓存必须有自己的死亡清理策略。

附加对象 ​

ObjectManager attach 不能覆盖同一 objectID;detach 不调用 cleanup;代理析构才执行剩余 cleanup。 使用者必须明确哪个路径拥有 cleanup 责任。

9. 测试输入 ​

Java监听 ​

源码文件:frameworks/base/core/tests/coretests/src/android/os/BinderProxyTest.java

相关测试:testNoListener()、testListener()、testSessionPropagated()

测试使用 ActivityManager 触发真实 Binder 调用,分别断言未安装监听器时计数为 0、安装后 start/end 各为 1,以及 session 被原样传到结束回调。它证明 Java 代理的监听生命周期,不证明 服务端线程或 native 事务耗时。

缓存死亡 ​

源码文件:frameworks/native/libs/binder/tests/binderCacheUnitTest.cpp

相关测试:LibbinderCacheTest.RemoveFromCacheOnServerDeath()

cpp
sp<IBinder> binder1 =
        defaultServiceManager()->checkService(kServerName);
EXPECT_EQ(OK, mServiceManager->addService(
        kCachedServiceName, binder1));
ASSERT_EQ(binder1,
        mServiceManager->checkService(kCachedServiceName));

killServer(binder1);
sp<IBinder> binder2 = sp<BBinder>::make();
EXPECT_EQ(OK, mServiceManager->addService(
        kCachedServiceName, binder2));
ASSERT_EQ(binder2,
        mServiceManager->checkService(kCachedServiceName));

输入是被缓存的远程服务,动作是杀死旧服务并以同名注册新 Binder,断言最终查询返回新对象。 它证明缓存 owner 必须响应服务死亡,不证明旧 BpBinder 会自动复活。

死亡通知 ​

源码文件:frameworks/native/libs/binder/tests/binderLibTest.cpp

相关测试:BinderLibTest.DeathNotificationStrongRef()

测试给代理注册 DeathRecipient,让服务执行退出事务,flush 命令并等待死亡事件;随后 unlinkToDeath 返回 DEAD_OBJECT。它能证明死亡通知与代理引用的交互,不能覆盖多个 recipient、 冻结通知或 Java GC 竞态。

10. 阅读边界 ​

生命周期主线 ​

把代理问题限定为一条可回溯路径:readStrongBinder 得到 handle → ProcessState 按 handle 查找或创建 BpBinder → BinderProxy 复用同一 native peer → transact 使用该 handle → death/GC 触发清理。 本篇前面的代码分别展示这些步骤;下面的图只强调状态关系,不替代各实现段的源码阅读。

图中的 Dead 只表示旧代理的 mAlive 状态,不表示 ServiceManager 中的服务名已经自动指向新对象; Recreated 必须由上层重新发现服务并创建新的引用。

本文证明了接口代理形成、native/Java 两级复用、Parcel 引用恢复、远程转发、死亡失效与清理。 没有展开完整 binder_ref 强弱计数、死亡通知算法、代理数量水位、AIDL 参数生成、RPC Binder session、allocator 和 SELinux。

继续阅读 Binder的C/S模型 复习角色变化,再进入 Binder 引用计数和 Parcel 对象专题。复查代理问题时,应依次标出接口转换、native handle 缓存、Java ProxyMap、 Parcel 形态、事务结果和清理 owner。

11. 代理诊断顺序 ​

遇到“服务重启后调用仍失败”,先确认上层是否重新执行服务发现;再检查 ProcessState 是否仍返回旧 BpBinder,最后查看 Java BinderProxy 是否复用了同一 native peer。只有拿到新 handle/ref 或确认缓存已 清除,才能断言代理已经重建。旧代理的 mAlive=false 只说明它不会继续发送,不说明同名服务已经恢复。

源码文件:frameworks/native/libs/binder/tests/binderCacheUnitTest.cpp

RemoveFromCacheOnServerDeath 的输入是已缓存的远程服务,动作是杀死服务后用同名注册新 Binder,断言新查询返回新对象;它证明缓存清理和重新发现的组合,不证明任意业务层 singleton 会自动刷新代理。