阅读须知
本文源码基于 Android 10
。
Questions
-
Zygote
是什么?有什么作用?? -
Zygote
是如何启动的,启动后做了哪些事情? - 为什么不用
SystemServer
孵化应用进程? -
Zygote
的通信方式?为什么不使用Binder
进行通信?
Zygote
Zygote
是 init
孵化的一个进程。本文将从源码的角度对 Zygote
进行分析,包括 Zygote
是如何启动的,在 Native
层和 Java
层分别做了哪些事情。
本文主要流程如下图所示:
启动 Zygote
先来看看第一步启动 Zygote
,这里主要做了两件事情:
-
init
进程解析init.rc
文件; - 启动
Zygote
服务。
解析 init.rc 文件
linux
内核启动后会去创建 init
进程,init
进程是用户空间的第一个进程。
init
进程的入口函数在 Anroid 10
上做了调整,不再是之前的 system/core/init/init.cpp
,变成了 system/core/init/main.cpp
中的 main()
函数。
// system/core/init/main.cpp
int main(int argc, char** argv) {
if (argc > 1) {
// 参数为 "second_stage",启动 init 进程第二阶段
if (!strcmp(argv[1], "second_stage")) {
return SecondStageMain(argc, argv);
}
}
// 默认启动 init 进程第一阶段
return FirstStageMain(argc, argv);
}
init
进程的启动分为两个阶段,因为本文主要是讲解 Zygote
,这里就直接进入第二阶段 SecondStageMain()
。
// system/core/init/init.cpp
int SecondStageMain(int argc, char** argv) {
// 解析 init.rc 文件
LoadBootScripts(am, sm);
std::string bootmode = GetProperty("ro.bootmode", "");
if (bootmode == "charger") {
// 添加 trigger charger
am.QueueEventTrigger("charger");
} else {
// 添加 trigger late-init
am.QueueEventTrigger("late-init");
}
// ...
return 0;
}
在 init
进程的第二阶段,会通过 LoadBootScripts()
解析 init.rc
文件;然后添加一些 trigger
,这些 trigger
会触发 init.rc
文件中对应的 Action
,这里需要结合 init.rc
来看。
# system/core/rootdir/init.rc
# action 的一般结构为
# on trigger [ <& trigger> ]*
# command1
# command2
# ...
# 表示当满足 trigger 的时候依次执行下面的 command
# trigger charger
on property:sys.boot_from_charger_mode=1
class_stop charger
trigger late-init
# trigger late-init
on late-init
trigger zygote-start
# trigger zygote-start
on zygote-start && property:ro.crypto.state=unencrypted
# 重点是这里会 start zygote 服务
start zygote
start zygote_secondary
on zygote-start && property:ro.crypto.state=unsupported
start zygote
start zygote_secondary
on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file
start zygote
start zygote_secondary
可以看到,在 SecondStageMain()
中添加的 trigger charger
和 trigger late-init
最终都会触发 start zygote
命令,没错,这个命令就是用于启动 Zygote
服务的。
启动 Zygote 服务
Zygote
服务定义在哪里呢?我们回到 init.rc
文件的最前面,会发现如下代码。
# system/core/rootdir/init.rc
import /init.${ro.zygote}.rc
可以发现它导入了 init.${ro.zygote}.rc
文件,其实就是不同的平台(32位,64位,32_64位和64_32位)上对应的 init.zygote.rc
文件,如下图所示。
解释一下,因为 Android 5.0
开始支持 64 位程序,为了兼容 32 位和 64 位才会这样定义。
这些文件含义如下:
-
init.zygote32.rc
表示Zygote
进程对应的执行程序是app_process
(纯 32 bit 模式); -
init.zygote64.rc
表示Zygote
进程对应的执行程序是app_process
(纯 64 bit 模式); -
init.zygote32_64.rc
表示会启动两个Zygote
进程(zygote
和zygote_secondary
),对应的执行程序分别是app_process32
(主模式)、app_process64
; -
init.zygote64_32.rc
表示会启动两个Zygote
进程(zygote
和zygote_secondary
),对应的执行程序分别是app_process64
(主模式)、app_process32
。
这里以 init.zygote64_32.rc
为例,它的定义如下。
# system/core/rootdir/init.zygote64_32.rc
# service 的一般结构为
# service [name] [pathname] [ ] *
# option
# option
# ...
# 表示名称为 name 的服务,启动程序位于 pathname,传递参数为 [ ]*
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
class main
priority -20
user root
group root readproc reserved_disk
# option socket 的一般结构为 socket [name] [ ]*,这里表示创建名称为 zygote 的 socket
socket zygote stream 660 root system
socket usap_pool_primary stream 660 root system
# option onrestart 表示当 zygote 服务重启的时候需要做什么事情
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
# option writepid 表示创建子进程时,向 /dev/cpuset/foreground/tasks 写入 pid
writepid /dev/cpuset/foreground/tasks
service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
class main
priority -20
user root
group root readproc reserved_disk
# 创建名为 zygote_secondary 的 socket
socket zygote_secondary stream 660 root system
socket usap_pool_secondary stream 660 root system
# 当 zygote_secondary 重启的时候也要重启 zygote
onrestart restart zygote
writepid /dev/cpuset/foreground/tasks
主要看第一行:
-
/system/bin/app_process64
表示启动zygote
服务对应执行的二进制文件; -
-Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
是传递给可执行文件的参数(--zygote
表示zygote
模式,--start-system-server
表示启动SystemServer
,后面会说到,简单了解一下)。
这里的可执行文件 /system/bin/app_process64
在编译前对应的源码位于 frameworks/base/cmds/app_process
下,来看看下面的 Android.mk
。
# frameworks/base/cmds/app_process/Android.mk
app_process_src_files := \
app_main.cpp \
LOCAL_MODULE:= app_process
LOCAL_MULTILIB := both
LOCAL_MODULE_STEM_32 := app_process32
LOCAL_MODULE_STEM_64 := app_process64
可以看到无论是 app_process
、app_process32
和 app_process64
对应的源文件都是 app_main.cpp
,这也就是 Zygote Native
层的入口了。
Zygote Native 层
app_main.cpp
即 Zygote
在 Native
的入口了。来看看其做了哪些事情:
- 解析参数;
- 创建虚拟机;
- 注册
JNI
函数; - 查找
static main()
并调用。
解析参数
前面我们已经找到 Zygote Native
层的入口 app_main.cpp
,来看看其 main()
。
// frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
{
// 这里会创建 AppRuntime 的对象,它是 AndroidRuntime 的子类
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;
++i;
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
// --zygote 参数表示启动 zygote 进程
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
// --start-system-serve 参数表示启动 SystemServer
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
// --application 参数表示启动应用进程
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
// --nick-name 指定进程名
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
// 与 --application 配置,启动指定的类,application 启动的 class
className.setTo(arg);
break;
} else {
--i;
break;
}
}
Vector args;
if (!className.isEmpty()) {
// --application 模式下
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);
} else {
// --zygote 模式下
// 创建 dalvik 的缓存目录,并定义权限
maybeCreateDalvikCache();
// 如果指定了 --start-system-server
if (startSystemServer) {
args.add(String8("start-system-server"));
}
// 添加 --abi-list 参数
String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag);
// 添加未解析的参数
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}
if (!niceName.isEmpty()) {
// 如果指定了 --nick-name,则修改进程名
runtime.setArgv0(niceName.string(), true /* setProcName */);
}
if (zygote) {
// zygote 模式,调用 AppRuntime 的 start(),启动 ZygoteInit
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
// application 模式,启动 RuntimeInit
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
}
}
这里首先创建 AppRuntime
对象,然后进行参数解析。
从参数解析可以看出它是有两种模式的:
-
zygote
模式,传递参数为--zygote --start-system-server
也就是前面init.zygote64_32.rc
传入的参数,这种模式主要是启动SystemServer
进程; -
application
模式,传递参数为--className=xxx
以及className
携带的参数,这种模式是启动应用进程。
主要分析 zygote
模式,application
模式后续分析应用进程启动的时候再进行说明。这里参数解析完成后,如果是 zygote
模式,会调用 AppRuntime.start()
,并传入 com.android.internal.os.ZygoteInit
和解析好的参数,而 AppRuntime
是 AndroidRuntime
的子类,并且没有重写 start()
,那我们直接看 AndroidRuntime.start()
即可。
创建虚拟机
在 start()
里面首先会创建虚拟机。
// frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
// 创建虚拟机
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);
}
注册 JNI 函数
然后会注册 JNI
函数。
// frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
if (startReg(env) < 0) {
return;
}
}
int AndroidRuntime::startReg(JNIEnv* env)
{
// 注册 jni 函数
if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {
env->PopLocalFrame(NULL);
return -1;
}
}
进入 Zygote Java 层
最后会查找并调用 com.android.internal.os.ZygoteInit
的 static main()
,进入到 Zygote Java
层。
// frameworks/base/core/jni/AndroidRuntime.cpp
// 找 ZygoteInit 的 static main()
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
{
jmethodID startMeth = env->GetStaticMethodID(startClass, "main", "([Ljava/lang/String;)V");
if (startMeth == null) {
} else {
// 找到 static main() 直接调用
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
}
Zygote Java 层
走到 ZygoteInit.main()
也就进入到了 Java
层,来看看其做了哪些事情:
- 预加载;
- 创建
Zygote Server Socket
- 启动
SystemServer
; - 等待和处理请求。
预加载
在 Java
层,Zygote
首先会通过 preload()
进行预加载,在这里会预加载一些常用的类(比如常用的 Activity),主题资源,库等。
// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
// 进行预加载
preload(bootTimingsTraceLog);
}
static void preload(TimingsTraceLog bootTimingsTraceLog) {
// 预加载 /system/etc/preloaded-classes 文件里面定义的常用类(比如我们用到的 Activity,Fragment 等)
preloadClasses();
// 预加载系统资源
preloadResources();
// 硬件抽象层
nativePreloadAppProcessHALs();
// 图形驱动
maybePreloadGraphicsDriver();
// 加载必要的库
preloadSharedLibraries();
// 语言相关字符信息
preloadTextResources();
// webview
WebViewFactory.prepareWebViewInZygote();
}
那为什么要进行预加载呢?
-
Android
通过Zygote fork
的方式创建子进程,Zygote
进程预加载一些类和资源,这样在fork
子进程的时候,只需要复制一份即可,这样就节省了子进程的启动时间 - 根据
fork
的copy-on-write
机制,有些类如果不做改变,甚至都不用复制,子进程可以和父进程共享这部分数据,从而省去不少内存的占用
创建 Zygote Server Socket
预加载完成后,会创建 Server Socket
,Zygote
是使用的 Socket
进行通信的。
// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
// 这里会创建 server socket
ZygoteServer zygoteServer = null;
zygoteServer = new ZygoteServer(isPrimaryZygote);
}
// frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
ZygoteServer(boolean isPrimaryZygote) {
// 创建 ServerSocket
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
mUsapPoolSocket =
Zygote.createManagedSocketFromInitSocket(
Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
// android 10 的 usap 机制,感兴趣的可以了解下,就是会预创建 usap 进程,后面启动进程的时候使用这种方式会快一点
fetchUsapPoolPolicyProps();
}
// frameworks/base/core/java/com/android/internal/os/Zygote.java
static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
// 创建 server socket
return new LocalServerSocket(fd);
}
//
public LocalServerSocket(FileDescriptor fd) throws IOException
{
// 创建 server socket
impl = new LocalSocketImpl(fd);
// 监听50端口
impl.listen(LISTEN_BACKLOG);
localAddress = impl.getSockAddress();
}
启动 SystemServer
创建完 server socket
后,会通过 forkSystemServer()
启动 SysteServer
,这里底层会调用 fork()
创建 syste_server
进程,关于 SystemServer
后面写的时候再做具体分析。
// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
// 解析参数
boolean startSystemServer = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
}
}
if (startSystemServer) e
// 通过 forkSystemServer() 启动 SystemServer,最终是通过 fork() 去创建的
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);
if (r != null) {
r.run();
return;
}
}
}
等待和处理请求
最后,Zygote
会调用 runSelectLoop()
开启循环等待和处理 socket
请求。
// frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
// 开启循环,等待和处理请求
caller = zygoteServer.runSelectLoop(abiList);
}
// frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
Runnable runSelectLoop(String abiList) {
while (true) {
// 当 pollFDs 有事件到来则往下执行,否则阻塞在这里
Os.poll(pollFDs, -1);
while (--pollIndex >= 0) {
if (pollIndex == 0) {
// 请求到来的时候,创建 socket 连接
ZygoteConnection newPeer = acceptCommandPeer(abiList);
} else if (pollIndex < usapPoolEventFDIndex) {
// 处理 socket 请求
ZygoteConnection connection = peers.get(pollIndex);
final Runnable command = connection.processOneCommand(this);
}
}
}
}
private ZygoteConnection acceptCommandPeer(String abiList) {
return createNewConnection(mZygoteSocket.accept(), abiList);
}
protected ZygoteConnection createNewConnection(LocalSocket socket, String abiList)
throws IOException {
// 创建 socket 连接
return new ZygoteConnection(socket, abiList);
}
当有请求到来的时候,会先通过 acceptCommandPeer()
创建 socket
连接(ZygoteConnection
)。然后通过 processOneCommand()
处理 socket
请求,具体的源码在写应用启动流程的时候再详细分析,这里了解 Zygote
是如何进行通信的即可。
Answers
到此,Zygote
的分析就结束了。接下来我们得回过头看看前面提到的一些问题。
Zygote 是什么?有什么作用?
Zygote
是由 init
创建出来的进程,它负责启动 SysteServer
,孵化应用进程。
Zygote 是如何启动的,启动后做了哪些事情?
当 linux
内核启动后,会创建 init
进程,init
进程启动后解析 init.rc
文件,触发 start zygote
命令启动 zygote
服务。
Zygote
启动后做的事情可以分为 Native
层和 Java
层。
Native
层:
- 创建虚拟机;
- 注册
JNI
函数; - 查找并调用
ZygoteInit
的static main()
,进入Java
层。
Java
层:
- 预加载常用类,主题资源,库等;
- 创建
Zygote Server Socket
; - 启动
SystemServer
; - 循环等待和处理请求。
为什么不用 SystemServer 孵化应用进程?
应用在启动的时候需要做很多准备工作,包括启动虚拟机,加载常用类,主题资源等,这些在 Zygote
启动后就已经完成了,应用进程通过 zygote fork
的时候只需要复制一份即可,提高了应用进程的启动效率,而对于没有修改的类甚至不用复制,直接和 Zygote
共享,节省了应用进程的内存空间。
而对于 SystemServer
,它会启动 Binder
线程,引导服务,核心服务和其他服务等,这些是不应该被继承到应用进程的。
所以,将 SystemServer
和应用进程都需要的资源单独放到 Zygote
里面进行处理,各自的事情等进程孵化出来后自己处理就好了。
Zygote 的通信方式?为什么不使用 Binder 进行通信?
Zygote
是使用的 Socket
进行的通信。
如果 Zygote
使用 Binder
进行通信,那么它需要启动 Binder
线程,打开 Binder
驱动,获取文件描述符,再通过 mmap
进行内存映射,还要创建 Binder
对象注册到 ServiceManager
。
试想一下 AMS
向 Zygote
发起启动应用进程请求的话,需要从 ServiceManager
中查询 Zygote
的 Binder
对象,然后再通过 Binder
调用,十分的繁琐。而且 Zygote
和 SystemServer
本来就是父子进程关系,简单的消息通信使用 Socket
非常方便。