Zygote 进程启动流程
核心目标:理解 Android 系统服务和应用进程的起源
- 系统服务(SystemServer)的起源:我们手机里的各种系统服务,如活动管理(ActivityManager)、窗口管理(WindowManager)、包管理(PackageManager)等,都不是凭空产生的。它们都运行在一个名为
system_server
的进程中,而这个进程正是由 Zygote 进程“孵化”(fork)出来的 - 应用进程的起源:当你点击一个 App 图标时,系统需要为这个 App 创建一个新的进程来运行它的代码。为了极致地优化启动速度和内存占用,Android 不会在这个新进程里从头开始加载 Android 框架所需的类和资源,而是直接复制(fork)已经准备好的 Zygote 进程。这样,新进程一诞生就天然继承了 Zygote 已经预加载好的所有资源,从而能够快速启动
Zygote 的核心思想就是 “共享内存,写时复制(Copy-on-Write)”。通过预先加载通用的、只读的代码和资源(如Android框架的类库、主题资源等),让所有子进程共享同一块内存空间。只有当某个进程试图修改这些共享内容时,系统才会为其复制一份副本。这极大地节省了内存和启动时间
学习路径分解
研究 Zygote 启动流程的三个关键步骤,我们逐一进行详细分析
第一步:从 init.rc
脚本开始,追踪 Zygote 的启动参数
init.rc
是什么?
Android 设备启动时,内核加载完成后启动的第一个用户空间进程是init
(初始化进程)。init
进程的责任之一是解析和执行一系列扩展名为.rc
的初始化脚本文件。init.rc
是其中最核心的主脚本,它定义了在启动特定阶段需要执行的服务(service)和动作(action)- Zygote 在
init.rc
中的定义
在init.rc
(或通常由init.zygoteXX.rc
导入,如init.zygote32.rc
for 32位)中,你会找到类似这样的服务声明:service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server --socket-name=zygoteclass mainsocket zygote stream 660 root system...
service zygote
:定义了一个名为 “zygote” 的系统服务
○/system/bin/app_process
:这是 Zygote 进程真正的可执行文件。它是一个通用的 Android 应用进程启动器
○-Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
:这些是传递给app_process
的启动参数
◎--zygote
:告诉app_process
:“请以 Zygote 模式运行”
◎--start-system-server
:指示 Zygote 在启动后立即“孵化”(fork)并启动 SystemServer 进程。这就是系统服务的起源
◎--socket-name=zygote
:指定 Zygote 要监听的 Socket 名称,后续应用进程的启动请求就是通过这个 Socket 通信的
○socket zygote stream 660 root system
:同时创建一个名为 “zygote” 的 Unix Domain Socket,并设置其权限。这是 Zygote 与其他进程通信的桥梁
小结: 这一步明确了 Zygote 是由 init
进程根据脚本配置启动的,其二进制文件是 app_process
,并获得了关键的执行参数
第二步:分析 app_main.cpp
的 main
函数
- 这个文件是干什么的?
app_main.cpp
是app_process
可执行文件的源码文件。它的main()
函数是 Zygote 进程的原生(Native,C++)入口点 main
函数的关键工作:
① 解析参数:接收并解析从init.rc
传过来的参数(如--zygote
,--start-system-server
)
② 创建 AppRuntime:实例化一个AppRuntime
对象(它是 AndroidRuntime 的子类),这是启动 Android Java 世界的核心类
③ 准备虚拟机参数:根据启动参数配置 Java 虚拟机(JVM/ART)的各种选项,例如堆大小、垃圾回收策略等(-Xzygote
参数就在这里处理)
④ 启动虚拟机并进入 Java 世界:这是最关键的一步。调用runtime.start(“com.android.internal.os.ZygoteInit”, args, zygote)
◎ 这个调用会启动 Android 运行时环境(ART)
◎ 然后,它并不是直接运行一个 Java 类的main
方法,而是通过 JNI 调用com.android.internal.os.ZygoteInit
类的main
方法
◎ 从此,执行流程就从 C++ 原生代码 跳转到了 Java 代码。Zygote 进程的核心逻辑正式开始
小结: app_main.cpp
是承上启下的枢纽。它作为原生入口,解析配置,初始化 Android 运行时,并将执行权交给 Java 端的 ZygoteInit
类
第三步:理解 ZygoteInit.java
的 main
方法
这是 Zygote 启动流程的 Java 层核心。它的 main
方法主要完成三件大事
- 预加载资源(preload)
static void preload() {preloadClasses(); // 预加载 frameworks.jar 中列出的常用类(在 preloaded-classes 文件中定义),数量高达上千个。preloadResources(); // 预加载系统资源(如 frameworks-res.apk 中的颜色、尺寸、字符串、图片等),这样所有应用进程都能共享这些资源,无需各自加载。preloadSharedLibraries(); // 预加载共享库(如 android, jnigraphics 等)preloadTextResources(); // 预加载文字相关资源// 等等... }
目的:极大提升应用进程的启动速度,并节省内存。这些只读资源在所有子进程间是共享的
启动 SystemServer(forkSystemServer)
○ 这是 Zygote 孵化的第一个子进程
○ 通过Zygote.forkSystemServer()
方法,当前进程(Zygote)调用fork()
系统调用,分裂出一个与自己几乎一模一样的子进程(即system_server
)
○ 在子进程(system_server
)中,会脱离 Zygote 的启动路径,转而调用com.android.server.SystemServer
类的main
方法,开始启动所有 Java 编写的系统服务
○ 从此,Android 系统的核心大脑就开始运转了进入 Socket 循环等待创建新应用进程(runSelectLoop)
○ 在完成上述任务后,Zygote 的使命就变成了“待命”,等待创建新的应用进程
○ 它调用ZygoteServer.runSelectLoop()
方法,在一个死循环中监听之前创建的 “zygote” Socket
○ 当 ActivityManagerService(AMS,运行在刚启动的system_server
进程中)需要启动一个新应用时,它会向这个 Socket 发送一个连接请求和启动命令(包含要启动的 App 包名、主类名等信息)
○ Zygote 接收到请求后,再次调用fork()
,分裂出一个新的子进程(即应用进程)
○ 在子进程(应用进程)中,会处理启动参数,最终调用ActivityThread
类的main
方法,开始执行应用的代码
○ 父进程(Zygote)则继续回到 Socket 循环中,等待下一个请求。由于fork()
的特性,Zygote 进程始终保持“纯净”,里面只有预加载好的系统资源,没有任何应用代码
总结
Zygote 的启动流程是一个经典的、分层清晰的、充分优化的设计:
- 由
init
进程根据配置脚本启动,确定了其基础身份和参数 app_process
(app_main.cpp) 作为原生入口,完成底层初始化,并搭建好通往 Java 世界的桥梁ZygoteInit
在 Java 世界完成三大核心使命:
○ 预加载(Preload):为快速孵化做准备(备好“干粮”)
○ 孵化系统服务(Fork SystemServer):生下第一个最重要的“孩子”,让它去管理整个系统
○ 监听请求(Socket Loop):进入“待产”状态,随时根据系统指令孵化出新的应用进程