Binder代理生命周期
代理模式不是“把远程对象包装一下”这么简单。一次远程 Binder 引用至少经过 C++ 接口层的 BpInterface、native 传输层的 BpBinder、Java 桥接层的 BinderProxy,以及内核进程中的 binder_ref。
本文面向已经读过 Binder的C/S模型 的读者,专门追踪远程代理从 形成到失效的生命周期:接口转换为何先尝试本地短路,handle 如何缓存成 BpBinder,Java 如何复用 BinderProxy,Parcel 如何携带代理,transact 如何调用,以及 GC、服务死亡和 native finalizer 如何收束引用。
1. 代理边界
四层对象
| 层 | 对象 | 所有状态 | 失效信号 |
|---|---|---|---|
| C++接口 | BpInterface | remote IBinder | transact status |
| native代理 | BpBinder | handle、mAlive、ObjectManager | DEAD_OBJECT |
| Java代理 | BinderProxy | nativeData、弱引用表、监听器 | RemoteException |
| 内核引用 | binder_ref | desc、strong/weak、目标 node | ref/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()
#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
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()
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()
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
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
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()
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()
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
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()
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()
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
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
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()
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
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()
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 会自动刷新代理。
