BnInterface与BpInterface模板
BnInterface 和 BpInterface 把同一个接口分别接到本地 BBinder 与远程 BpBinder。asInterface() 先问 Binder 是否能返回匹配 descriptor 的本地接口;不能时才构造 Proxy。因此同一份客户端代码可能拿到本地实现或远程代理。
本文面向已经读过 BBinder本地对象、BpBinder代理对象 和 transact发送 的读者。本文追踪模板继承、接口转换、descriptor 检查和 Stub/Proxy 调用路径,不展开每个 AIDL 业务方法的 Parcel 字段。
1. 两类实现
1.1 Bn本地端
源码文件:frameworks/native/libs/binder/include/binder/IInterface.h
template <typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder {
public:
virtual sp<IInterface> queryLocalInterface(
const String16& descriptor);
virtual const String16& getInterfaceDescriptor() const;
protected:
virtual IBinder* onAsBinder();
};BnInterface<I> 同时是接口和 BBinder。本地实现覆写接口业务方法或 onTransact();onAsBinder() 返回自身。
1.2 Bp远程端
template <typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase {
public:
explicit BpInterface(const sp<IBinder>& remote);
protected:
virtual IBinder* onAsBinder();
};BpInterface<I> 持有远程 IBinder,接口方法通常构造 Parcel 后调用 remote()->transact()。
| 模板 | Binder基类 | onAsBinder() | 执行位置 |
|---|---|---|---|
BnInterface<I> | BBinder | 本地对象 | 服务进程 |
BpInterface<I> | BpRefBase | 远程代理 | 对端服务 |
2. 接口转换
2.1 Cast入口
源码文件:frameworks/native/libs/binder/include/binder/IInterface.h
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(
const sp<IBinder>& obj) {
return INTERFACE::asInterface(obj);
}
template<typename INTERFACE>
inline sp<INTERFACE> checked_interface_cast(
const sp<IBinder>& obj) {
if (obj->getInterfaceDescriptor() !=
INTERFACE::descriptor) return nullptr;
return interface_cast<INTERFACE>(obj);
}普通 cast 不先验证 descriptor;checked cast 在转换点立即拒绝不匹配对象。两者都不改变远程 Binder 的 handle 或引用。
2.2 asInterface
::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;
}宏生成代码先尝试本地接口,失败后创建 Proxy。queryLocalInterface() 返回空并不等于 Binder 无效,只表示当前对象没有暴露匹配的本地实现。
2.3 asBinder
源码文件:frameworks/native/libs/binder/IInterface.cpp
sp<IBinder> IInterface::asBinder(
const sp<IInterface>& iface) {
if (iface == nullptr) return nullptr;
return sp<IBinder>::fromExisting(
iface->onAsBinder());
}BnInterface 返回自身,BpInterface 返回 remote();这是多态取回现有 Binder,不会重新创建对象。
3. Descriptor分层
3.1 本地查询
template<typename INTERFACE>
inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
const String16& descriptor) {
if (descriptor == INTERFACE::descriptor) {
return sp<IInterface>::fromExisting(this);
}
return nullptr;
}descriptor 匹配时返回本地接口;不匹配时 asInterface() 退回 Proxy,而不是强制转换错误对象。
3.2 事务令牌
源码文件:frameworks/native/libs/binder/include/binder/IInterface.h
#define CHECK_INTERFACE(interface, data, reply) \
do { \
if (!(data).checkInterface(this)) { \
return PERMISSION_DENIED; \
} \
} while (false)descriptor 选择接口对象;CHECK_INTERFACE 检查本次 Parcel 的 interface token。两者分别发生在对象转换和事务分发阶段。
3.3 AIDL边界
Android 17 仍支持手写接口宏,但源码提示优先使用 .aidl 自动生成。AIDL Stub/Proxy 仍遵循相同 local-interface/remote-proxy 模型,业务 Parcel 读写和 transaction code 由生成器提供。
4. 调用路径
4.1 本地直连
若 queryLocalInterface() 返回 BnInterface,接口方法直接调用本地实现,不经过驱动;asBinder() 仍可把它传给其他 Binder API。
4.2 远程代理
若返回空,BpInterface 保存远程 BpBinder,接口方法调用 transact();驱动交付后由 Stub 的 onTransact() 解包并调用实现。
5. 测试边界
5.1 本地对象
源码文件:frameworks/native/libs/binder/tests/binderLibTest.cpp
PromoteLocal、LocalGetExtension 和 AddManagerToManager 分别验证本地引用、扩展对象和 IInterface::asBinder() 的多态入口。
5.2 远程分发
测试 callback 继承 BBinder 并覆写 onTransact();已知 code 返回结果,未知 code 返回 UNKNOWN_TRANSACTION。这证明 Stub/Proxy 分发边界,不覆盖所有 AIDL 语言后端。
5.3 可执行阅读
rg -n "BnInterface|BpInterface|interface_cast|checked_interface_cast|DECLARE_META_INTERFACE" \
frameworks/native/libs/binder/include/binder/IInterface.h
rg -n "asBinder|onAsBinder|queryLocalInterface" \
frameworks/native/libs/binder/include/binder/IInterface.h \
frameworks/native/libs/binder/IInterface.cpp
rg -n "PromoteLocal|LocalGetExtension|AddManagerToManager|UNKNOWN_TRANSACTION" \
frameworks/native/libs/binder/tests/binderLibTest.cpp遇到调用没有进入预期远程进程时,先检查是否命中了本地 queryLocalInterface();descriptor 错误要区分普通 cast 的延迟失败和 checked cast 的立即空值;远程路径再检查 Proxy code 与 Stub 的 onTransact()。
