4. Binder架构总览

Binder 是 Android 系统中最重要的 IPC(进程间通信)机制。它并不是一个单纯的库,而是一套由内核驱动、用户态服务、代理对象和引用计数共同构成的通信体系。理解 Binder,最有效的方式是先抓住四个核心角色:Binder 驱动、ServiceManager、Client 和 Server。它们分别承担“传输中枢”“服务注册与查询”“服务使用方”“服务提供方”的职责,并通过 Binder 协议形成一条完整的调用链。

核心记忆:Server 向 ServiceManager 注册服务;Client 向 ServiceManager 查询服务;拿到代理后,Client 通过 Binder 驱动向 Server 发起调用;Server 执行后把结果沿原路返回。

一、四大角色的职责定位

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 驱动完成真正的跨进程传输。

Binder 四大角色协作关系 内核空间:Binder 驱动 /dev/binder · binder_proc · binder_node · binder_ref · 线程池 · 引用计数 · 死亡通知 数据拷贝 一次拷贝 mmap 线程调度 唤醒目标进程线程 权限与安全 UID/PID 校验 ServiceManager 服务名称 → Binder 引用 addService / getService handle = 0 Server 实现业务逻辑 BnInterface / onTransact 注册服务、等待请求 Client 查询服务并调用 BpInterface / transact 持有代理对象 查询 调用 注册 传输 注册/查询 典型调用链 Client → ServiceManager 查询 → 获得 BpBinder → Binder 驱动转发 → Server onTransact → 返回结果

三、一次完整调用的方法流程

以 Client 调用某个系统服务为例,整个过程可以拆解为“注册、查询、调用、返回”四个阶段。每个阶段都依赖 Binder 驱动完成跨进程边界的数据传递。

  1. Server 注册服务:Server 进程启动后创建 BBinder 对象,通过 IServiceManager::addService 把服务名称和 Binder 引用交给 ServiceManager。ServiceManager 记录名称与 handle 的映射关系。
  2. Client 查询服务:Client 调用 getService("xxx"),请求先到达 ServiceManager。ServiceManager 返回一个 BpBinder 代理,Client 侧通常再封装成 BpInterface。
  3. Client 发起调用:Client 调用代理对象的 transact(),数据被写入 Parcel,经 Binder 驱动拷贝到内核缓冲区,再投递到 Server 进程。
  4. Server 处理请求:Server 的 Binder 线程被唤醒,调用 onTransact() 解析 code 和 data,执行真实业务逻辑,并把结果写回 reply。
  5. 结果返回: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 驱动屏蔽。

ServiceManager 本身也是一个 Binder 服务,它的 handle 固定为 0。Client 在查询其他服务之前,必须先通过 handle 0 找到 ServiceManager,这是 Binder 体系能够启动起来的关键前提。

五、常见误区与复盘

  • 误区一:Client 直接连接 Server。实际上 Client 只持有 Server 的代理,真正传输由 Binder 驱动完成,Client 与 Server 之间没有直接的文件描述符或 socket。
  • 误区二:ServiceManager 负责业务逻辑。ServiceManager 只做名称与引用的映射,不参与具体业务处理,也不转发调用数据。
  • 误区三:Binder 驱动只是“搬运工”。驱动还负责线程池管理、引用计数、死亡通知和权限校验,是 Binder 安全性和稳定性的核心。
  • 误区四:一个进程只能扮演一种角色。system_server 既注册大量服务作为 Server,也会作为 Client 调用其他服务,角色是动态的。
排障提示:如果 getService 返回 NULL,优先检查服务是否已注册、ServiceManager 是否正常运行、SELinux 策略是否允许该 Client 访问目标服务。不要一上来就怀疑 Binder 驱动故障。

掌握这四大角色及其协作关系,是后续理解 Binder 驱动源码、AIDL 生成代码、ServiceManager 启动流程以及 Binder 性能优化的基础。只有先看清“谁在注册、谁在查询、谁在传输、谁在处理”,才能在遇到跨进程调用问题时快速定位到正确的层次。