Android Zygote 进程启动流程
Android 系统 zygote 进程的启动流程分析。
Android zygote 进程启动过程的要点如下:
- init 进程启动了 zygote 进程。具体来说,init 进程通过
zygote-start
触发器(trigger)拉起zygote
服务(service) - zygote 进程是系统中的第一个 Java 进程
- zygote 进程对应的 Java 类是
com.android.internal.os.ZygoteInit
- zygote 进程启动中有3个关键动作
- 预加载资源
- 启动 SystemServer
- 启动 ZygoteServer
init.rc 中的 zygote 服务
zygote service 的定义见 init.zygote64.rc
1 | # 第1行 |
启动 zygote service 的 trigger 和 action 见 init.rc
1 | # 第557行 |
关于 service, action, trigger 等概念的详细介绍可以参考 Android init language。
app_process64 命令
通过前面的 init.rc
配置我们知道 zygote 进程对应于 /system/bin/app_process64
命令。
而 app_process64
命令相关代码在 /base/cmds/app_process 目录下。
这是一个非常简单的项目,只有一个不到400行代码的 app_main.cpp
。我们重点关注 main 函数,精简后的流程如下:
1 | int main(int argc, char* const argv[]) |
- zygote 进程的启动,对应于分支1
- 普通应用进程的启动,对应于分支2
AppRuntime
及其父类 AndroidRuntime
其实是个简单的 wrapper,对 Java VM 进行一层薄的包装,其定义见这里。
1 | class AndroidRuntime { |
ZygoteInit 类
完整的类名是 com.android.internal.os.ZygoteInit
,代码见 ZygoteInit.java。
ZygoteInit 类及相关类的类图。
ZygoteInit 类的主要操作包括:
- 预加载资源
- 启动 SystemServer (如果指定了
--start-system-server
的话) - 启动 ZygoteServer
1 | public static void main(String[] argv) { |
预加载资源
1 | preload() { |
- 预加载常用类
- 从
/system/etc/preloaded-classes
读取类名 - 对每个类名调用一次
Class.forName()
方法
- 从
- 预加载常用的 drawable 和 color list 资源
- 通过
Resources.getSystem()
获取系统级别的 Resources 对象 - 在该对象上预加载各个
com.android.internal.R.array.preloaded_xxx
对应的资源
- 通过
- 预加载动态库
libandroid.so
和libjnigraphics.so
- 预加载常用字符资源
Hyphenator.init()
TextView.preloadFontCache()
启动 ZygoteServer
ZygoteServer 通过 runSelectLoop() 启动消息循环:
1 | Runnable runSelectLoop(String abiList) { |
ZygoteConnection 是 ZygoteServer 和相应客户端之间的一条连接,两端之间的通信过程发生在 ZygoteConnection.processCommand() 方法中:
1 | Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) { |
- 第1步,读取客户端请求并解析成 parsedArgs 参数
- 第2步,从 zygote 进程 fork 出一个新的进程
- 第3步,初始化新的进程并启动 parseArgs 中指定的 Java 类
当然,这里还有个问题:谁是客户端。这个问题在后续文章中解答。
启动 SystemServer
简单起见,这里我们只要知道通过以下调用关系最终在新的 SystemServer 进程执行 SystemServer.main()
函数即可,具体的分析放在下一篇中。
1 | ZygoteInit.main() |
上述调用关系对应的代码如下:
1 | public static void main(String[] argv) { |
更正
今天(7月20)打日志观察进程启动流程:
- 我确认自己对 init、zygote 和 system_server 三个进程的启动流程理解大体正确
- 但也有不正确的地方。我偶然通过日志发现普通 app 进程启动时似乎并不走前面”启动 ZygoteServer”那一节列出的任何代码逻辑
今天又看了一下 runSelectLoop()
里的逻辑,比预期的要复杂一些。
1 | Runnable runSelectLoop(String abiList) { |
而 processCommand()
里面 fork 进程,也有新老不同的两种处理方式:
1 | Runnable processCommand(ZygoteServer zygoteServer, boolean multipleOK) { |
Zygote 中有4个不同的 forkXXX()
方法:
- forkSystemServer()
- forkUsap()
- forkSimpleApps()
- forkAndSpecialize()
除第1个 forkSystemServer()
功能明确外,剩下三个待进一步了解。
TODO
粗线条地理解 zygote 进程启动过程并不难,但更好地理解还需要先了解一些背景知识。待整理的背景知识点:
- Linux 的进程 fork 机制
- Android 的 Local Socket 机制,这个本质上应该是 UNIX domain socket
- C++ 代码中如何创建一个 JavaVM
参考
- services/java/com/android/server/SystemServer.java - platform/frameworks/base - Git at Google
- core/java/com/android/internal/os/ZygoteServer.java - platform/frameworks/base - Git at Google
- rootdir/init.zygote64.rc - platform/system/core - Git at Google
- core/java/com/android/internal/os/Zygote.java - platform/frameworks/base - Git at Google
- core/java/com/android/internal/os/ZygoteInit.java - platform/frameworks/base - Git at Google
- cmds/app_process/app_main.cpp - platform/frameworks/base - Git at Google