4. Binder通信模型
Binder IPC 的核心通信架构基于经典的 Client-Server 模型,并引入了一个关键的全局注册中心——ServiceManager。理解这三者之间的协作关系,以及内核中 binder_node(Binder 实体)与 binder_ref(Binder 引用)的映射机制,是掌握 Binder 通信原理的基石。
4.1 Client-Server 通信模型
在 Binder 驱动之上,所有跨进程交互都遵循 Client-Server 模式。Server 进程提供特定服务(如窗口管理、音频播放),Client 进程通过 Binder 驱动发起请求以调用这些服务。
下图展示了典型的 Binder Client-Server 通信流程:
4.2 ServiceManager 的作用
ServiceManager 是一个特殊的系统服务进程,在 Android 系统中扮演着“服务注册中心”的角色。它本身也是一个 Binder Server,其 Binder 引用(句柄为 0)被所有进程预先知晓。
| 角色 | 功能描述 | 关键操作 |
|---|---|---|
| 服务注册 | Server 进程在启动后,将自己的 Binder 实体(通过驱动转换为引用)注册到 ServiceManager 中,并关联一个字符串名称(如 "media.audio")。 | svc_manager.addService(name, binder) |
| 服务查询 | Client 进程在需要调用某个服务时,向 ServiceManager 发起查询请求,传入服务名称,获取该服务的 Binder 引用。 | svc_manager.getService(name) |
| 全局唯一性 | ServiceManager 是系统启动时最早启动的进程之一,其句柄 0 在内核中具有特殊含义,所有进程均可直接访问。 | 句柄 0 固定指向 ServiceManager |
下图展示了 ServiceManager 在服务注册与发现过程中的桥梁作用:
4.3 Binder 实体(binder_node)与 Binder 引用(binder_ref)
在内核 Binder 驱动中,binder_node 和 binder_ref 是描述跨进程通信两端核心对象的数据结构。它们共同构成了 Binder 通信的“寻址”基础。
4.3.1 binder_node:Binder 实体
binder_node 代表一个 Binder 服务端对象,它存在于提供服务的进程(Server)的内核空间中。每个 Binder 服务在 Server 进程中都有一个唯一的 binder_node 与之对应。
- 创建时机:当 Server 进程通过
mmap分配 Binder 缓冲区,并调用BC_ENTER_LOOPER或创建 Binder 对象时,驱动会在内核中为其分配一个 binder_node。 - 核心字段:
proc:指向所属进程的 binder_proc 结构体。ptr:指向用户空间 Binder 对象的指针(Server 本地地址)。cookie:附加数据,通常用于标识具体的 Binder 对象。refs:指向该实体所有引用的链表头。
- 生命周期:只要 Server 进程不主动销毁 Binder 对象,binder_node 就会一直存在。
4.3.2 binder_ref:Binder 引用
binder_ref 代表一个 Binder 实体的“代理”,它存在于客户端进程(Client)的内核空间中。Client 通过 binder_ref 来间接访问 Server 端的 binder_node。
- 创建时机:当 Client 进程通过 ServiceManager 获取服务,或通过 Binder 驱动传递 Binder 对象时,驱动会在 Client 进程的内核空间中创建一个 binder_ref。
- 核心字段:
node:指向所引用的 binder_node 的指针。desc:引用描述符(句柄),这是一个整数值,Client 用户空间通过该句柄来标识目标服务。death:死亡通知机制,用于监听 Server 进程是否意外终止。
- 句柄(handle):每个 binder_ref 在所属进程内都有一个唯一的句柄值。Client 用户空间通过句柄来发起 Binder 调用。
4.3.3 关系与映射
binder_node 与 binder_ref 之间是 一对多 的关系。一个 Binder 实体(binder_node)可以被多个不同的 Client 进程引用,每个 Client 进程中都会有一个对应的 binder_ref。
| 特性 | binder_node(实体) | binder_ref(引用) |
|---|---|---|
| 所属进程 | Server 进程 | Client 进程 |
| 数量关系 | 一个服务对应一个 node | 一个 node 可对应多个 ref |
| 用户空间标识 | Binder 对象指针(ptr) | 句柄(handle/desc) |
| 主要作用 | 接收并处理来自多个 Client 的请求 | 向 Server 发起调用请求 |
| 生命周期 | 随 Server 进程 Binder 对象存在 | 随 Client 进程引用存在 |
下图展示了 binder_node 与 binder_ref 在内核中的映射关系:
BR_DEAD_BINDER 或 BR_FAILED_REPLY 错误。务必在 Client 端实现死亡通知回调,及时释放无效引用。
4.4 通信流程总结
- 服务注册:Server 进程创建 Binder 对象,内核为其分配
binder_node。Server 将 Binder 对象(通过驱动转换为引用)注册到 ServiceManager。 - 服务发现:Client 进程通过句柄 0 向 ServiceManager 查询服务名称,ServiceManager 返回目标服务的 Binder 引用(句柄)。驱动在 Client 进程内核空间中创建
binder_ref,指向 Server 的binder_node。 - 远程调用:Client 通过句柄发起
BC_TRANSACTION,驱动根据binder_ref找到对应的binder_node,将请求数据拷贝到 Server 进程的缓冲区中,并唤醒 Server 进程处理。 - 结果返回:Server 处理完成后,驱动将结果数据拷贝回 Client 进程的缓冲区,完成一次完整的 RPC 调用。
通过这种模型,Binder 实现了高效、安全的跨进程通信,而 ServiceManager、binder_node 和 binder_ref 则构成了整个通信体系的“骨架”。