Android 基于 Linux 内核,继承了 Linux 所有的 IPC 机制,同时引入了专用的 Binder 作为核心 IPC 框架。理解 Android 使用的各种 IPC 机制的差异、优劣和适用场景,是深入系统架构的必修课。
一、Android 中使用的 IPC 机制概览
| IPC 机制 | 是否主要 | 典型用途 | 数据拷贝次数 | 安全性 |
|---|---|---|---|---|
| Binder | 是 | 系统服务通信、四大组件调度 | 1 次 | 基于能力+UID 检查 |
| Unix Domain Socket | 是 | Zygote ↔ system_server, init, adbd | 2 次 | 基于 UID/GID |
| ashmem(匿名共享内存) | 是 | SurfaceFlinger, AudioFlinger | 0 次(映射后) | 基于 fd 传递 |
| 管道 (pipe) / 信号 (signal) | 辅助 | 进程同步、轻量通知 | 2 次 | 基于 fd |
| dma-buf / ION | 是 | 图形缓冲区、Camera | 0 次(硬件直接访问) | 基于 fd |
| SysV IPC / POSIX 消息队列 | 极少 | 无广泛使用 | 2 次 | 较弱 |
二、Binder——Android 的核心 IPC
2.1 为什么 Android 选择了 Binder?
Android 在设计之初评估了多种 IPC 方案,选择了 Binder 作为核心 IPC 而非传统 Linux IPC(如 Socket、管道、SysV)的原因:
1. 安全模型:Binder 天然支持基于能力的访问控制。每个 Binder 对象有唯一的标识(binder_node),不能伪造。配合 UID/PID 检查(IPCThreadState 在每次调用时自动传递调用者的 UID/PID),实现了细粒度的权限控制。相比之下,Socket/管道缺乏内置的身份传递机制。
2. 一次拷贝:通过 mmap 机制,Binder 将数据拷贝从两次减少为一次,提升了大数据量场景下的性能。
3. 对象引用计数:Binder 内置强/弱引用计数(通过 binder_node 的 internal_strong_refs / local_weak_refs 等字段),配合死亡通知机制,使得跨进程对象生命周期管理自动化。
4. 线程池管理:Binder 驱动管理服务端线程池(最多 15 个线程),自动根据负载请求创建或回收线程。
5. 同步语义(RPC 模型):Binder 天然支持同步调用(Client 阻塞等待 Server 回复),也支持异步的 oneway 调用。
2.2 Binder 通信流程回顾
Client 进程 Server 进程 |
用户空间库:frameworks/native/libs/binder/
三、Unix Domain Socket
3.1 在 Android 中的应用
Unix Domain Socket(UDS)是 Android 中第二重要的 IPC 机制,用于以下关键场景:
- init → Zygote:init 进程通过 socket 向 Zygote 发送 fork 请求
- adbd:ADB 守护进程使用 socket 与 system_server 和应用通信
- installd:PKMS 通过 socket 与 installd 守护进程通信执行 dexopt、数据目录创建等
- netd:网络管理守护进程
- keystore:密钥管理守护进程
3.2 Zygote 的 Socket 通信
// frameworks/base/core/java/android/os/ZygoteProcess.java |
3.3 install 的 Socket 通信
// frameworks/base/services/core/java/com/android/server/pm/Installer.java |
installd 守护进程路径:frameworks/native/cmds/installd/
Zygote 为什么用 Socket 而不是 Binder?因为 Binder 依赖 /dev/binder 设备,而 Zygote 在 fork 后通过 exec 执行具体应用时,需要关闭所有不必要的文件描述符。使用 Socket 可以在 fork 时更简单地进行 fd 管理。而且 Zygote 的通信模式是简单的 “请求-响应” 模式,Socket 完全足够。
四、共享内存机制
4.1 ashmem(Android Shared Memory)
ashmem 是 Android 对 Linux 共享内存的扩展,增加了引用计数和 pin/unpin 机制:
// system/core/libcutils/ashmem-dev.cpp |
应用场景:
- SurfaceFlinger:应用通过
GraphicBuffer(底层使用 ashmem)将渲染的帧传递给 SurfaceFlinger。 - AudioFlinger:音频数据缓冲区。
- ContentProvider 的 Cursor window:通过 ashmem 在 Provider 进程和 Client 进程间共享查询结果。
4.2 ION / dma-buf
ION 是 Android 为多媒体场景设计的内存分配器,dma-buf 是 Linux 标准的 DMA 缓冲区共享机制:
Camera HAL → ION buffer → Gralloc → SurfaceFlinger |
Android 11+ 逐步用标准的 Linux dma-buf 取代 ION。AOSP 路径:drivers/dma-buf/
4.3 共享内存协同 Binder 的优势
共享内存的典型使用模式是:
- 使用 ashmem 创建共享内存,获取 fd
- 通过 Binder 将 fd 传递给对端进程
- 对端进程通过 fd 做 mmap,直接访问同一块物理内存
- 数据读写不再经过 Binder 通道,零拷贝
这种模式结合了 Binder 的安全性和共享内存的高效性。
五、管道与信号(辅助 IPC)
5.1 管道
- Looper 的唤醒:addFd() 注册的管道 fd
- Zygote 的 USAP(Unspecialized App Process)Pool:使用管道同步
5.2 信号
- SIGCHLD:Zygote 监控子进程退出
- SIGQUIT:ANR trace 采集(
kill -3 <pid>触发线程 dump) - SIGSTOP / SIGCONT:进程的暂停和恢复
六、各 IPC 机制的性能对比
| IPC 机制 | 延迟 (小数据) | 吞吐 (大数据) | 内存开销 | 安全模型 |
|---|---|---|---|---|
| Binder | ~100us | ~50MB/s | 低(一次拷贝) | 能力+UID |
| Unix Domain Socket | ~200us | ~80MB/s | 高(两次拷贝) | UID/GID |
| ashmem (mmap) | 初始 ~1ms | ~无限(物理内存带宽) | 最低 | fd 传递 |
| SysV 消息队列 | ~150us | ~10MB/s | 中 | 弱 |
延迟数据仅供参考(取决于内核版本和硬件)。Binder 的综合性能在小到中等数据量场景(大多数系统服务调用)下最优,这也是 Android 选择它的重要原因。
七、核心面试题
Q1:为什么 Android 不用传统 Linux 的 SysV / POSIX IPC,而要单独设计 Binder?
主要有三点:(1) 安全:Binder 自动传递调用者 UID/PID,服务端可以通过 Binder.getCallingUid() 做权限检查;SysV IPC 依赖全局 key,容易冲突也容易被恶意进程猜测和利用。(2) 性能:Binder 的一次拷贝优于多数传统 IPC 的两次拷贝。(3) 生命周期管理:Binder 通过引用计数和死亡通知自动管理跨进程对象生命周期,传统 IPC 需要额外机制实现。
Q2:Zygote 为什么使用 Socket 而不是 Binder 来通信?
Zygote 的特殊性在于它 fork 子进程。fork 会复制父进程的文件描述符表。如果 Zygote 已经打开 /dev/binder 并通过 Binder 通信,那么 fork 出的每个子进程都继承了这些 Binder 相关的 fd 和 binder_proc 状态。这会导致混乱——子进程继承了 Zygote 的 Binder 身份。实际上,在 Zygote fork 和 exec 新进程之前,会关闭大部分不需要的 fd。Socket 在此场景下更简单:对端明确(只有 system_server 中的 ZygoteProcess),通信模型简单(发送 fork 请求,等待返回 PID),不需要复杂的能力模型。
Q3:ashmem 的 pin/unpin 机制有什么作用?和普通的 POSIX shm(如 shmget/shm_open)有什么区别?
ashmem 的 pin/unpin 是 Android 特有的内存管理功能。当系统内存紧张时,内核可以 “回收” unpin 的 ashmem 页面(将其内容丢弃),这在 SurfaceFlinger 的 BufferQueue 中非常有用——当 Buffer 已经被消费且不再需要时,可以 unpin 让内核回收内存。POSIX 标准 shm 缺乏这种 fine-grained 控制,分配后会一直占用物理内存直到进程退出或显式释放。
AOSP 核心路径参考:
frameworks/native/libs/binder/— Binder 用户空间库system/core/libcutils/ashmem-dev.cpp— ashmem 封装frameworks/base/core/java/android/os/ZygoteProcess.java— Zygote Socket 通信frameworks/native/cmds/installd/— installd 守护进程system/core/adb/— ADB 守护进程




