Skip to content

BpBinder代理对象

追踪 handle 到 BpBinder 的缓存、弱强引用、transact、死亡通知和析构清理。

基于android-17.0.0_r1
AndroidBinderBpBinderNative框架源码阅读

BpBinder代理对象 ​

BpBinder 是 native 进程中代表远程 Binder node 的代理对象。它的关键身份不是 C++ 指针,而是驱动分配给当前进程的 handle;ProcessState 用 handle 表缓存代理的裸指针和弱引用控制块,避免同一 handle 被无故创建多个代理。代理的强引用、弱引用、死亡通知和析构都会回到 IPCThreadState,最终产生对应 Binder 命令。

本文面向已经读过 ProcessState初始化、IPCThreadState线程绑定、transact发送 和 Binder远程引用 的读者。本文回答代理从哪里来、何时复用、强弱引用何时通知驱动、死亡后为什么不复活,以及析构如何与 handle 表并发协作。不展开 Java BinderProxy 的包装层。

1. 代理入口 ​

1.1 Handle查找 ​

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

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

cpp
ProcessState::handle_entry*
ProcessState::lookupHandleLocked(int32_t handle) {
    const size_t N = mHandleToObject.size();
    if (N <= static_cast<size_t>(handle)) {
        handle_entry e{.binder = nullptr, .refs = nullptr};
        status_t err = mHandleToObject.insertAt(
                e, N, handle + 1 - N);
        if (err < NO_ERROR) return nullptr;
    }
    return &mHandleToObject.editItemAt(handle);
}

handle 表按整数下标扩展;新槽位初始化为空 Binder 和弱引用。mLock 由调用者持有,保证查找、复用和替换不会与代理析构同时修改同一槽位。

1.2 复用或创建 ​

