Native服务注册实战
一个 Native Binder 服务至少要解决四件事:创建本地 BBinder 实现、通过 ServiceManager 发布名字、让进程具备消费 Binder 请求的线程、处理注册或线程配置失败。AOSP gpuservice 的 main_gpuservice.cpp 正好把这条最小主线集中在一个入口里。
本文面向已经读过 addService注册服务、ProcessState初始化、joinThreadPool 和 BnInterface与BpInterface模板 的读者。本文按真实 gpuservice 入口解释“服务如何从 C++ 对象变成可查询的 Binder 服务”,不提供脱离 AOSP 构建系统的伪造 demo,也不展开 GpuService 业务 API。
1. 构建入口
1.1 二进制模块
源码文件:frameworks/native/services/gpuservice/Android.bp
cc_binary {
name: "gpuservice",
init_rc: ["gpuservice.rc"],
srcs: [":gpuservice_binary_sources"],
static_libs: ["libgpuservice"],
shared_libs: ["libbinder", "libcutils", "liblog", "libutils"],
}cc_binary 把 main_gpuservice.cpp 编成可执行文件,并通过 init_rc 让 init 知道如何启动它;libgpuservice 只承载 GpuService.cpp 的实现。构建模块和 Binder 服务名是两套命名:二进制叫 gpuservice,ServiceManager 名称来自 GpuService::SERVICE_NAME。
1.2 rc边界
源码文件:frameworks/native/services/gpuservice/gpuservice.rc
rc 文件负责进程启动、用户/组、class 和重启策略;它不执行 addService(),也不替代 Binder 线程池。服务是否出现在 ServiceManager 表中,必须回到 C++ main 的注册调用。
2. 服务发布
2.1 本地对象
源码文件:frameworks/native/services/gpuservice/main_gpuservice.cpp
相关类型:GpuService
sp<GpuService> gpuservice = new GpuService();GpuService 是本进程拥有的 BBinder/接口实现。构造成功只说明 C++ 对象存在,其他进程还不能通过名字查询;必须把该对象交给 ServiceManager。
2.2 管理器代理
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(GpuService::SERVICE_NAME),
gpuservice, false);defaultServiceManager() 返回 native IServiceManager shim;addService() 经过前文的 AIDL backend 和 ServiceManager 服务端校验。第三个参数 false 表示 isolated caller 默认不能访问该服务;这里使用旧 C++ overload,dump priority 采用默认值。
3. 线程消费
3.1 上限设置
ProcessState::self()->setThreadPoolMaxThreadCount(4);这一步把 Binder 驱动可按需启动的线程上限设为 4,不会立即创建四个线程。ioctl 失败会返回负 status;示例 main 没有检查返回值,因此设备错误主要通过 libbinder 日志暴露,不能把这段代码描述成“确认线程池已配置成功”。
3.2 启动线程池
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
ps->giveThreadPoolName();
IPCThreadState::self()->joinThreadPool();startThreadPool() 创建一个 PoolThread;giveThreadPoolName() 设置当前调用线程的 Binder 风格线程名;joinThreadPool() 让 main 线程发送 BC_ENTER_LOOPER 并持续消费驱动命令。真正接收 GpuService 请求的是线程池消费路径,不是 addService() 调用线程本身。
3.3 永不返回
正常情况下 joinThreadPool() 进入循环,不返回到 main() 的 return 0。只有驱动关闭、fd 错误或其他退出路径才可能返回;因此 main 末尾的 return 不是服务成功运行的信号。
4. 失败路径
4.1 对象失败
GpuService 构造失败或内存不足时不会进入 addService();进程继续执行的前提已经破坏。源码样例没有显式 null 检查,因为 sp::make/new 和构造失败通常通过异常/致命路径处理,不能据此推导所有服务都自动处理构造错误。
4.2 注册失败
addService() 返回 status_t,示例没有检查返回值就继续配置线程池。若权限、名称、VINTF、Binder 或 ServiceManager 不可用,服务可能没有注册却仍进入 Binder 循环;这是一条真实代码的可观测风险,排查时应先查询服务名和查看 ServiceManager 日志。
4.3 线程失败
线程上限 ioctl 失败或 driver fd 无效时,startThreadPool()/joinThreadPool() 可能输出 warning、返回错误或进入 fd 失败退出。服务注册成功不等于服务具备可用的请求消费者。
5. 可执行复现
5.1 源码搜索
rg -n "GpuService|defaultServiceManager|addService|setThreadPoolMaxThreadCount|startThreadPool|joinThreadPool" \
frameworks/native/services/gpuservice/main_gpuservice.cpp \
frameworks/native/services/gpuservice/Android.bp \
frameworks/native/libs/binder/IServiceManager.cpp \
frameworks/native/libs/binder/ProcessState.cpp \
frameworks/native/libs/binder/IPCThreadState.cpp5.2 读者验证
沿 GpuService::SERVICE_NAME 找到注册名,再从 defaultServiceManager() 跟到 CppBackendShim::addService(),最后进入 ServiceManager::addService()。随后回答三个问题:如果注册失败,哪一层返回 status;如果线程上限设置失败,哪个调用者拥有错误;如果 joinThreadPool() 返回,服务进程的 Binder 消费者发生了什么。
5.3 测试边界
源码文件:frameworks/native/libs/binder/tests/binderLibTest.cpp
测试环境在 setup 中使用 defaultServiceManager() 获取服务并关闭 add-service cache,以便后续注册/查询反映真实 manager;ThreadPoolStarted 和 ThreadPoolAvailableThreads 验证线程池标志与近似线程数量。它们不是 gpuservice 的直接生产 main 测试,也不证明设备 init rc 和 GPU HAL 配置。
