文章内容
- 一、从 Zygote 到系统服务
- 二、启动入口:Zygote 为什么先创建 systemserver
- 三、forkSystemServer:创建进程并设置身份
- 3.1 启动参数描述了什么
- 3.2 父子进程如何分流
- 四、进入 SystemServer.main 之前,还要准备什么
- 4.1 Binder 线程池在哪里启动
- 4.2 为什么通过异常调用 main
- 五、SystemServer.run:先准备环境,再启动服务
- 5.1 三个启动批次表达依赖顺序
- 5.2 SystemServiceManager 管理哪些对象
- 六、启动服务与注册服务,是两个步骤
- 七、ServiceManager 如何把服务交给调用方
- 7.1 注册:传递 Binder 引用
- 7.2 查询:拿到引用后直接调用目标服务
- 八、如何在设备上观察这条链路
- 九、沿着三个边界继续读源码
一、从 Zygote 到系统服务
Zygote 完成预加载后,Android 还不能立即运行应用。管理 Activity、窗口、电源和软件包的服务需要先启动,而这些服务中的许多都运行在同一个进程中:system_server。
理解这段启动流程,要分清三个层次:
- 进程创建:Zygote 通过
fork()创建system_server,为子进程设置运行身份。 - 运行环境初始化:子进程加载入口类、启动 Binder 线程池,进入
SystemServer.main()。 - 服务初始化与发布:
SystemServer按依赖顺序创建服务,并把需要跨进程访问的 Binder 接口注册到servicemanager。
system_server 表示进程,SystemServer 则为该进程的 Java 入口类。

init 启动 Zygote,Zygote 再创建 system_server 和应用进程。支持两种 ABI 的设备可能同时运行主、次两个 Zygote;负责启动 system_server 的是带有相应启动参数的那个 Zygote。Android 还有由 init 直接启动的原生进程,因此不能把 Zygote 理解为所有用户空间进程的父进程。
二、启动入口:Zygote 为什么先创建 system_server
init 的 Zygote 服务配置会向 app_process 传入 --start-system-server。
相关控制流的简化代码:
// 代码位置 /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java 第 565—622 行// ZygoteInit.main():省略其余参数解析与初始化boolean startSystemServer = false;for (int i = 1; i < argv.length; i++) { if ("start-system-server".equals(argv[i])) { startSystemServer = true; }} registerZygoteSocket(socketName);preload();// 省略预加载后的清理等工作 if (startSystemServer) { startSystemServer(abiList, socketName);} runSelectLoop(abiList);这里最重要的是执行顺序:先预加载,再 fork 出 system_server,父进程随后进入 socket 监听循环。
创建 system_server 不需要 AMS 发出请求。此时 AMS 自身还没有创建,必须由 Zygote 的启动流程主动拉起承载它的进程。等系统服务运行起来,AMS 才能通过 Zygote socket 请求创建应用进程。
还要注意,父子进程会从 fork 的返回点继续执行,但会走向不同分支。父进程留在 Zygote 的工作流程中,子进程则转入 SystemServer 的入口,不会继续承担 Zygote 的监听职责。对应实现见 ZygoteInit.java 和 app_main.cpp。
三、forkSystemServer:创建进程并设置身份
3.1 启动参数描述了什么
startSystemServer() 在源码中组装了一组参数,再交给 ZygoteConnection.Arguments 解析。几个关键字段如下:
| 参数 | 含义 |
|---|---|
--setuid=1000 |
使用系统 UID,即 AID_SYSTEM |
--setgid=1000 |
设置主用户组 |
--setgroups=... |
设置附加用户组 |
--capabilities=... |
指定 permitted、effective capabilities 位掩码 |
--nice-name=system_server |
设置进程显示名称 |
--runtime-args |
标记后续内容按运行时参数解析 |
com.android.server.SystemServer |
Java 入口类名 |
| 这些字段分别描述 Linux 身份、进程名称和 Java 入口。 |
UID 1000 不等于 root,也不意味着进程拥有所有系统权限。实际访问能力还受到附加组、Linux capabilities、SELinux 策略以及服务自身权限检查的共同约束。普通第三方应用也不能仅靠在 Manifest 中声明 android.uid.system 就获得系统 UID,安装时还涉及共享 UID 的签名校验等条件。
--runtime-args 同样不是选择 fork 函数的开关。普通应用启动也会使用它;system_server 走专用路径,是因为 startSystemServer() 明确调用了 Zygote.forkSystemServer()。
3.2 父子进程如何分流
解析后的身份信息被传给 fork 方法:
// 代码位置 /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java 第 493—549 行// startSystemServer() 中的关键片段pid = Zygote.forkSystemServer( parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, null, parsedArgs.permittedCapabilities, parsedArgs.effectiveCapabilities); if (pid == 0) { if (hasSecondZygote(abiList)) { waitForSecondaryZygote(socketName); } handleSystemServerProcess(parsedArgs);}成功 fork 后,父进程拿到子进程 PID,子进程拿到 0。只有子进程会进入 handleSystemServerProcess()。双 Zygote 配置下,子进程还会先等待另一个 Zygote 就绪。
Java 层的 forkSystemServer() 在调用 native 方法前后执行虚拟机 fork hooks。native 层的 nativeForkSystemServer() 则进入公共实现 ForkAndSpecializeCommon(),完成 fork,以及子进程的身份、资源限制和安全上下文等设置。
应用进程的 nativeForkAndSpecialize() 也使用这份公共实现。二者共享底层机制,但触发时机、参数和部分处理不同:
| 对比项 | system_server | 普通应用进程 |
|---|---|---|
| 触发来源 | Zygote 启动参数 | AMS 等发来的进程创建请求 |
| Java fork 入口 | forkSystemServer() |
forkAndSpecialize() |
| 身份参数 | 系统预设身份与 capabilities | 请求指定的应用身份等参数 |
| 常规 Java 入口 | SystemServer.main() |
ActivityThread.main() |
普通应用的顺序是“请求创建 → Zygote fork → 子进程初始化”,不会先 fork 一个应用进程,再由这个子进程请求 Zygote fork 第二次。
Zygote 记录 system_server 的 PID,在发现它退出时终止自身,让上层启动机制进行恢复。这说明 system_server 的存活与系统运行紧密相关。相关分支见 Zygote native 实现。

