Android 启动过程简析(二)之 zygote 进程

前言

Android启动过程简析(一)中我们已经分析过了 init 进程是如何被启动的,本篇文章将会继续分析 zygote 启动过程以及作用。

zygote 启动过程

zygote 进程创建之后会首先进入到 app_main.cpp 的 main 函数当中去,所以首先对 app_main 进行分析

app_main 分析

frameworks/base/cmds/app_process/app_main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
int main(int argc, char* const argv[])
{
...
//创建 AppRuntime 对象
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
...

// 解析运行时参数,当遇到无法识别的选项时停止
bool zygote = false;
bool startSystemServer = false;
bool application = false;
String8 niceName;
String8 className;

++i; // Skip unused "parent dir" argument.
while (i < argc) {
const char* arg = argv[i++];
//如果传入的参数有 ”--zygote“ 则将 zygote 置为 true
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
//如果传入的参数有 "--start-system-server" 则将 startSystemServer 置为 true
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
niceName.setTo(arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
className.setTo(arg);
break;
} else {
--i;
break;
}
}

Vector<String8> args;
//非 zygote 模式处理
if (!className.isEmpty()) {
// We're not in zygote mode, the only argument we need to pass
// to RuntimeInit is the application argument.
//
// The Remainder of args get passed to startup class main(). Make
// copies of them before we overwrite them with the process name.
args.add(application ? String8("application") : String8("tool"));
runtime.setClassNameAndArgs(className, argc - i, argv + i);
} else {
//zygote 模式下的处理
maybeCreateDalvikCache();

//如果 startSystemServer 为 true 则将 "start-system-server" 添加到 args
if (startSystemServer) {
args.add(String8("start-system-server"));
}

char prop[PROP_VALUE_MAX];
if (property_get(ABI_LIST_PROPERTY, prop, NULL) == 0) {
LOG_ALWAYS_FATAL("app_process: Unable to determine ABI list from property %s.",
ABI_LIST_PROPERTY);
return 11;
}

String8 abiFlag("--abi-list=");
abiFlag.append(prop);
args.add(abiFlag);

// In zygote mode, pass all remaining arguments to the zygote
// main() method.
for (; i < argc; ++i) {
args.add(String8(argv[i]));
}
}

if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string());
set_process_name(niceName.string());
}

//如果 zygote 为 true 则启动 zygote
if (zygote) {
//通过 runtime 对象启动 zygote
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
app_usage();
LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
return 10;
}
}

可以看到在 main 函数中首先创建了一个 AppRuntime 对象,然后就会根据传入的参数对一些标志位进行相应的置位,这里值得注意的一个标志位是 startSystemServer,上文说过 Android 5.0 之后系统可能会启动两个 zygote 进程,而 SystemServer 只需要启动一次,所以通过这个标志位控制只在启动主 zygote 进程的时候将 "start-system-server" 增加到 args,然后则会通过 AppRuntime 的 start 函数调用 Java 层的 zygote 代码。

AndroidRuntime 分析

由于 AppRuntime 继承自 AndroidRuntime,所以想要了解系统是如何调用 Java 层的 zygote 代码则需要继续了解 AndroidRuntime 的 start 函数

1
class AppRuntime : public AndroidRuntime

AndroidRuntime 位于 frameworks/base/core/jni

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/*
* Start the Android runtime. This involves starting the virtual machine
* and calling the "static void main(String[] args)" method in the class
* named by "className".
*
* Passes the main function two arguments, the class name and the specified
* options string.
*/
void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...

static const String8 startSystemServer("start-system-server");

/*
* 'startSystemServer == true' means runtime is obsolete and not run from
* init.rc anymore, so we print out the boot start event here.
*/
for (size_t i = 0; i < options.size(); ++i) {
//只有 startSystemServer == true,options 才会有 start-system-server
if (options[i] == startSystemServer) {
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = 3000;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START, ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
}

...

//const char* kernelHack = getenv("LD_ASSUME_KERNEL");
//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);

/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
//创建启动 DVM
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);

/*
* Register android functions.
*/
//注册 JNI 方法
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}

/*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*/
//将 options 转化为 java 中的 String 数组
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;

stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
//创建对象数组,类型为 stringClass(即 String 类型),长度为 options.size() + 1
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);

//将 options 逐个增加到对象数组当中
for (size_t i = 0; i < options.size(); ++i) {
jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
assert(optionsStr != NULL);
env->SetObjectArrayElement(strArray, i + 1, optionsStr);
}

/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className);
//寻找类名为 slashClassName 的类
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
//查找 main 方法,([Ljava/lang/String;)V 是 main 方法的签名
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 {
//调用 startClass 类当中的 main 方法,传入参数 strArray
env->CallStaticVoidMethod(startClass, startMeth, strArray);

#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
...
}

通过 start 函数的注释我们可以大致了解到 start 函数的主要作用是启动虚拟机和名为 classname 的 main 方法

而上文可以知道,传入的 classname 是 "com.android.internal.os.ZygoteInit" 。那么整个的执行流程就是:

