Binder 机制
问题
Android Binder 机制的原理是什么?为什么选择 Binder 而不是传统 Linux IPC?
答案
为什么选择 Binder
| 特性 | 共享内存 | Socket | 管道 | Binder |
|---|---|---|---|---|
| 拷贝次数 | 0 次 | 2 次 | 2 次 | 1 次 |
| 安全性 | 低(无身份验证) | 低 | 低 | 高(UID/PID) |
| C/S 架构 | ❌ | ✅ | ❌ | ✅ |
| 易用性 | 复杂(同步控制) | 中等 | 简单 | 好(AIDL 自动生成) |
Binder 在性能(一次拷贝)和安全性(内核验证调用方身份)之间取得了最佳平衡。
Binder 通信原理
一次拷贝的关键:mmap
传统 IPC(如 Socket)需要两次拷贝:
- 发送方用户空间 → 内核空间
- 内核空间 → 接收方用户空间
Binder 通过 mmap(内存映射)将接收方的用户空间和内核缓冲区映射到同一块物理内存。因此只需一次拷贝(从发送方到内核缓冲区),接收方直接读取映射的内存即可。
Binder 架构
- ServiceManager:Binder 的"DNS",管理所有注册的服务
- Proxy(客户端代理):将调用参数打包为 Parcel,通过 Binder 驱动发送
- Stub(服务端存根):从 Parcel 解包参数,调用真正的业务方法
Android 中的 Binder 应用
startActivity()→ AMS(ActivityManagerService)通过 BindergetSystemService()→ 各种系统服务通过 Binder- ContentProvider 底层通过 Binder 跨进程传输数据
- AIDL 是 Binder 的上层封装
常见面试问题
Q1: Binder 传输数据有大小限制吗?
答案:
有。Binder 事务缓冲区默认大小为 1MB(所有正在进行的事务共享,非单个事务独占)。传输大数据时会抛出 TransactionTooLargeException。大数据应通过文件、ContentProvider 或 共享内存(MemoryFile / SharedMemory)传输。
Q2: Binder 如何保证安全性?
答案:
Binder 驱动在内核中为每次通信附加调用方的 UID 和 PID,这些信息由内核填充,调用方无法伪造。服务端通过 Binder.getCallingUid() 和 Binder.getCallingPid() 获取调用方身份,进行权限验证。这比 Socket 等需要应用层自行验证身份的方式安全得多。
Q3: Binder 调用是同步还是异步?
答案:
默认是同步的——Client 调用后会阻塞等待 Server 返回。可以通过 AIDL 中声明 oneway 关键字使调用变为异步(Client 发送后立即返回,不等待 Server 处理完成)。