4. 服务端实现:创建Binder实体、注册到 ServiceManager、启动 Service
4.1 原理概述
在 Binder 通信体系中,服务端是提供具体功能的进程。服务端至少需要完成三个核心动作:
- 创建 Binder 实体:实现一个继承自
BnInterface<INTERFACE>的类,重写onTransact()方法,用于处理客户端发来的调用请求。 - 注册到 ServiceManager:将 Binder 实体的句柄以服务名登记到系统全局的 ServiceManager 中,使客户端能够通过服务名找到该服务。
- 启动 Service 线程池:调用
ProcessState::self()->startThreadPool()并进入IPCThreadState::self()->joinThreadPool(),使服务端进程持续监听和处理 Binder 驱动传来的事务。
关键关系:Binder 实体是服务端的“门面”,ServiceManager 是注册中心,Binder 驱动是传输通道,三者缺一不可。
4.2 实现流程(三步法)
| 步骤 | 职责 | 核心 API / 类 |
|---|---|---|
| 1. 创建 Binder 实体 | 定义服务端业务逻辑,重写 onTransact() | BnInterface<IMyService>, status_t onTransact() |
| 2. 注册到 ServiceManager | 将实体以服务名发布到全局注册表 | defaultServiceManager()->addService() |
| 3. 启动 Binder 线程池 | 使服务端进程进入监听循环 | ProcessState::self()->startThreadPool(), IPCThreadState::self()->joinThreadPool() |
4.3 代码实现(C++ 示例)
以下代码演示一个简单的“计算服务”MyService 的完整服务端实现。
4.3.1 头文件与接口定义
// IMyService.h
#include <binder/IInterface.h>
#include <binder/Parcel.h>
namespace android {
class IMyService : public IInterface {
public:
DECLARE_META_INTERFACE(MyService); // 生成描述符和 asInterface
virtual int add(int a, int b) = 0;
};
// BnInterface 模板类为服务端提供骨架
class BnMyService : public BnInterface<IMyService> {
public:
virtual status_t onTransact(uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
} // namespace android
4.3.2 服务端实体实现
// MyService.cpp
#include "IMyService.h"
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
namespace android {
status_t BnMyService::onTransact(uint32_t code,
const Parcel& data,
Parcel* reply, uint32_t flags) {
switch (code) {
case 0: { // 自定义命令码:add
CHECK_INTERFACE(IMyService, data, reply);
int a = data.readInt32();
int b = data.readInt32();
int result = a + b;
reply->writeInt32(result);
return NO_ERROR;
}
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
int main(int argc __unused, char** argv __unused) {
// 1. 创建 Binder 实体(此处直接实例化 BnMyService)
sp<BnMyService> service = new BnMyService();
// 2. 注册到 ServiceManager(服务名 "my_calc_service")
defaultServiceManager()->addService(
String16("my_calc_service"), service);
ALOGI("MyService is registered and starting thread pool...");
// 3. 启动 Binder 线程池
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
} // namespace android
关键检查点:
addService() 的第二个参数必须是 sp<IBinder> 类型,通常传入 BnInterface 派生类实例。如果忘记调用 startThreadPool(),服务端进程将不会应答任何 Binder 调用。
4.4 服务端创建、注册、启动流程图
4.5 调试与验证
- 使用
adb shell dumpsys service my_calc_service查看服务是否已被 ServiceManager 记录。 - 在服务端进程日志中搜索
MyService is registered确认注册完成。 - 检查 Binder 线程池数量:
adb shell service list | grep my_calc_service。
4.6 常见错误
| 错误现象 | 根本原因 | 解决方法 |
|---|---|---|
添加服务时返回 ALREADY_EXISTS | 服务名已被其他进程注册 | 更换唯一服务名 |
客户端无法获取服务(nullptr) | 服务端未调用 addService() 或未进入线程池 | 确认 startThreadPool() 和 joinThreadPool() 已执行 |
onTransact() 返回 UNKNOWN_TRANSACTION | 命令码未处理或 CHECK_INTERFACE 缺失 | 确保 switch 覆盖所有命令码,且包含 CHECK_INTERFACE 宏 |
4.7 性能与稳定性优化
- 多线程并发:Binder 线程池默认最大线程数 16,可通过
ProcessState::self()->setThreadPoolMaxThreadCount()调整。 - 避免阻塞 onTransact:长时间耗时操作应异步处理,否则会降低其他客户端请求的响应速度。
- 服务保活:如果服务端进程意外死亡,注册的服务会自动注销。使用
registerService的回调或监听IServiceManager::onServiceDied做重连。 - 内存管理:Binder 实体使用
sp智能指针管理,防止循环引用导致泄露。
稳定性红线:切勿在
onTransact() 中直接执行死循环或无限等待,否则会耗尽 Binder 线程池,造成系统级 Binder 饿死。