2. 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 将直接失败。
ServiceManager 在 Binder 架构中的位置 服务端进程 (如 system_server) 客户端进程 (如应用进程) ServiceManager (句柄 0) ① 注册服务(addService) ② 查询服务(getService) ③ 直接 Binder 调用 说明:ServiceManager 是 Binder 通信的“起点”,所有进程通过固定句柄 0 访问它。注册与查询完成后,客户端与服务端直接通信,不再经过 SM。

2.2 注册服务流程(addService)

服务端进程(如 system_server)在初始化某个系统服务后,会调用 ServiceManager.addService() 将服务注册到SM。该流程涉及一次完整的Binder跨进程调用。

2.2.1 注册步骤

  1. 服务端发起: 服务端通过 BinderInternal.getContext().getServiceManager() 获取SM代理,调用 addService(name, binder)。
  2. Binder驱动转发: 驱动识别目标句柄为0(SM),将请求数据包转发给 servicemanager 进程。
  3. SM处理: servicemanager 进程的 svcmgr_handler 函数解析请求,将服务名与Binder引用存入内部红黑树(svclist)。
  4. 返回确认: SM向服务端返回 NO_ERROR,注册完成。

2.2.2 注册流程关键数据结构

数据结构 类型 说明
svclist 红黑树(内核态) 存储服务名到Binder引用的映射,支持快速查找
handle int32 Binder驱动为每个注册服务分配的句柄值,客户端通过句柄访问服务
Binder节点 binder_node 驱动内核中代表服务端Binder对象的节点,包含引用计数与死亡通知
调试陷阱: 如果服务端重复注册同名服务,SM会覆盖旧条目。使用 dumpsys service list 时,同名服务只会显示最后一次注册的句柄。这在热修复或服务重启场景中容易引发混淆。
注册服务(addService)完整流程 服务端进程 Binder驱动 ServiceManager 1. addService(name, binder) 2. 转发到句柄0 SM内部处理 svcmgr_handler() 解析服务名 存入 svclist 红黑树 3. 处理请求 4. 返回 NO_ERROR 关键点:注册过程是同步Binder调用,服务端会阻塞直到SM返回。如果SM进程卡死,所有服务注册都将超时。

2.3 获取服务流程(getService)

客户端进程在需要调用某个系统服务时,会调用 ServiceManager.getService(name) 获取服务的Binder代理。该流程同样经过Binder驱动转发到SM查询。

2.3.1 获取步骤

  1. 客户端发起: 客户端通过SM代理调用 getService(name),传入服务名称字符串。
  2. Binder驱动转发: 驱动将请求发送给 servicemanager 进程(句柄0)。
  3. SM查询: SM在 svclist 中根据名称查找对应的Binder引用。如果找到,返回该服务的句柄值;如果未找到,返回 NULL 句柄。
  4. 客户端获取代理: 客户端根据返回的句柄,在本地创建 BinderProxy 对象,后续通过该代理直接与服务端通信。

2.3.2 获取服务 vs 注册服务对比

对比维度 注册服务(addService) 获取服务(getService)
发起方 服务端进程 客户端进程
SM操作 插入/更新 svclist 查询 svclist
返回数据 状态码(NO_ERROR) Binder句柄(或NULL)
阻塞行为 同步阻塞直到完成 同步阻塞直到完成
常见失败 服务名冲突、SM进程死亡 服务未注册、SM进程死亡
调试技巧: 使用 dumpsys service list 可以查看当前SM中注册的所有服务。如果某个服务未出现在列表中,客户端调用 getService 将返回NULL,导致空指针异常。这是分析“服务未启动”类问题的快速方法。
获取服务(getService)完整流程 客户端进程 Binder驱动 ServiceManager 1. getService(name) 2. 转发到句柄0 SM内部处理 svcmgr_handler() 在 svclist 中查找 返回句柄或NULL 3. 查询服务 4. 返回 Binder 句柄(或 NULL) 客户端创建代理 BinderProxy(handle) 5. 创建代理 关键点:getService 返回的句柄是Binder驱动分配的整数值,客户端通过该句柄后续直接与服务端通信,不再经过SM。

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 后,所有服务需要重新注册,系统服务可能需重启才能恢复。
servicemanager 进程内部架构 servicemanager 进程 binder_loop() 主循环等待请求 svcmgr_handler() 请求分发回调 addService 注册服务 getService 查询服务 listServices 列出服务 底层数据存储:svclist 红黑树(服务名 → Binder 引用)

2.5 本章小结

  • ServiceManager 是Binder通信的“DNS服务器”,通过固定句柄0被所有进程访问。
  • 注册服务(addService) 将服务名与Binder引用存入SM的红黑树;获取服务(getService) 根据名称查询并返回句柄。
  • servicemanager 进程是一个轻量级Native守护进程,核心是 binder_loop() 与 svcmgr_handler() 回调。
  • 调试时,dumpsys service list 是查看SM状态的直接手段;SM进程异常将导致整个系统服务不可用。