2、ServiceManager角色:ServiceManager作为DNS服务的作用、注册服务与获取服务的流程、servicemanager进程分析
2.1 ServiceManager:Binder世界的DNS
在Android Binder通信架构中,ServiceManager(简称SM)扮演着“服务注册中心”与“服务查询中心”的双重角色。它类似于互联网中的DNS(域名系统),将服务名称(字符串)映射到具体的Binder引用(句柄)。
任何Binder服务(如ActivityManagerService、WindowManagerService)在启动后,必须先在ServiceManager中注册自己的名称;客户端进程在调用服务前,也必须先向ServiceManager查询该名称对应的Binder代理。没有ServiceManager,客户端将无法动态发现服务,整个系统服务调用链路将断裂。
核心概念: ServiceManager本身也是一个Binder服务,其句柄固定为0。任何进程都可以通过句柄0向SM发送注册或查询请求。
调试启示: 当使用
dumpsys 或 service list 命令时,底层实际上就是通过Binder向ServiceManager发起 LIST_SERVICES 请求。如果SM进程异常或响应超时,dumpsys 将直接失败。
2.2 注册服务流程(addService)
服务端进程(如 system_server)在初始化某个系统服务后,会调用 ServiceManager.addService() 将服务注册到SM。该流程涉及一次完整的Binder跨进程调用。
2.2.1 注册步骤
- 服务端发起: 服务端通过
BinderInternal.getContext().getServiceManager()获取SM代理,调用addService(name, binder)。 - Binder驱动转发: 驱动识别目标句柄为0(SM),将请求数据包转发给
servicemanager进程。 - SM处理:
servicemanager进程的svcmgr_handler函数解析请求,将服务名与Binder引用存入内部红黑树(svclist)。 - 返回确认: SM向服务端返回
NO_ERROR,注册完成。
2.2.2 注册流程关键数据结构
| 数据结构 | 类型 | 说明 |
|---|---|---|
svclist |
红黑树(内核态) | 存储服务名到Binder引用的映射,支持快速查找 |
handle |
int32 | Binder驱动为每个注册服务分配的句柄值,客户端通过句柄访问服务 |
Binder节点 |
binder_node | 驱动内核中代表服务端Binder对象的节点,包含引用计数与死亡通知 |
调试陷阱: 如果服务端重复注册同名服务,SM会覆盖旧条目。使用
dumpsys service list 时,同名服务只会显示最后一次注册的句柄。这在热修复或服务重启场景中容易引发混淆。
2.3 获取服务流程(getService)
客户端进程在需要调用某个系统服务时,会调用 ServiceManager.getService(name) 获取服务的Binder代理。该流程同样经过Binder驱动转发到SM查询。
2.3.1 获取步骤
- 客户端发起: 客户端通过SM代理调用
getService(name),传入服务名称字符串。 - Binder驱动转发: 驱动将请求发送给
servicemanager进程(句柄0)。 - SM查询: SM在
svclist中根据名称查找对应的Binder引用。如果找到,返回该服务的句柄值;如果未找到,返回NULL句柄。 - 客户端获取代理: 客户端根据返回的句柄,在本地创建
BinderProxy对象,后续通过该代理直接与服务端通信。
2.3.2 获取服务 vs 注册服务对比
| 对比维度 | 注册服务(addService) | 获取服务(getService) |
|---|---|---|
| 发起方 | 服务端进程 | 客户端进程 |
| SM操作 | 插入/更新 svclist | 查询 svclist |
| 返回数据 | 状态码(NO_ERROR) | Binder句柄(或NULL) |
| 阻塞行为 | 同步阻塞直到完成 | 同步阻塞直到完成 |
| 常见失败 | 服务名冲突、SM进程死亡 | 服务未注册、SM进程死亡 |
调试技巧: 使用
dumpsys service list 可以查看当前SM中注册的所有服务。如果某个服务未出现在列表中,客户端调用 getService 将返回NULL,导致空指针异常。这是分析“服务未启动”类问题的快速方法。
2.4 servicemanager 进程分析
servicemanager 是Android系统中一个独立的Native进程,可执行文件路径为 /system/bin/servicemanager。它由init进程启动,是系统中最核心的守护进程之一。
2.4.1 进程基本信息
| 属性 | 值 |
|---|---|
| 进程名 | servicemanager |
| 可执行文件 | /system/bin/servicemanager |
| 启动方式 | init.rc 中 service servicemanager /system/bin/servicemanager |
| 用户/组 | system / system |
| Binder句柄 | 固定为 0(所有进程默认知晓) |
| 核心循环 | binder_loop() 等待并处理Binder请求 |
2.4.2 进程内部架构
servicemanager 进程的代码位于 frameworks/native/cmds/servicemanager/,核心逻辑围绕 binder.c 和 service_manager.c 展开。其主循环如下:
// service_manager.c 核心逻辑简化
int main(int argc, char** argv) {
struct binder_state *bs;
bs = binder_open(128*1024); // 打开Binder设备,映射128KB内存
binder_become_context_manager(bs); // 成为上下文管理器(句柄0)
svcmgr_handle = BINDER_SERVICE_MANAGER;
binder_loop(bs, svcmgr_handler); // 进入循环,处理请求
return 0;
}
// 请求处理回调
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply) {
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
// 查询服务逻辑
break;
case SVC_MGR_ADD_SERVICE:
// 注册服务逻辑
break;
case SVC_MGR_LIST_SERVICES:
// 列出所有服务(dumpsys service list 底层调用)
break;
}
return 0;
}
2.4.3 进程调试方法
- 查看进程状态:
ps -A | grep servicemanager确认进程是否存活。 - 查看Binder信息:
dumpsys service list列出所有注册服务;dumpsys service <name>查看具体服务状态。 - 查看Binder驱动节点:
ls -l /sys/kernel/debug/binder/proc/查看各进程Binder信息,servicemanager的PID对应目录可查看其Binder节点状态。 - 日志分析:
logcat -s ServiceManager查看SM输出的日志,包括服务注册与查询记录。
调试陷阱: 如果
servicemanager 进程崩溃,所有Binder服务将无法注册和查询,系统会陷入严重异常。此时 dumpsys 命令会报错 "ServiceManager is not responding"。重启 servicemanager 后,所有服务需要重新注册,系统服务可能需重启才能恢复。
2.5 本章小结
- ServiceManager 是Binder通信的“DNS服务器”,通过固定句柄0被所有进程访问。
- 注册服务(addService) 将服务名与Binder引用存入SM的红黑树;获取服务(getService) 根据名称查询并返回句柄。
- servicemanager 进程是一个轻量级Native守护进程,核心是
binder_loop()与svcmgr_handler()回调。 - 调试时,
dumpsys service list是查看SM状态的直接手段;SM进程异常将导致整个系统服务不可用。