安卓启动流程梳理之 Zygote 进程
安卓系统从开机到桌面显示是一个长而复杂的流程,本文参考安卓源码记录安卓启动流程的梳理学习。(文章涉及的源码基于 Android 10.0)由于 Android 启动流程很长,所以分几篇来记录,本篇记录安卓系统进程之父 Zygote 进程的启动过程。
[TOC]
zygote
进程是在 Init
进程启动时创建的,通过 init.zygotexx.rc
脚本启动,zygote
进程可以通过调用 fork()
函数创建应用程序进程和 system server
进程,所以 zygote
进程通常被称为进程孵化器。 zygote
进程在启动的时候会创建 JVM
,因此通过 zygote
进程创建的进程可以在进程内部获取一个 JVM
实例副本。
zygote 进程入口
zygote
进程通过 init.zygotexx.rc
脚本启动,这些脚本存放在 system/core/rootdir
目录下。
1 service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
...
17 service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
...
上面代码是 init.zygote63_32.rc
文件中截取的,从中可以看出,这里通过 service
语句启动了两个 zygote
进程,一个是名为 zygote
,执行程序为 app_process64
的主模式 zygote
进程,另一个是名为 zygote_secondary
,执行程序为 app_precess32
的辅模式 zygote
进程。app_prcessxx
会执行到 /framework/base/cmds/app_process/app_main.cpp
文件中的 main()
方法中。
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) { // 1
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) { // 2
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
}
...
if (startSystemServer) {
args.add(String8("start-system-server"));
}
...
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote); // 3
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
}
}
从 main
方法中可以看出,通过入参 '--zygote'
指定了启动 zygote
进程, 通过 '--start-system-server'
指定了在 zygote
进程中启动 system server 进程。最后是执行到 AppRuntime.start()
方法中,而 AppRuntime
继承自 AndroidRuntime
,所以接下来执行 AndroidRuntime.start()
方法。
AndroidRuntime.start()
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
JniInvocation jni_invocation;
jni_invocation.Init(NULL); // 1
JNIEnv* env;
if (startVm(&mJavaVM, &env, zygote) != 0) { // 2
return;
}
onVmCreated(env);
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
...
char* slashClassName = toSlashClassName(className != NULL ? className : "");
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
env->CallStaticVoidMethod(startClass, startMeth, strArray); // 3
}
}
free(slashClassName);
}
start()
方法中主要执行了:
- 初始化并注册
JNI
接口方法 - 启动
JVM
虚拟机 - 由入参
'com.android.internal.os.ZygoteInit'
找到ZygoteInit
类,并通过JNI
调用ZygoteInit.main()
方法。
ZygoteInit.main()
public static void main(String argv[]) {
Runnable caller;
try {
boolean startSystemServer = false;
String zygoteSocketName = "zygote";
boolean enableLazyPreload = false;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true;
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length());
}
}
if (!enableLazyPreload) {
preload(bootTimingsTraceLog); // 1
} else {
Zygote.resetNicePriority();
}
...
final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);
zygoteServer = new ZygoteServer(isPrimaryZygote); // 2
if (startSystemServer) {
Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer); // 3
if (r != null) {
r.run();
return;
}
}
caller = zygoteServer.runSelectLoop(abiList);
}
...
}
ZygoteInit.main
方法中主要执行了:
-
preload()
预加载虚拟机运行时所需的各类资源,包括常用的classes
、资源库、sharedLibraries
等。这个过程支持通过‘--enable-lazy-preload’
参数控制延后加载。 - 创建
zygote
进程通信服务端 SocketmZygoteSocket
,用于监听所有请求和zygote
进程通信的消息。 - 通过
forkSystemServer()
启动system server
进程。
最后调用到 ZygoteServer
中的 runSelectLoop
方法中,一直循环等待其他进程的创建请求。
ZygoteServer.runSelectLoop()
Runnable runSelectLoop(String abiList) {
ArrayList<FileDescriptor> socketFDs = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
socketFDs.add(mZygoteSocket.getFileDescriptor()); // 1
peers.add(null);
while (true) {
boolean usapPoolFDRead = false;
while (--pollIndex >= 0) {
if (pollIndex == 0) { // 2
// Zygote server socket
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
socketFDs.add(newPeer.getFileDescriptor());
} else if (pollIndex < usapPoolEventFDIndex) { // 3
// Session socket accepted from the Zygote server socket
try {
ZygoteConnection connection = peers.get(pollIndex);
final Runnable command = connection.processOneCommand(this);
if (mIsForkChild) {
return command;
} else {
if (connection.isClosedByPeer()) {
connection.closeSocket();
peers.remove(pollIndex);
socketFDs.remove(pollIndex);
}
}
}
} else { // 4
// Either the USAP pool event FD or a USAP reporting pipe.
long messagePayload = -1;
try {
byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];
int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);
if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {
DataInputStream inputStream =
new DataInputStream(new ByteArrayInputStream(buffer));
messagePayload = inputStream.readLong();
}
}
if (pollIndex > usapPoolEventFDIndex) {
Zygote.removeUsapTableEntry((int) messagePayload);
}
usapPoolFDRead = true;
}
}
// Check to see if the USAP pool needs to be refilled.
if (usapPoolFDRead) {
int[] sessionSocketRawFDs =
socketFDs.subList(1, socketFDs.size())
.stream()
.mapToInt(fd -> fd.getInt$())
.toArray();
final Runnable command = fillUsapPool(sessionSocketRawFDs); // 5
if (command != null) {
return command;
}
}
}
}
runSelectLoop()
是一个无限循环,也就是 zygote
进程起来之后会一直在后台等待 socket
消息。在注释 1 处 ZygoteServer
新建了两个 list
, 用于保存所有 ZygoteConnection
和对应 ZygoteSocket
的句柄标识。对应 zygote
进程启动时创建的 mZygoteSocket
连接存放在 index
为 0 的位置,仅用于监听新建连接的消息。
循环里主要是在处理三类 socket
消息:
- 注释2处,这类消息是已有进程 (例如
system server
) 发送给mZygoteSocket
,请求建立新的连接,收到之后zygote
进程会创建SocketConnection
并更新list
。 - 注释3处,这类消息是第一步新建的
SocketConnection
中发来的消息,收到之后zygote
进程通过processOneCommand
处理,这里就是通常应用程序进程创建的入口。(注释2和注释3这个地方比较绕,思考了很久,两眼冒 +_+) -
USAP
类消息处理。USAP
是谷歌在安卓10.0上引进的一种新的进程fork()
机制,借鉴了线程池的思想,通过prefork()
提前创建一批进程,当有进程启动时直接从已创建好的进程中分配,加快应用启动速度。在注释4处通过调用fillUsapPool()
处理这类消息。
总结
zygote
进程启动流程主要包括以下步骤:
- 解析
init.zygotexx.rc
脚本,创建AndroidRuntime
实例,并调用其start()
方法。 - 初始化
JNI
接口、启动JVM
,并通过JNI
调用ZygoteInit.java
中main()
方法,进入到 Java Framework 层。 - 加载
JVM
运行时资源,并创建ZygoteServer
和服务端 Socket 对象。 - 创建
system server
进程,最后进入ZygoteServer.runSelectLoop()
无限循环,等待接收处理 Socket 消息。