1. 引言
Android 系统基于 Binder 实现了"透明"的进程间通信。从应用调用系统服务(startActivity),到 Wi‑Fi 驱动向 WifiService 上报事件,再到硬件抽象层(HAL)与系统服务的数据交换,Binder 无处不在。因此,理解 Binder 及其上层封装,是 ROM 开发者进行系统定制、性能分析、功能扩展的必备能力。
Binder 本身是一个庞大的主题。本期"Framework 开发专题系列四"不深究内核驱动细节,而是聚焦于 Framework 中五种最常见的 Binder 应用形态,帮助你在阅读和修改源码时能够快速识别并选择最合适的 IPC 方式。
2. Binder 架构分层总览
Android 的 Binder 体系从下到上可分为三层:
内核层
硬件抽象层
Native 框架层
应用与框架层
AIDL
Java 接口定义
Messenger
Handler 信使
AsyncChannel
双向异步通道
Native Binder
libbinder C++ 接口
系统服务: AMS/WMS/...
HIDL
硬件接口定义语言
Binder 驱动 /dev/binder
- 内核 Binder 驱动 :提供基础 IPC 能力,管理跨进程的
transaction。 - Native Binder (
libbinder) :C++ 封装,提供BpBinder、BnBinder等核心类。 - Java Binder 框架 :通过 JNI 调用
libbinder,提供IBinder、Binder、BinderProxy等类。 - 上层 IPC 封装:为了让开发者更方便地使用 Binder,Android 提供了多种高级封装,例如 AIDL、Messenger、AsyncChannel;而在硬件抽象层,则使用 HIDL(正逐步向 AIDL 迁移)。
下文逐一剖析这五种形态。
3. AIDL ------ Java 层 IPC 标准姿势
AIDL(Android Interface Definition Language) 是 Android 官方推荐的跨进程接口定义语言,底层基于 Binder 实现。它允许开发者像定义普通接口一样声明远程服务的方法,由 aidl 编译器自动生成 Java 代理类和桩类。
3.1 基本使用流程
- 定义
.aidl文件,声明接口和方法。 - 在 Service 端实现
Stub抽象类。 - 在 Client 端通过
bindService获取Proxy对象并调用。
生成的代码中,Stub 继承自 Binder 并实现接口,Proxy 持有 IBinder 对象并使用 transact 发送请求。
3.2 AIDL 定向 tag
Android 10+ 的 AIDL 支持方法参数的定向标注:
in:数据从客户端流向服务端(可跨进程传递)。out:数据从服务端流回客户端(服务端修改后客户端可见)。inout:双向流动。
Framework 中大量系统服务接口都使用了这些标注以优化拷贝次数。
3.3 Stable AIDL(稳定 AIDL)
从 Android 10 开始,AIDL 支持声明为 stable,其接口被版本化管理,可像 SDK API 一样保证跨系统更新兼容。System 分区的 Framework 服务与 Vendor 分区的 HAL 实现之间的通信,正逐步从 HIDL 迁移到 Stable AIDL。
java
// 稳定 AIDL 接口声明
@VintfStability
interface IMyService {
int getValue();
}
4. Native Binder ------ C++ 世界中的原始力量
许多系统服务(如 SurfaceFlinger、media 相关服务)本身就是 Native 进程,它们使用 libbinder 提供的 C++ Binder 接口进行通信。
4.1 核心类架构
Server Side
Client Side
transact
onTransact
Client 进程
BpBinder
Binder 驱动
BBinder
Server 进程
BpRefBase
具体服务实现
BBinder:服务端桩,需重写onTransact方法处理请求。BpBinder:客户端代理,通过handle对象与驱动交互。BpRefBase:为代理提供引用计数。
4.2 Framework 实例:SurfaceFlinger
SurfaceFlinger 是一个独立的 Native 进程,其服务端继承自 BBinder,客户端通过 ISurfaceComposer 接口调用。以获取显示信息为例:
cpp
// 客户端调用
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
sf->getDisplayConfigs(displayToken, &configs);
内部通过 BpSurfaceComposer::transact 将请求序列化并发送给 Service 进程,BnSurfaceComposer::onTransact 解包并调用实际函数。
4.3 与 AIDL 的关系
实际上,AIDL 编译器生成的 Java 代码底层也是通过 JNI 调用 libbinder 的 transact 方法。而 C++ 服务同样可以使用 AIDL 来定义接口(C++ 后端),使得 Native 服务开发也具备接口标准化和版本管理能力。
5. HIDL ------ 硬件抽象层的接口定义语言
HIDL(HAL Interface Definition Language) 是 Android 8.0 引入的,用于定义 HAL 与 Framework 之间的接口。它的诞生源于 Project Treble,目的是将 HAL 实现放置在 Vendor 分区,与 System 分区的 Framework 完全解耦。
5.1 HIDL 架构
HIDL 调用
Binder IPC
应用
Framework 服务
HIDL 客户端存根
HIDL 服务端实现
HAL 硬件模块
HIDL 接口定义在 .hal 文件中,编译后自动生成 C++(或 Java)的客户端/服务端代码。服务端注册到 hwservicemanager,客户端通过 getService 获取代理。
5.2 常用 HIDL 接口示例
IComposer:显示屏合成接口ICameraProvider:相机服务接口ISensor:传感器接口
5.3 从 HIDL 到 AIDL 的迁移
Android 14 之后,Google 宣布 HIDL 已废弃,转而使用 Stable AIDL 来定义 HAL 接口。与 HIDL 相比,AIDL 的优势在于:
- 语法更简洁,生态系统更健全。
- 支持 C++ 和 Java,而 HIDL 主要面向 C++。
- 可直接复用上层 AIDL 工具链。
因此,作为 ROM 开发者在维护旧平台时仍需理解 HIDL,但在新平台中应优先使用 Stable AIDL。
6. AsyncChannel ------ 双向异步通信通道
AsyncChannel 是 Framework 内部使用的一套基于 Handler + Binder 的双向异步消息通道 。它允许两个实体(可能位于不同进程)互相发送消息,每个实体都有自己的 Handler 线程来接收和处理消息。
6.1 设计目的
普通 Service 通过 Binder 调用是同步的(客户端调用服务端方法后等待返回),但在系统中有些场景需要 异步、双向、无返回值 的通信,比如:
- Wi‑Fi 驱动状态变化需要实时告知
WifiService。 WifiService也需要向状态机发送控制命令。
AsyncChannel 就是为此而生。
6.2 连接模型
Server AsyncChannel Client Server AsyncChannel Client loop [双向消息传递] connect(context, handler, messenger) CMD_CHANNEL_HALF_CONNECTED sendReply(STATUS_SUCCESSFUL) CMD_CHANNEL_FULL_CONNECTION sendMessage(msg) msg 投递到 Server Handler sendMessage(msg) msg 投递到 Client Handler
建立连接后,双方都持有一个 AsyncChannel 对象,通过 sendMessage(msg) 发送 Message,对方的 Handler 会收到并处理。底层仍使用 Binder 进行跨进程传输,但所有细节被封装。
6.3 Framework 中的实际应用
WifiStateMachine 与 WifiService 之间即通过 AsyncChannel 通信:
WifiService的客户端(SystemUI、Settings)通过 Binder 调用WifiService暴露的 API。WifiStateMachine跑在WifiService所属进程中,WifiService使用AsyncChannel向状态机发送命令(如CMD_START_SCAN)。WifiStateMachine的状态变化则通过AsyncChannel异步通知到WifiService。
另一个典型应用是 Telephony 中的 RIL 与 Phone 之间的通信。
7. Messenger ------ 轻量级的 Handler 通信
Messenger 是一个基于 Binder 和 Handler 的轻量级 IPC 机制,适用于简单的单向或双向消息传递,不需要定义复杂的 AIDL 接口。
7.1 实现原理
Messenger 内部包含一个 Handler 引用,对外提供 IMessenger 接口(AIDL 定义):
java
// frameworks/base/core/java/android/os/Messenger.java
private final IMessenger mTarget;
public Messenger(Handler target) {
mTarget = new IMessengerImpl(target);
}
当客户端调用 Messenger.send(Message) 时,消息被序列化,通过 Binder 发送到服务端,服务端的 IMessengerImpl 收到后直接 handler.sendMessage()。
7.2 双向通信
两个进程各持有一个 Messenger 对象的话,即可实现双向通信。典型做法是在 Message.replyTo 中放置客户端自己的 Messenger,服务端收到后可向该 Messenger 回复消息。
7.3 应用场景
- 跨进程通知 :比如音乐播放服务通过
Messenger向客户端发送播放进度。 - 绑定服务:不想显式定义 AIDL 时的便利选择。
- Messenger 在 Framework 中常见于系统通知、
MediaRouter等组件。
与 AsyncChannel 的区别:
| 特性 | AsyncChannel | Messenger |
|---|---|---|
| 使用范围 | Framework 内部专用 | 应用层、Framework 均可 |
| 通信模式 | 全双工异步通道,自动管理连接确认 | 基于 Message 传递,需手动处理 replyTo |
| 底层 | 仍基于 Binder,但封装了完整的状态机 | 直接依赖 Binder(IMessenger.aidl) |
| 灵活性 | 功能强大,但使用复杂,未开放给应用 | 简单易用,轻量级 |
8. 五种 Binder 应用形态对比与选型指南
| 形态 | 层次 | 适用场景 | 主要优点 | 主要局限 |
|---|---|---|---|---|
| AIDL | Java / C++ | 系统服务接口、应用间 IPC | 类型安全、支持复杂对象、可版本化 | 需要定义接口,编译步骤多 |
| Native Binder | C++ (libbinder) | Native 服务(SurfaceFlinger等) | 性能极高,直接操作 C++ 对象 | 学习曲线陡,手动管理引用 |
| HIDL | HAL / Framework | 硬件抽象层接口(旧) | 与 Treble 架构融合,自动生成代码 | 语法独立,已废弃,迁移成本高 |
| AsyncChannel | Java Framework | 系统内部异步双向通道 | 双向异步,自动连接确认,Handler 驱动 | 未公开为 API,仅限 Framework |
| Messenger | Java | 简单的跨进程消息传递 | 无需 AIDL,快速开发,支持双向 | 不类型安全(Message.what),不适合复杂数据 |
选型建议:
- 对于体系化、需要多版本支持的新接口 ,优先选择 Stable AIDL。
- 在 Native 进程中,若已有成熟接口,可使用 Native Binder ;新设计应使用 AIDL C++ 后端。
- 对于 Framework 内部组件间的异步命令通信,使用 AsyncChannel(照搬已有模块模式)。
- 当只是传递简单的
Message且不想引入 AIDL 时,Messenger 是最佳选择。 - HIDL 仅维护旧平台,新平台应向 AIDL 迁移。
9. 总结与学习建议
Binder 是 Android 系统的"神经系统",掌握其上层封装比死磕驱动层更实用。建议 ROM 开发者按照以下路径学习:
- 从 AIDL 实操开始 :手写一个简单的 AIDL 服务,查看生成的代码,理解
Stub与Proxy的运行机制。 - 阅读 Framework 中的 Native Binder 服务 :从
SurfaceFlinger入手,跟踪一下createDisplay的 IPC 流程。 - 分析 AsyncChannel 典型用例 :打开
WifiStateMachine和WifiService,理解其双向通信机制。 - 关注 HIDL → AIDL 迁移:了解 Google 的最新架构演进方向,避免在新平台上走弯路。