4. Binder架构总览
Binder 是 Android 系统中最重要的 IPC(进程间通信)机制。它并不是一个单纯的库,而是一套由内核驱动、用户态服务、代理对象和引用计数共同构成的通信体系。理解 Binder,最有效的方式是先抓住四个核心角色:Binder 驱动、ServiceManager、Client 和 Server。它们分别承担“传输中枢”“服务注册与查询”“服务使用方”“服务提供方”的职责,并通过 Binder 协议形成一条完整的调用链。
一、四大角色的职责定位
Binder 架构中的四个角色并不是并列的四个进程,而是从“通信职责”角度划分出来的逻辑角色。同一个进程在不同场景下可能扮演不同角色,例如系统服务进程通常既是 Server,也可能作为 Client 去调用其他服务。
| 角色 | 所在位置 | 核心职责 | 关键对象/接口 |
|---|---|---|---|
| Binder 驱动 | Linux 内核空间 | 提供 /dev/binder 设备,负责数据拷贝、线程调度、引用计数、死亡通知和权限校验 | binder_device、binder_proc、binder_node、binder_ref |
| ServiceManager | 用户态系统服务进程 | 管理服务名称与 Binder 引用的映射,提供 addService、getService、checkService 等接口 | IServiceManager、servicemanager.rc |
| Server | 服务提供方进程 | 实现具体业务逻辑,向 ServiceManager 注册服务,等待并处理 Client 请求 | BnInterface、onTransact、BBinder |
| Client | 服务使用方进程 | 通过 ServiceManager 查询服务,获得代理对象后发起跨进程调用 | BpInterface、transact、IBinder |
二、整体协作关系图
下图展示了四大角色在一次典型“获取服务并调用”过程中的位置与数据流向。Client 并不直接连接 Server,而是先经过 ServiceManager 获取代理,再通过 Binder 驱动完成真正的跨进程传输。
三、一次完整调用的方法流程
以 Client 调用某个系统服务为例,整个过程可以拆解为“注册、查询、调用、返回”四个阶段。每个阶段都依赖 Binder 驱动完成跨进程边界的数据传递。
- Server 注册服务:Server 进程启动后创建 BBinder 对象,通过 IServiceManager::addService 把服务名称和 Binder 引用交给 ServiceManager。ServiceManager 记录名称与 handle 的映射关系。
- Client 查询服务:Client 调用 getService("xxx"),请求先到达 ServiceManager。ServiceManager 返回一个 BpBinder 代理,Client 侧通常再封装成 BpInterface。
- Client 发起调用:Client 调用代理对象的 transact(),数据被写入 Parcel,经 Binder 驱动拷贝到内核缓冲区,再投递到 Server 进程。
- Server 处理请求:Server 的 Binder 线程被唤醒,调用 onTransact() 解析 code 和 data,执行真实业务逻辑,并把结果写回 reply。
- 结果返回:Binder 驱动把 reply 数据回传给 Client,Client 从 Parcel 中读取结果,一次跨进程调用结束。
// 简化后的调用链示意
Client:
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("demo.service"));
sp<IDemo> demo = interface_cast<IDemo>(binder);
demo->sayHello(String16("binder"));
Server:
status_t DemoService::onTransact(uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags) {
switch (code) {
case SAY_HELLO:
reply->writeString16(String16("hello from server"));
return NO_ERROR;
}
return BBinder::onTransact(code, data, reply, flags);
}
四、案例场景:从应用到系统服务
假设一个应用需要获取当前设备电量。应用进程是 Client,它并不直接读取内核节点,而是通过 Binder 调用 BatteryService。BatteryService 运行在 system_server 进程中,作为 Server 向 ServiceManager 注册了 "battery" 服务。应用先通过 ServiceManager 拿到 BatteryService 的代理,再调用 getCapacity()。Binder 驱动负责把请求从应用进程送到 system_server,BatteryService 读取底层数据后返回电量值。整个过程中,应用与 system_server 之间没有直接 socket 连接,所有跨进程细节都被 Binder 驱动屏蔽。
五、常见误区与复盘
- 误区一:Client 直接连接 Server。实际上 Client 只持有 Server 的代理,真正传输由 Binder 驱动完成,Client 与 Server 之间没有直接的文件描述符或 socket。
- 误区二:ServiceManager 负责业务逻辑。ServiceManager 只做名称与引用的映射,不参与具体业务处理,也不转发调用数据。
- 误区三:Binder 驱动只是“搬运工”。驱动还负责线程池管理、引用计数、死亡通知和权限校验,是 Binder 安全性和稳定性的核心。
- 误区四:一个进程只能扮演一种角色。system_server 既注册大量服务作为 Server,也会作为 Client 调用其他服务,角色是动态的。
掌握这四大角色及其协作关系,是后续理解 Binder 驱动源码、AIDL 生成代码、ServiceManager 启动流程以及 Binder 性能优化的基础。只有先看清“谁在注册、谁在查询、谁在传输、谁在处理”,才能在遇到跨进程调用问题时快速定位到正确的层次。