[ English | 简体中文 ]
Binder 进程间通信 (IPC) 开发指南
Binder 是一种高效的进程间通信 (IPC) 传输机制,允许不同进程之间进行数据交换和远程方法调用。
1. 核心架构
Binder 机制由以下四个核心组件构成:
- Binder 驱动程序:位于内核空间,负责处理进程间通信的底层细节,包括数据包传输和线程管理。
- ServiceManager:一个特殊的守护进程,充当上下文管理器,负责注册服务和查找 Binder 服务。
- Binder 服务端 (Server):实现具体的服务功能,并通过 Binder 机制响应来自其他进程的请求。
- Binder 客户端 (Client):使用服务的进程,通过 Binder 机制向服务端发送请求并接收响应。
2. 系统配置与启动
2.1 Kconfig 配置
在使用 Binder 之前,请确保开启以下基本配置:
CONFIG_DRIVERS_BINDER # 内核驱动开关
CONFIG_ANDROID_BINDER # Binder Lib 库开关
CONFIG_ANDROID_SERVICEMANAGER # Binder 守护进程
CONFIG_BINDER_EXAMPLES # Binder 示例开关
若使用 libuv 进行事件循环监听,需在开启 CONFIG_BINDER_EXAMPLES 后,额外使能:
CONFIG_LIBUV # 使能 libuv 支持
2.2 运行时启动
进行 Binder 通信前,必须先启动 ServiceManager 守护进程:
nsh> servicemanager &
3. 工作原理
Binder 的通信流程如下:
- 开发者通过 AIDL 文件定义通信接口。
- 服务端实现该接口,并将服务注册到 ServiceManager。
- 客户端向 ServiceManager 查询特定服务名,获取服务端的 Binder 对象引用。
- 客户端调用预定义的接口方法。AIDL 生成的代理代码与 Binder 库将参数序列化,并将请求写入内核驱动。
- Binder 驱动将客户端请求转发至服务端。
- 服务端接收请求,执行具体操作,并将结果原路返回给客户端。
4. 接口定义 (AIDL)
AIDL (Android Interface Definition Language) 用于定义进程间通信接口,简化了跨进程的方法调用。
4.1 接口定义示例
创建一个简单的 AIDL 接口文件:
interface ITestStuff {
void write(int sample);
void read(int idx);
}
4.2 代码生成
AIDL 工具将根据上述定义生成以下 C++ 文件,包含客户端代理类 (Bp) 和服务端桩类 (Bn):
BnTestStuff.hBpTestStuff.hITestStuff.hITestStuff.cpp
5. 实现模式
根据应用场景的不同,Binder 服务端主要有三种实现模式。
模式一:基于 Binder 线程池 (标准模式)
此模式适用于标准的阻塞式服务调用。
1. 服务端实现
-
创建服务实例:继承 AIDL 生成的
Bn类并实现接口。sp<ITestServer> testServer = new ITestServer; -
定义接口方法:
Status read(int32_t sample) { /* 实现逻辑 */ } Status write(int32_t index) { /* 实现逻辑 */ } -
注册服务:
sp<IServiceManager> sm(defaultServiceManager()); sm->addService(String16("aidldemo.service"), testServer); -
启动线程池:将当前线程加入 Binder 线程池处理请求。
ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool();
2. 客户端实现
-
获取服务:
sp<IServiceManager> sm(defaultServiceManager()); sp<IBinder> binder = sm->getService(String16("aidldemo.service")); -
转换代理接口:
sp<ITestStuff> service = interface_cast<ITestStuff>(binder); -
调用接口:
service->write(123); service->read(456);
模式二:基于 Libuv 主循环 (异步事件驱动)
此模式适用于需要集成到 libuv 事件循环的应用。
1. 服务端实现
-
创建并注册服务:
sp<ILibuvServer> testServer = new ILibuvServer; // ... 实现接口并注册到 ServiceManager (同模式一) ... -
配置 Binder 轮询:获取 Binder 驱动的文件描述符 (FD)。
IPCThreadState::self()->setupPolling(&fd); -
初始化 Libuv 句柄:
uv_poll_init(uv_default_loop(), &binder_handle, fd); -
启动监听:当 FD 可读时触发回调
uv_binder_cb,处理消息队列。uv_poll_start(&binder_handle, UV_READABLE, uv_binder_cb); -
运行事件循环:
uv_run(uv_default_loop(), UV_RUN_DEFAULT); -
资源释放:
uv_close((uv_handle_t*)&binder_handle, NULL); IPCThreadState::self()->stopProcess();
2. 客户端实现
请参考模式一。
模式三:基于 Epoll 主循环 (原生 Linux 事件驱动)
此模式适用于使用原生 epoll 机制管理事件的应用。
1. 服务端实现
-
创建并注册服务:
// 参考模式一创建 Bn 类实例并注册 -
创建 Epoll 实例:
int epoll_fd = epoll_create1(EPOLL_CLOEXEC); -
配置 Binder 轮询:
int fd; IPCThreadState::self()->setupPolling(&fd); -
注册 Epoll 事件:
struct epoll_event ev; ev.events = EPOLLIN; epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev); -
事件循环处理:
while (1) { struct epoll_event events[1]; int numEvents = epoll_wait(epoll_fd, events, 1, -1); if (numEvents < 0) { if (errno == EINTR) { continue; } break; } if (numEvents > 0 && (events[0].events & EPOLLIN)) { ALOGI("process binder transaction"); // 处理命令并刷新缓冲区 IPCThreadState::self()->handlePolledCommands(); IPCThreadState::self()->flushCommands(); // flush BC_FREE_BUFFER } }
2. 客户端实现
请参考模式一。