一、原理篇
1. 什么是 Android Binder?
Binder 是 Android 的跨进程通信(IPC)机制,用于不同进程(如 App 与系统服务)之间的数据传递和方法调用。它通过内核驱动实现高效通信。
2. Binder 如何实现进程间通信?
- 用户态与内核态协作:Binder 驱动在内核中管理通信逻辑。
- 内存映射(mmap):客户端与服务端共享一块内核内存,数据只需一次拷贝。
- 线程池与事务队列:Binder 驱动通过线程池处理并发请求,事务队列保证顺序。
3. 为什么 Android 选择 Binder?
- 性能高效:传统 IPC(如 Socket、管道)需 2 次数据拷贝,Binder 仅 1 次。
- 安全可控:基于 UID/PID 验证身份,避免恶意进程冒充。
- 面向对象:支持远程方法调用(RPC),开发者体验更友好。
4. Binder 如何实现一次拷贝?
-
内存映射技术(mmap):
- 客户端将数据写入共享内存(用户空间 → 内核空间)。
- 服务端直接读取内核内存(无需二次拷贝)。
这是 Binder 性能优于 Socket 的核心原因。
5. Binder 的优势是什么?
- 高效(一次拷贝、线程池优化)。
- 安全(身份验证、权限控制)。
- 易用(自动生成代理类,如 AIDL)。
- 轻量(内核驱动无复杂协议)。
二、流程篇
1. 从 ServiceManager 获取服务的流程
- 客户端调用
getService("service_name")。 - Binder 驱动将请求转发给 ServiceManager(SM 是特殊 Binder 服务)。
- SM 查表返回目标服务的 Binder 引用(handle)。
- 客户端通过该引用直接调用目标服务。
2. 如何找到目标服务并唤醒进程?
- Binder 引用表:每个进程维护一张
binder_ref表,通过 handle 找到目标服务的内存地址。 - 唤醒机制:若目标进程的 Binder 线程池空闲,驱动会唤醒线程处理请求。
3. Proxy 和 Stub 是什么?
- Proxy(代理):客户端侧的接口实现(如
IMyService.Stub.Proxy),负责打包数据(序列化)并发送给 Binder 驱动。 - Stub(存根):服务端侧的抽象类(如
IMyService.Stub),负责解包数据(反序列化)并调用实际方法。
4. 如何获取/添加 Binder 服务?
- 获取服务:通过
ServiceManager.getService()或bindService()。 - 添加服务:继承
Service并实现onBind(),返回自定义的IBinder对象。
5. AIDL 是什么?如何使用?
-
AIDL(Android Interface Definition Language):用于定义跨进程接口的 DSL。
-
使用步骤:
- 定义
.aidl文件(接口方法)。 - 实现
Stub类(服务端)。 - 客户端通过
asInterface()获取 Proxy 对象。
- 定义
6. Binder 组件与工作流程
-
核心组件:
- Binder 驱动(内核)。
- ServiceManager(服务注册中心)。
- Proxy/Stub(客户端/服务端接口)。
-
工作流程:
- 客户端调用 Proxy → 数据序列化 → 驱动转发 → 服务端 Stub 反序列化 → 执行方法 → 返回结果。
三、细节篇
1. mmap 的原理
- 内存映射:将内核空间的一块内存映射到用户空间,用户直接读写该内存,无需系统调用(如
read/write)。 - Binder 中的应用:客户端和服务端共享同一块内存,避免数据多次拷贝。
2. Binder 传输数据最大限制
- 默认限制:1MB(实际值因 Android 版本而异)。
- 占满后果:抛出
TransactionTooLargeException,客户端崩溃。
3. Intent 传输数据限制
- 限制原因:Intent 底层依赖 Binder,受 1MB 限制。
- 解决方案:传递文件路径或 URI,而非大对象。
4. binder_proc 中的两个红黑树
- binder_refs:管理本进程对其他 Binder 对象的引用(通过 handle)。
- nodes:管理本进程提供的 Binder 实体(服务对象)。
5. APP 进程天生支持 Binder 的原理
- Zygote 预加载:APP 进程由 Zygote fork 生成,继承已初始化的 Binder 线程池和驱动连接。
6. AIDL 关键字作用
- in:数据从客户端→服务端(只读)。
- out:数据从服务端→客户端(可修改)。
- inout:双向传输。
- oneway:异步调用(不等待返回结果)。
7. 服务端抛出异常会 Crash 吗?
- 服务端异常:会触发
RemoteException,但服务端不会 Crash(由 Binder 线程捕获)。 - 客户端异常:收到
RemoteException(如DeadObjectException)。
8. DeadObjectException 含义
表示服务端进程已终止或 Binder 对象失效,客户端需重新绑定服务。
9. Binder 驱动加载步骤
- 初始化驱动数据结构(如
binder_proc、binder_thread)。 - 注册为字符设备(
/dev/binder)。 - 建立内存映射管理(
mmap)。 - 启动线程池处理事务。
10. 死亡通知机制
- 作用:感知服务端是否存活。
- 实现:客户端注册
DeathRecipient,驱动通过BR_DEAD_BINDER通知客户端。
11. bindService 与 Binder Server 的区别
- bindService:面向应用层的服务绑定(如
Service组件)。 - Binder Server:底层 Binder 服务的实现(如系统服务
ActivityManagerService)。
12. writeStrongBinder/readStrongBinder
- 作用:序列化/反序列化 Binder 对象。
- 原理:
writeStrongBinder将 Binder 对象转换为flat_binder_object结构体,驱动通过该结构重建引用。
13. Binder 线程数量限制
- 默认最多 15 个线程(不同版本可能不同)。
- 占满后果:新请求排队,可能导致 ANR(应用无响应)。
14. Binder 缓冲区释放时机
驱动在事务完成(客户端收到回复)后释放缓冲区。
15. 广播与 AIDL 传输 Bitmap 的区别
- 广播:通过 Intent 传输,受 1MB 限制。
- AIDL:可传递文件描述符(
ParcelFileDescriptor)或分块传输,规避大小限制。
16. 四大组件为何支持 Binder?
- 系统服务化:四大组件(如
ActivityManagerService)本身是 Binder 服务,通过 Binder 与 App 通信。
17. 四大组件中的两个 Binder 服务
- ActivityManagerService:管理 Activity 生命周期。
- WindowManagerService:管理窗口和界面。
18. Binder 主要协议
- BC_:Binder Command(客户端→驱动),如
BC_TRANSACTION。 - BR_:Binder Return(驱动→客户端),如
BR_REPLY。
19. BC_ 与 BR_ 的区别
- BC_:客户端发送的指令(如发起事务)。
- BR_:驱动返回的响应(如事务结果)。
20. 如何感知对端存活?
-
A 感知 B:通过
DeathRecipient注册死亡通知。 -
B 感知 A:Binder 不原生支持,需自定义心跳机制(如定期
ping)。 -
对端死亡处理:
- A 死亡:B 释放相关资源。
- B 死亡:A 收到
DeadObjectException,重新绑定服务。
四、实践篇
1. Binder 相关问题案例
- TransactionTooLargeException:优化数据分块或传递文件描述符。
- Binder 线程池占满:检查服务端是否阻塞主线程,优化异步处理。
- DeadObjectException:增加重试逻辑或重新绑定服务。
2. Binder 的稳定性
-
内核级优化:Binder 驱动经过多年迭代,极少崩溃。
-
常见问题场景:
- 数据序列化错误(如 Parcel 写入顺序错误)。
- 跨进程传递不可序列化对象(如
Bitmap未实现Parcelable)