7. ServiceManager 的启动:init 进程如何拉起 servicemanager 进程?

好,咱们今天聊聊 ServiceManager 是怎么被拉起来的。

很多人觉得 ServiceManager 就是个“服务大管家”,但很少有人关心它是什么时候、被谁、怎么启动的。我当年刚接触 Android 时,也以为它是系统启动后自动就有的。直到有一次我在调试一个早期开机阶段的 crash,发现 log 里报“无法获取 ServiceManager 代理”,才意识到——哦,原来它也是被一个进程拉起来的。

这个“拉它起来”的进程,就是 init。

7.1 init 进程的“启动清单”:.rc 文件

Android 系统启动后,内核会启动第一个用户空间进程——init。init 进程的职责之一,就是解析一系列 .rc 文件,然后根据里面的规则启动各种系统服务。

servicemanager 的启动规则,就写在 servicemanager.rc 里。这个文件通常位于 /system/core/servicemanager/ 目录下。

说白了,init 进程就像是一个“启动管家”,它手里拿着一张清单(.rc 文件),上面写着“什么时候、启动哪个服务、启动几次”。servicemanager 就是清单上最早被启动的那一批之一。

我们来看看这个 .rc 文件长什么样:

# /system/core/servicemanager/servicemanager.rc
service servicemanager /system/bin/servicemanager
    class core
    user system
    group system
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart audioserver
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart inputflinger
    onrestart restart drm
    onrestart restart cameraserver
    onrestart restart keystore
    onrestart restart gatekeeperd
    onrestart restart netd
    onrestart restart logd
    writepid /dev/cpuset/system-background/tasks

嗯,这里要注意几个关键字段:

  • service:声明一个服务,名字叫 servicemanager,可执行文件路径是 /system/bin/servicemanager
  • class core:表示它属于 core 类。init 进程启动时会按 class 分组启动,core 类是最早启动的那一批。
  • critical:这个标记很关键。表示如果 servicemanager 挂了,系统会直接重启。为什么?因为它是所有服务的“注册中心”,它一挂,整个系统就瘫痪了。
  • onrestart:当 servicemanager 重启时,会连带重启哪些服务。你看这个列表——zygote、media、surfaceflinger……几乎全是核心服务。我当年看到这个列表时,心里想的是:servicemanager 一挂,半个系统都得跟着陪葬。

我个人习惯在分析系统启动流程时,先看 .rc 文件。它就像一张“服务依赖图”,能帮你快速理清哪些服务是核心、哪些是附属。

7.2 init 拉起 servicemanager 的完整流程

init 进程解析完 .rc 文件后,会执行以下步骤:

  1. 解析 .rc 文件:init 读取 servicemanager.rc,将 servicemanager 服务注册到内部的服务列表中。
  2. 触发启动条件:当 init 进入 core class 启动阶段时,会遍历所有 class core 的服务,调用 service_start() 函数。
  3. fork 子进程:init 调用 fork() 创建一个子进程。子进程会执行 execve() 加载 /system/bin/servicemanager 这个可执行文件。
  4. 设置权限和 cgroup:init 会设置子进程的 user、group、以及 writepid 指定的 cgroup 路径。
  5. 监控子进程状态:init 会通过 SIGCHLD 信号监听 servicemanager 进程的退出。如果它挂了,init 会根据 critical 标记决定是否重启系统。

这个流程,说白了就是 init 进程“生”了一个子进程,然后让这个子进程去跑 servicemanager 的代码。子进程跑起来之后,init 就不管它具体干什么了,只负责“看它有没有死”。

我曾经在项目中遇到过一个问题:某款设备在开机时偶尔卡在“Android”logo 处。排查了很久,最后发现是 servicemanager 启动时因为 selinux 权限不足被 kill 了。init 检测到它挂了,但因为 critical 标记,系统直接重启——结果就是无限重启。所以,servicemanager 的 selinux 策略一定要配对,否则连开机都开不了。

7.3 servicemanager 启动后做了什么?

servicemanager 进程启动后,会立即做三件事:

  • 打开 Binder 驱动:调用 open("/dev/binder", O_RDWR),获取 Binder 设备的文件描述符。
  • 将自己注册为 Binder 上下文管理器:通过 ioctl(fd, BINDER_SET_CONTEXT_MGR, 0) 告诉 Binder 驱动:“我就是 ServiceManager,所有服务注册和查询都来找我。”
  • 进入循环等待:调用 binder_loop(),不断读取 Binder 驱动传来的消息,处理服务注册(ADD_SERVICE_TRANSACTION)和服务查询(CHECK_SERVICE_TRANSACTION)请求。

这里有个细节:servicemanager 本身不依赖其他任何服务。它只需要 Binder 驱动。所以它才能成为“第一个启动的服务”。

你想想看,如果 servicemanager 启动时还需要别的服务,那就成了“先有鸡还是先有蛋”的问题了。所以它必须是最纯粹的——只依赖内核的 Binder 驱动。

7.4 核心流程图:init 拉起 servicemanager

下面我用一张 SVG 图来展示这个流程。我个人习惯把这种“进程启动链”画成时序图,一目了然。

init 进程拉起 servicemanager 流程图 init 进程 servicemanager Binder 驱动 ① 解析 servicemanager.rc ② fork() 子进程 ③ execve() 加载 /system/bin/servicemanager ④ open("/dev/binder") ⑤ BINDER_SET_CONTEXT_MGR ⑥ binder_loop() 等待请求 ⑦ SIGCHLD 监控进程状态

7.5 避坑指南:servicemanager 启动常见问题

问题 原因 解决方案
servicemanager 启动失败 selinux 策略未配置,或 Binder 驱动未加载 检查 dmesglogcat,确认 selinux avc 权限
系统无限重启 servicemanager 被 critical 标记,挂了就重启 排查 servicemanager 崩溃原因,或临时去掉 critical 标记调试
其他服务无法注册 servicemanager 未完全启动,或 Binder 驱动异常 检查 /dev/binder 是否存在,以及 ls -l /proc/<pid>/fd

我曾经在调试一个定制系统时,发现 servicemanager 启动后立刻 crash。查了半天,发现是 Binder 驱动版本不匹配——内核里的 Binder 驱动是旧版,而 servicemanager 用了新版 ioctl 命令。所以,如果你在移植 Android 到新内核,一定要确认 Binder 驱动的版本对齐。

好了,关于 servicemanager 的启动,我们就聊到这里。核心就一句话:init 进程通过解析 .rc 文件,fork 出子进程,子进程加载 servicemanager 可执行文件,然后 servicemanager 自己打开 Binder 驱动、注册为上下文管理器、进入循环等待。整个过程干净利落,没有多余的依赖。


公众号:蓝海资料掘金营,微信deep3321