首先会判断传递进来的参数是否存在 "start-system-server" ,如果存在则会输出启动日志,然后会通过 startVm 函数创建启动 DVM,在启动 DVM 之后会通过 startReg 函数注册 JNI 方法,在注册完毕之后会将传入的 options 参数转换为 Java 的对象数组,而之所以需要转换成对象数组是因为在于 options 需要作为 main 方法的参数传入,之后再通过传入的 className 去获得 jclass 对象,并根据 main 方法的 JNI 签名得到 jmethodID,最终通过CallStaticVoidMethod 方法完成 main 方法的调用。

ZygoteInit 分析

frameworks/base/core/java/com/android/internal/os

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public static void main(String argv[]) {
...
String socketName = "zygote";
...

try {
...
//注册 socket
registerZygoteSocket(socketName);
...
//预加载类和资源
preload();
...
if (startSystemServer) {
//创建 SystemServer 进程
startSystemServer(abiList, socketName);
}

...
//等待客户端请求
runSelectLoop(abiList);
...

closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}

整个 main 方法的执行流程是:首先通过 registerZygoteSocket 方法对 socket 进行了注册,注册的 socket 用于和 ActivityManagerService 进行通信,然后调用 preload 方法对类和资源进行加载,之后则会调用 startSystemServer 创建 SystemServer 进程,最后通过 runSelectLoop 等待来自 ActivityManagerService 的请求。

这里最为关键的是 socket 以及创建 SystemServer 进程,所以我们需要进一步了解这两个部分。

注册 Socket 过程

首先是注册 Socket 部分, registerZygoteSocket 主要是利用文件描述符创建了一个 LocalServerSocket 对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private static void registerZygoteSocket(String socketName) {
if (sServerSocket == null) {
int fileDesc;
//socket 名为 ANDROID_SOCKET_zygote
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}

try {
FileDescriptor fd = new FileDescriptor();
fd.setInt$(fileDesc);
//创建 LocalServerSockt
sServerSocket = new LocalServerSocket(fd);
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}

启动 SystemServer

startSystemServer 主要工作是对设置的参数进行解析,然后通过 forkSystemServer 创建 SystemServer 进程,最后在 SystemServer 进程中调用 handleSystemServerProcess 方法处理剩余工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
...
/* Hardcoded command line to start the system server */
//设置 uid 为 1000,设置 gid 为 1000,启动 com.android.server.SystemServer
String args[] = {
"--setuid=1000",
"--setgid=1000",
/// M: ANR mechanism for system_server add shell(2000) group to access
/// /sys/kernel/debug/tracing/tracing_on
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,2000," +
"3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;

int pid;

try {
//对 args 进行解析
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

/* Request to fork the system server process */
//创建 SystemServer 进程
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}

/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}

//处理 SystemServer 进程剩余工作
handleSystemServerProcess(parsedArgs);
}

return true;
}

监听客户端的请求

runSelectLoop 的主要工作是通过 ZygoteConnection 的 acceptCommandPeer 方法监听客户端的请求,然后调用 runOnce 方法对来自客户端的请求进行处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();

fds.add(sServerSocket.getFileDescriptor());
peers.add(null);

//循环处理连接请求
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
Os.poll(pollFds, -1);//无限等待能够进行 I/O 操作
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
for (int i = pollFds.length - 1; i >= 0; --i) {
//说明没有来自客户端的连接请求或数据处理请求
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {//处理来自客户端的连接请求
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done = peers.get(i).runOnce();//处理客户端数据处理请求,创建对应的进程
if (done) {//处理完毕则进行移除
peers.remove(i);
fds.remove(i);
}
}
}
}
}

处理客户端请求

对于 runOnce 而言主要做的工作是从连接中读取参数,然后根据参数创建相应的进程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

String args[];
Arguments parsedArgs = null;
...

try {
args = readArgumentList();//读取参数
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
Log.w(TAG, "IOException on command socket " + ex.getMessage());
closeSocket();
return true;
}

if (args == null) {
// EOF reached.
closeSocket();
return true;
}

...

try {
parsedArgs = new Arguments(args);//构造 Arguments 对象

...
//创建进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir);
} catch (ErrnoException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (IllegalArgumentException ex) {
logAndPrintError(newStderr, "Invalid zygote arguments", ex);
} catch (ZygoteSecurityException ex) {
logAndPrintError(newStderr,
"Zygote security policy prevents request: ", ex);
}

try {
if (pid == 0) {
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
//进入子进程的处理流程
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);

// should never get here, the child is expected to either
// throw ZygoteInit.MethodAndArgsCaller or exec().
return true;
} else {
// in parent...pid of < 0 means failure
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}

总结

到这里我们大致能够知晓 Zygote 进程的启动过程和主要作用了:

  1. 系统在启动 Zygote 的过程中首先启动了虚拟机,然后通过 JNI 调用了 ZygoteInit 中的 main 方法,由此系统从 C++ 的 FrameWork 层到了 Java 的 FrameWork 层,之后在则注册了用于和 ActvityManagerService 通信的 Socket,完成注册之后则会调用 startSystemServer 启动 SystemServer 进程,最后 Zygote 进程将会通过 runSelectLoop 对来自客户端的连接进行监听。
  2. 总的来说 Zygote 的主要作用启动 SystemServer 进程以及根据客户端的连接创建相应的进程。

Thanks

  1. Android系统启动流程(二)解析Zygote进程启动过程
  2. Android系统启动-zygote篇