四、进入 SystemServer.main 之前,还要准备什么
handleSystemServerProcess() 此时已经运行在子进程中。fork 复制了进程状态,但子进程还需要清理继承的资源,并准备自己的 Java 入口。
正常启动路径主要完成四项工作:
- 关闭继承的 Zygote 监听 socket:子进程不负责接收进程创建请求。关闭子进程中的描述符不影响父进程继续监听。
- 设置文件创建掩码和进程名:
umask(0077)屏蔽新建文件或目录的组权限、其他用户权限;最终权限仍由创建时的 mode 与掩码共同决定。 - 准备服务类路径:读取
SYSTEMSERVERCLASSPATH,执行所需的 dex 优化,并在正常分支中构造PathClassLoader。 - 进入 RuntimeInit:执行通用初始化,再转向
com.android.server.SystemServer。
类加载器解决的是“从哪里加载服务代码”,本身不会赋予系统权限。进程身份已在前面的 native fork 路径中设置。
4.1 Binder 线程池在哪里启动
RuntimeInit.zygoteInit() 的主线是:
// 代码位置 /frameworks/base/core/java/com/android/internal/os/RuntimeInit.java 第 269—279 行// 省略跟踪与日志设置commonInit();nativeZygoteInit();applicationInit(targetSdkVersion, argv, classLoader);commonInit() 配置公共运行环境,例如未捕获异常处理。nativeZygoteInit() 通过原生运行时回调进入 AppRuntime::onZygoteInit(),由后者调用:
// 代码位置 /frameworks/base/cmds/app_process/app_main.cpp 第 91—95 行sp<ProcessState> proc = ProcessState::self();proc->startThreadPool();这一步为进程建立接收 Binder 事务的线程池。后续服务发布 Binder 接口后,远程调用通常由这些 Binder 线程承接;需要在特定线程执行的工作,再由服务转交给相应 Handler 或工作线程。
Binder 线程池与稍后创建的主线程 Looper 是两套机制。主线程的 Looper.loop() 处理消息队列,并不直接充当 Binder 线程池。对应入口见 RuntimeInit.java 与 AppRuntime 实现。
4.2 为什么通过异常调用 main
applicationInit() 解析目标类及其参数,随后由 invokeStaticMain() 反射查找 public static main(String[])。在 Android 6.0 中,它没有立即调用这个方法,而是抛出携带目标方法和参数的 ZygoteInit.MethodAndArgsCaller。
异常一直回到 ZygoteInit.main(),由这里接住并执行:
// 代码位置 /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java 第 615—616 行catch (MethodAndArgsCaller caller) { caller.run();}这个异常用于转移控制流,不表示启动失败。它让中间的初始化栈帧先退出,再调用目标入口。最终执行的是:
// 代码位置 /frameworks/base/services/java/com/android/server/SystemServer.java 第 167—169 行public static void main(String[] args) { new SystemServer().run();}这里的 new SystemServer() 只是创建 Java 对象。Linux 进程早已由 fork 创建,不能把这两次“创建”当成同一件事。
五、SystemServer.run:先准备环境,再启动服务
进入 run() 后,工作重心从进程创建转向系统服务初始化。省略辅助逻辑后,可以沿着下面的顺序阅读:
校正过早的系统时间、处理属性和运行时配置 ↓设置线程调度策略,准备主线程 Looper ↓ ↓处理待执行的关机或重启请求 ↓创建系统 Context 和 SystemServiceManager ↓startBootstrapServices()startCoreServices()startOtherServices() ↓Looper.loop()createSystemContext() 通过 ActivityThread.systemMain() 建立系统使用的上下文。这里调用 ActivityThread 的方法,并不意味着又创建了应用进程,也不是靠这个 Context 才取得系统 UID。
System.loadLibrary("android_servers") 加载原生库并接入 JNI 方法。加载库与发布服务是不同步骤,例如传感器服务还需要显式调用 startSensorService();不能把“库已加载”理解成“库中的服务全部注册完成”。
5.1 三个启动批次表达依赖顺序
| 方法 | Android 6.0 中的代表服务或工作 |
|---|---|
startBootstrapServices() |
Installer、AMS、PowerManagerService、DisplayManagerService、PackageManagerService,以及 SensorService 的启动 |
startCoreServices() |
BatteryService、UsageStatsService、WebViewUpdateService 等 |
startOtherServices() |
AlarmManagerService、WindowManagerService、InputManagerService,以及更多系统功能 |
这些名称用于组织启动代码,不是把服务简单分成“重要”和“不重要”。关键在于依赖顺序:后面的初始化可能要使用前面已经创建的服务,也可能必须等某个启动阶段完成。
三个方法也不等于三个 boot phase。SystemServiceManager.startBootPhase() 会在流程中的特定位置通知已纳入管理的服务。例如等待默认显示设备的阶段已经出现在引导服务启动过程中,并非等所有其他服务创建完才开始。完整顺序见 SystemServer.java。
5.2 SystemServiceManager 管理哪些对象
SystemServiceManager.startService() 创建或接收 SystemService 实例,将其加入列表,并调用 onStart()。后续 startBootPhase() 再向列表中的服务分发 onBootPhase() 回调。
AMS 通过一个适配生命周期的内部类接入:
// 代码位置 /frameworks/base/services/java/com/android/server/SystemServer.java 第 329—330 行mActivityManagerService = mSystemServiceManager.startService( ActivityManagerService.Lifecycle.class).getService();Lifecycle 继承 SystemService,内部持有真正的 ActivityManagerService。这一层包装使 AMS 能参与统一的生命周期管理。
但并非所有服务都通过同一种入口创建。这个版本中,PackageManagerService 使用 main(...),WindowManagerService 也使用自己的静态入口,InputManagerService 则直接构造。阅读启动代码时,应分别追踪对象创建、初始化和接口发布,不能只搜索 startService()。生命周期管理实现见 SystemServiceManager.java。
六、启动服务与注册服务,是两个步骤
服务对象已经创建,并不意味着其他进程就能按名称找到它。这里需要区分三个名字相近的组件:
| 组件 | 主要职责 | 作用范围 |
|---|---|---|
SystemServiceManager |
启动服务、分发启动阶段和生命周期回调 | system_server 内部 |
LocalServices |
按接口类型保存和获取本地对象 | 当前进程内部 |
ServiceManager / servicemanager |
通过 Binder 注册、查询具名服务 | 跨进程服务发现 |
其中,android.os.ServiceManager 是 Java 侧的访问封装,servicemanager 是独立的原生进程。后者保存服务名与 Binder 引用的对应关系,不承载 AMS、WMS 这些服务的业务实现。
例如,窗口和输入服务在创建后分别发布 Binder 接口:
// 代码位置 /frameworks/base/services/java/com/android/server/SystemServer.java 第 503—504 行ServiceManager.addService(Context.WINDOW_SERVICE, wm);ServiceManager.addService(Context.INPUT_SERVICE, inputManager);AMS 的发布位置则在 setSystemProcess() 内部,不能仅凭 SystemServer.java 中没有直接写出 addService("activity", ...),就判断它没有注册。
有些 SystemService 会在自己的 onStart() 中调用 publishBinderService(),后者最终进入 ServiceManager.addService()。因此,“启动”和“发布”在职责上不同,在实际调用栈中却可能嵌套发生。也有只提供进程内接口的服务,无需发布 Binder 接口。

