3、Zygote进程与System Server:Android进程孵化机制,System Server启动流程与核心服务
说实话,Zygote 和 System Server 这两兄弟,是 Android 系统启动过程中最核心的两个角色。我当年刚接触 Android 底层时,总觉得 Zygote 就是个“进程复制机”,System Server 就是个“服务大管家”。后来踩了不少坑才明白——它们之间的关系远比想象中复杂。
今天我们就来彻底搞懂这两个进程。我会结合我实际项目中的一些经历,帮你避开那些容易翻车的点。
3.1 Zygote 进程:Android 的“进程孵化器”
Zygote 这个词,直译是“受精卵”。名字起得很形象——它负责“孕育”出 Android 世界里所有的应用进程。
Zygote 进程本身是由 init 进程启动的。init 解析 init.rc 脚本时,会找到这样一段配置:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
onrestart restart wificond
注意看 --start-system-server 这个参数。它告诉 Zygote:启动后,顺便把 System Server 也给我拉起来。这就是两个进程的第一次“握手”。
3.2 Zygote 启动流程:从 native 到 Java
Zygote 的启动过程,说白了就是一次从 C++ 世界跨入 Java 世界的过程。我把它拆成几个关键步骤:
- init 进程 fork 出 Zygote——此时还是 native 进程
- Zygote 执行 app_process 入口——调用 AndroidRuntime::start()
- 启动 Java 虚拟机——创建 Dalvik/ART 实例
- 注册 JNI 函数——让 Java 代码能调用 native 方法
- 调用 ZygoteInit.main()——正式进入 Java 世界
- 预加载资源——加载 framework 类、主题、字体等
- 启动 System Server——fork 出第二个关键进程
- 进入 Socket 监听循环——等待 AMS 发来创建应用的请求
嗯,这里有个细节很多人会忽略:预加载。Zygote 在启动时会加载大量的 Java 类和资源。为什么要这么做?
你想想看,如果每个应用启动时都要重新加载一遍 framework 类,那得多慢?Zygote 的做法是:先把这些公共资源加载到自己进程里,然后 fork 子进程时,利用 Linux 的 COW(写时复制)机制,子进程直接共享这些内存。说白了就是“一次加载,全家共享”。
核心要点:Zygote 预加载的类包括 android.* 包下的几乎所有核心类,以及常用的 UI 组件、资源文件。我统计过,大约有 2000+ 个类和 1000+ 个资源文件。这也是为什么 Zygote 启动后内存占用就很大——它是在为所有应用“垫资”。
3.3 System Server 启动:Android 服务的“总开关”
System Server 是 Zygote fork 出来的第一个子进程。它的任务只有一个:启动并管理 Android 所有核心系统服务。
我刚开始看 System Server 源码时,被它那长长的启动顺序搞晕了。后来我画了一张图,才理清楚它的脉络:
这张图是我自己整理的。你看,System Server 的启动分三个阶段:
- 引导服务:最基础的服务,比如 Installer(负责安装应用)、DeviceIdentifiers(设备标识)。这些服务启动早,依赖少。
- 核心服务:AMS(Activity管理)、WMS(窗口管理)、PMS(包管理)、PowerManager(电源管理)。这些是 Android 的“五脏六腑”。
- 其他服务:Camera、Bluetooth、Wifi 等。它们依赖核心服务,所以放在最后。
避坑指南:我曾经在定制 ROM 时,遇到一个诡异的问题:系统启动后 Wifi 服务总是崩溃。查了两天才发现,是因为我在 PMS 启动之前就尝试注册 Wifi 服务。PMS 还没准备好,Wifi 拿不到包信息,自然就挂了。记住:服务启动顺序不能乱,这是 System Server 最核心的设计原则。
3.4 核心服务详解:AMS、WMS、PMS
这三个服务,是 Android 应用层的“三驾马车”。我分别说一下它们启动时的关键点。
3.4.1 AMS(ActivityManagerService)
AMS 是 System Server 里最复杂的服务,没有之一。它负责管理 Activity 的生命周期、进程调度、Intent 解析等。
AMS 启动时,会做以下几件事:
- 创建
ActivityStackSupervisor——管理所有 Activity 栈 - 创建
ProcessList——管理进程优先级和 OOM 调整 - 调用
startHomeActivityLocked()——启动桌面 Launcher - 注册
ProcessDeathListener——监听应用进程死亡
我个人觉得,AMS 最巧妙的设计是 进程优先级管理。它把进程分成多个等级:前台进程、可见进程、服务进程、后台进程、空进程。每个等级对应不同的 oom_adj 值。当系统内存不足时,LMK(Low Memory Killer)会根据这个值来杀掉进程。
// 进程优先级定义(部分)
// ProcessList.java
static final int FOREGROUND_APP_ADJ = 0;
static final int VISIBLE_APP_ADJ = 100;
static final int SERVICE_ADJ = 500;
static final int BACKUP_APP_ADJ = 600;
static final int HOME_APP_ADJ = 600;
static final int HIDDEN_APP_MIN_ADJ = 900;
static final int CACHED_APP_MAX_ADJ = 906;
你看,前台进程的 adj 值是 0,几乎不会被杀。而缓存进程的 adj 值是 906,内存紧张时第一个被清理。这个机制保证了用户正在交互的应用始终流畅。
3.4.2 WMS(WindowManagerService)
WMS 负责管理窗口的创建、布局、输入事件分发。它启动时会做:
- 创建
DisplayContent——管理屏幕显示区域 - 创建
InputManager——处理触摸、按键事件 - 创建
WindowAnimator——管理窗口动画
WMS 和 AMS 的交互非常频繁。比如你打开一个 Activity,AMS 会通知 WMS 创建对应的窗口;用户触摸屏幕,WMS 通过 InputManager 拿到事件,再交给 AMS 决定分发给哪个 Activity。
注意:WMS 和 AMS 运行在同一个进程(System Server)中,但它们通过 Binder 通信。为什么不用直接调用?因为 System Server 内部也使用了 Binder 架构,这样设计是为了保持一致性,方便后续扩展和调试。我见过有人试图绕过 Binder 直接调用,结果导致死锁——千万别这么干。
3.4.3 PMS(PackageManagerService)
PMS 负责扫描和安装应用。它启动时最耗时的操作是 扫描 /data/app 和 /system/app 目录。
PMS 启动流程:
- 扫描系统应用目录(/system/app, /system/priv-app)
- 扫描用户应用目录(/data/app)
- 解析每个 APK 的 AndroidManifest.xml
- 建立包名到组件信息的映射表
- 通知 AMS 和 WMS 应用信息已就绪
嗯,这里有个性能问题。如果手机里装了 500 个应用,PMS 启动时扫描 APK 可能要花好几秒。我记得在 Android 8.0 之前,每次开机都要全量扫描,那叫一个慢。后来 Google 引入了 dex2oat 编译缓存 和 包信息数据库,才把启动时间降下来。
3.5 Zygote 与 System Server 的协作关系
这两个进程的协作,可以用一句话概括:Zygote 负责生,System Server 负责养。
具体来说:
- Zygote 启动 System Server 后,就进入 Socket 监听模式
- System Server 中的 AMS 收到启动应用的请求时,通过 Socket 向 Zygote 发送命令
- Zygote fork 出新的应用进程,并返回 PID 给 AMS
- AMS 通过 Binder 通知新进程加载 Application 和 Activity
我画了一个简化的流程图:
你看,整个流程就是:Zygote 启动 System Server → System Server 需要创建应用时通知 Zygote → Zygote fork 出应用进程 → System Server 通过 Binder 管理应用。
3.6 常见问题与避坑
最后,分享几个我在实际项目中遇到的问题:
| 问题 | 原因 | 解决方案 |
|---|---|---|
| System Server 启动超时 | 某个服务初始化太慢,超过 5 分钟 | 检查服务依赖,确保没有循环依赖;优化启动逻辑 |
| Zygote fork 失败 | 内存不足,无法分配 COW 页面 | 减少 Zygote 预加载的资源;增加 swap 空间 |
| AMS 死锁 | 多个服务同时持有锁,互相等待 | 使用 systrace 分析锁竞争;避免在 Binder 调用中持有锁 |
| PMS 扫描过慢 | APK 数量多,且没有缓存 | 启用 dex2oat 缓存;使用增量扫描 |
个人经验:我曾经遇到一个线上问题:手机开机后,Launcher 要等 30 秒才能显示。用 bootchart 分析后发现,是 PMS 扫描 /data/app 时,有一个损坏的 APK 导致解析卡住。从那以后,我养成了一个习惯:在 PMS 扫描时加一个超时机制,超过 2 秒就跳过这个 APK,等系统启动后再单独处理。
好了,关于 Zygote 和 System Server 的核心机制,就讲到这里。这两个进程是 Android 系统的基石,理解了它们,你就掌握了 Android 启动流程的“命门”。