cpp
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) {
    std::unique_lock<std::mutex> lock(mLock);
    handle_entry* e = lookupHandleLocked(handle);
    if (e != nullptr) {
        IBinder* b = e->binder;
        if (b == nullptr || !e->refs->attemptIncWeak(this)) {
            sp<BpBinder> bp = BpBinder::PrivateAccessor::create(
                    handle, &postTask);
            e->binder = bp.get();
            if (bp) e->refs = bp->getWeakRefs();
            result = bp;
        } else {
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }
    ...
}

已有代理且弱引用仍可提升时直接复用;代理已析构或弱控制块不可提升时创建新 BpBinder。锁内只准备对象和 post task,解锁后才执行 task,避免构造期间回调再次取得同一把锁。

1.3 Context句柄 ​

handle 0 通常代表 context manager。若当前进程已经设置了本地 the_context_object,直接返回本地对象;否则驱动为 handle 0 提供特殊引用。ServiceManager 启动和普通客户端获取 context object 因此共享同一个 handle 表入口,但本地 context object 分支不创建 BpBinder。

2. 引用生命周期 ​

2.1 构造弱引用 ​

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

相关函数:BpBinder::BpBinder()

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

创建代理时先向当前线程状态登记 handle 的弱引用。此时还不代表应用持有强 sp,但保证驱动返回该 handle 时,代理生命周期可以被安全观察。

2.2 首个强引用 ​

cpp
void BpBinder::onFirstRef() {
    IPCThreadState* ipc = IPCThreadState::self();
    if (ipc) ipc->incStrongHandle(
            binderHandle(), this);
}

第一次强引用会把 handle 的 strong acquire 交给 IPCThreadState;后续复制 sp<BpBinder> 不重复发送 acquire。驱动引用计数因此与本进程代理的强引用边沿对应。

2.3 最后强引用 ​

cpp
void BpBinder::onLastStrongRef(const void* /*id*/) {
    IPCThreadState* ipc = IPCThreadState::self();
    if (ipc && !kDecStrongLast) {
        ipc->decStrongHandle(binderHandle());
    }
    ...
}

最后一个强引用释放时发送 strong decrement(具体时机受 kDecStrongLast 配置影响),并处理死亡 obituary。强引用归零不一定立即析构,因为 BpBinder 采用弱生命周期;真正析构还要等弱引用控制块也结束。

2.4 析构清理 ​

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

析构先从 ProcessState/IPCThreadState 的 handle 表移除自己,再减少驱动弱引用。expungeHandle() 只在槽位仍指向当前对象时清空,防止旧代理析构覆盖并发期间已经替换的新代理。

3. 事务与死亡 ​

3.1 代理发送 ​

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

相关函数:BpBinder::transact()

cpp
status_t BpBinder::transact(uint32_t code,
        const Parcel& data, Parcel* reply, uint32_t flags) {
    if (mAlive) {
        flags &= ~static_cast<uint32_t>(FLAG_PRIVATE_VENDOR);
        status_t status = IPCThreadState::self()->transact(
                binderHandle(), code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }
    return DEAD_OBJECT;
}

代理把 handle 转交给 IPCThreadState::transact()。一旦返回 DEAD_OBJECT,mAlive 置零;之后即使远端进程后来启动同名服务,这个旧代理也不会复活,调用者必须重新取得新的 Binder。

3.2 死亡通知 ​

cpp
status_t BpBinder::linkToDeath(
        const sp<DeathRecipient>& recipient,
        void* cookie, uint32_t flags) {
    LOG_ALWAYS_FATAL_IF(recipient == nullptr,
                        "recipient must be non-NULL");
    if (!mObitsSent && !mObituaries) {
        mObituaries = new Vector<Obituary>;
        getWeakRefs()->incWeak(this);
        IPCThreadState* self = IPCThreadState::self();
        self->requestDeathNotification(
                binderHandle(), this);
        self->flushCommands();
    }
    mObituaries->add({recipient, cookie, flags});
    return NO_ERROR;
}

第一次 linkToDeath() 才向驱动申请死亡通知;多个 recipient 共享一次驱动请求。死亡到达后 reportOneDeath() 以弱 BpBinder 调用 recipient,通知对象的 owner 是 DeathRecipient,不是发送线程本身。

4. 代理失效 ​

4.1 同名服务重启 ​

服务进程死亡让旧 BpBinder 进入 mAlive=false;ServiceManager 删除旧表项并可能重新注册新 Binder。旧代理的 handle 不能指向新 node,新的查询会通过 handle 表的弱引用状态决定复用或创建新的代理。

4.2 代理数量 ​

BpBinder::create() 维护全局 proxy count,并可按 UID 统计和触发高水位/限制回调。数量统计是资源保护机制,不改变单个 handle 代理的强弱引用语义。

4.3 RPC分支 ​

BpBinder 也可以携带 RpcSession 地址,但本文只讲 kernel Binder handle。RPC 构造函数不调用 incWeakHandle(),析构也不走 kernel handle 清理;不能把两类 BpBinder 生命周期混写。

5. 测试边界 ​

5.1 死亡通知 ​

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

DeathNotificationStrongRef 注册 DeathRecipient、让服务退出、等待事件并断言之后 unlinkToDeath() 返回 DEAD_OBJECT;DeathNotificationMultiple 验证多个进程/recipient 的通知和线程池消费边界。这些测试直接覆盖代理死亡状态与 obituary,不等同于 ServiceManager 的服务表清理。

5.2 代理计数 ​

BinderProxyCount 创建多个代理并逐个销毁,断言全局 proxy count 增减;BinderProxyCountCallback 设置 UID 水位,验证 warning/limit callback。它们证明统计 owner 在 BpBinder,而不是 ProcessState handle 表。

5.3 可执行阅读 ​

bash
rg -n "getStrongProxyForHandle|lookupHandleLocked|expungeHandle" \
  frameworks/native/libs/binder/ProcessState.cpp

rg -n "BpBinder::create|BpBinder::transact|onFirstRef|onLastStrongRef|BpBinder::~BpBinder" \
  frameworks/native/libs/binder/BpBinder.cpp

rg -n "DeathNotificationStrongRef|DeathNotificationMultiple|BinderProxyCount" \
  frameworks/native/libs/binder/tests/binderLibTest.cpp

排查“同一个服务出现多个代理”或“旧代理无法恢复”时,先看 handle 表弱引用是否仍可提升,再区分代理 mAlive、远端 node 死亡和 ServiceManager 重新注册;不要用服务名相同推断 handle 或 BpBinder 对象必然相同。