七、ServiceManager 如何把服务交给调用方
7.1 注册:传递 Binder 引用
Java 层首次访问注册中心时,通过以下代码取得 IServiceManager 接口:
// 代码位置 /frameworks/base/core/java/android/os/ServiceManager.java 第 33—41 行sServiceManager = ServiceManagerNative.asInterface( BinderInternal.getContextObject());在 system_server 中,这里得到的是访问远程注册中心的代理。随后 addService() 将服务名、Binder 引用和 allowIsolated 标记写入 Parcel,向注册中心发起事务。
关键操作是 writeStrongBinder(service)。它传递 Binder 对象的跨进程引用,不能理解成把 Java 对象或一个可直接解引用的内存地址复制到另一进程。Binder 驱动负责处理节点与各进程中引用的映射。
allowIsolated=true 表示允许隔离进程查询该服务,但不代表绕过其他访问控制;注册中心的策略和目标服务的方法权限检查仍然生效。Java 封装与事务实现见 ServiceManager.java 和 ServiceManagerNative.java。
7.2 查询:拿到引用后直接调用目标服务
以应用进程调用 AMS 为例,Android 6.0 的内部获取路径可以概括为:
ActivityManagerNative.getDefault() → ServiceManager.getService("activity") → ActivityManagerNative.asInterface(binder) → IActivityManager 接口代理这里使用该版本的 ActivityManagerNative,避免混入其他版本的 ActivityManager.getService() 调用链。应用开发通常通过公开的 Framework API 使用系统能力,不需要直接调用隐藏的 ServiceManager 接口。对应实现见 ActivityManagerNative.java。
拿到代理以后,业务调用直接通过 Binder 发往 system_server,由 AMS 处理。servicemanager 负责查找服务,不中转后续的每一次业务调用。

