一、为什么 Android 使用 Binder?

Android 系统出于安全性稳定性的考虑,为每个应用分配独立的进程和虚拟机实例。这样做的好处是,即使某个应用崩溃,也不会直接影响到其他应用或系统本身。但随之而来的问题是:不同进程间内存空间隔离,数据无法直接共享

然而,跨进程通信又是必不可少的。典型场景包括:

  • 应用调用系统服务:这些核心服务都运行在独立进程中,应用必须通过跨进程调用才能使用。

    • ActivityManagerService(AMS):负责四大组件的调度与生命周期管理,例如启动 Activity、切换任务栈等。

    • WindowManagerService(WMS):负责窗口的管理与显示,应用界面要显示到屏幕上,必须通过它。

    • PackageManagerService(PMS):负责安装、卸载和查询应用信息。

  • 应用内部跨进程交互:例如音乐播放器的播放服务通常运行在独立进程中,前台 UI 进程需要与后台播放进程交互。

  • 应用与系统 API 的交互:如位置服务、通知服务、传感器服务等,应用需要通过 IPC 请求底层系统能力。

Android 最终选择自研 Binder IPC 机制,而没有直接使用 Linux 的传统 IPC(Socket、管道、共享内存等),原因有三点:

  1. 性能更高:Binder 只需要 一次内存拷贝(用户态 → 内核态 → 目标进程),相比于 Socket 或管道的多次拷贝更快。

  2. 安全性强:Binder 在通信过程中会携带调用方的 UID/PID,系统可以在服务端自动校验权限。

  3. 使用简单:系统提供了 AIDL、Service 等高层 API,开发者不必直接操作底层 IPC。

因此,Binder 成为了 Android 平台统一的 IPC 基石。

二、Binder 的整体架构

Binder 机制大致可以分为四个角色:

  1. Client:调用方,比如应用进程。

  2. Server:服务端,比如系统服务进程。

  3. ServiceManager:类似“电话簿”,负责服务的注册和查询。

  4. Binder 驱动:运行在内核态的 binder 驱动(/dev/binder),负责消息的传递与对象的引用管理。

工作流程:

  1. Server 注册服务:Server 创建自己的 Binder 实体(Binder 对象),并通过 Binder 驱动注册到 ServiceManager。

  2. Binder 驱动建立内核实体:Binder 驱动在内核空间创建该 Binder 实体的副本,因此有两个 Binder 实体:

    • 用户空间 Binder 实体:真正的服务实现。

    • 内核空间 Binder 实体:用于在不同进程之间传递引用。ServiceManager 持有该内核 Binder 实体的引用,以便分发给 Client。

  3. Client 获取服务代理:Client 向 ServiceManager 查询服务,拿到的其实是一个 Binder 代理对象(BpBinder)。该代理对象内部持有一个句柄(handle),指向内核中的 Binder 实体。

  4. Client 调用服务:Client 调用代理对象的方法时,实际上是将请求通过 ioctl 系统调用写入到 Binder 驱动。

    • Client 进程通过 ioctl 将请求写入 /dev/binder,驱动根据 handle 找到目标 Binder 实体。

    • 驱动将数据复制到目标 Server 的内核缓冲区,并唤醒 Server 进程中的 Binder 线程池。

    • Server 的某个 Binder 线程从驱动中读取请求(通过 ioctl),调用真正的服务对象方法,并将结果再写回驱动。

    • 驱动再将结果拷贝回 Client,完成一次跨进程调用。

三、Binder 的应用层接口

Android 提供了一套封装好的接口,让开发者不必直接操作底层。