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 服务端创建、注册、启动流程图

服务端创建Binder实体、注册、启动流程图 1. 创建Binder实体 实现 onTransact() 业务逻辑 实例化 Service 对象 2. addService("name", service) 3. startThreadPool() 4. joinThreadPool() 进入循环 注意点 Binder实体必须继承 BnInterface<T> 并实现 onTransact() 常见陷阱 addService 后未调用 startThreadPool() 服务端将不会响应

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 饿死。