完整过程可以拆成四步:
- system_server 创建 AMS,并以
activity为名称发布它的 Binder 引用。 - 调用方查询
activity,取得 Binder 引用并转换为接口代理。 - 调用方调用代理方法,参数通过 Binder 事务进入 system_server。
- AMS 执行权限检查和业务逻辑,按接口约定返回结果;需要切换线程的工作由服务自行调度。
ServiceManager 中还有一个容易误读的 sCache:getService() 会先查本地缓存,但 Android 6.0 的实现不会把每次远程查询结果自动写回它。该缓存通过 initServiceCache() 初始化,具体接口的上层封装也可能另行保存代理。因此不能从“存在缓存”推导出“每个查询过的服务都被 ServiceManager 自动缓存”。
八、如何在设备上观察这条链路
源码说明启动机制,设备命令则帮助确认实际运行状态。不同 Android 版本和构建类型支持的命令选项、可见信息可能不同。
先查看进程:
adb shell ps在输出中找到 zygote、zygote64 和 system_server,比较 PID、PPID。对支持相应选项的较新设备,也可以使用:
adb shell ps -A -o USER,PID,PPID,NAME然后查看已发布的 Binder 服务和具体服务状态:
adb shell service listadb shell dumpsys activityadb shell dumpsys windowadb shell dumpsys batteryservice list 反映注册中心中的 Binder 服务,不等于 SystemServiceManager 的内部列表,也不会列出所有 LocalServices 对象。dumpsys 则适合观察服务当前状态,不能单凭其输出还原全部启动时序。
如需核对进程身份,可将下面的 1234 替换为实际 system_server PID;能否读取取决于设备访问限制:
adb shell cat /proc/1234/status其中 Uid、Gid 可与启动参数对照。本文没有连接设备执行这些命令,以上是供读者验证的操作步骤。
九、沿着三个边界继续读源码
阅读 SystemServer 启动代码时,始终区分这三个时间点:
- fork 完成:system_server 进程已经存在,但系统服务尚未全部创建。
- 服务启动:对象完成相应初始化,可能已经发布接口,但仍需等待后续启动阶段才能提供完整能力。
- 系统就绪:依赖和启动阶段逐步满足,服务开始承担正常的系统工作。
从 Zygote 到 SystemServer.main(),解决的是进程和运行环境的问题;从 run() 到各个服务的启动入口,解决的是依赖与初始化的问题;从 addService() 到调用方持有 Binder 代理,解决的是服务发现与跨进程调用的问题。把这三段分别读清楚,再进入 AMS、PMS 或 WMS 的具体实现,就能判断每段代码处于启动过程的哪一层。
本文由 AgentWorkFlow 生成