[译]Zygote

原文地址:Zygote https://anatomyofandroid.com/2013/10/15/zygote/

Zygote(受精卵)是一个启动应用的守护进程,在Server Manager之后被init.rc触发,但其实他是真正被app_process启动的,下面是启动这个特殊进程的流程。

1
2
3
4
5
6
7
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd

你可以发现Zygote是如何当做系统服务启动的,你也可以看到app_process为什么说app_process是启动Zygote的真正命令。就像之前说的,Zygote是一个以专门启动应用为的守护进程。这意味着Zygote是所有App进程的父进程。当app_process启动Zygote时,它通过调用Zygote的main()方法创建了第一个Dalvik虚拟机。当Zygote启动后,zygote会预加载所有必须的Java类和资源,启动System Server并打开一个名为/dev/socket/zygote的socket服务,去监听所有启动应用的请求。 想之前的文章所说,System Server 是一个和它的父进程完全分离的进程。一旦System Server创建完成,它会初始化一系列不同的System Services并启动Activity Manager。那Zygote是如何启动新的应用的呢?

Zygote 通过/dev/socket/zygote(一个sockete Socket Server)接收启动应用的请求,就会触发一次fork()调用,会在另一个存储空间创建一个自身的拷贝。这个过程是很高效的。当Zygote执行fork时,它会精准创建一个预加载了应用进程所需的所有必要类和资源的Dalvik虚拟机,这样就会把创建虚拟机和加载资源的过程变得很高效。但这个设计不仅仅是这样。由于Android运行在Linux内核上,Linux Kernal实现了一个叫做Copy On Write(COW)的策略,在fork进程的过程中并不会真正的拷贝内存。一个进程想要修改这个共享的内存是,kernel会拦截这个请求,并对要修改的内存做一个拷贝。当一些Android的类库是不可写的情况下,那就意味着所有从Zygote fork出来的进程都在共享一份系统类文件和资源。另一个好处就是真的节省内存。不管启动多少应用进程在内存的增长上都会小很多。

If you are in an early stage of a porting process, Zygote is another big process that you don’t need to start. You can disable it by adding the keyword “disabled” at the end of the boot sequence in init.rc

1
2
3
4
5
6
7
8
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
disabled

下面是一张说明Zygote在Android平台中作用的关系图(from Embedded Android)。

zygote的main()方法:

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
public static void main(String argv[]) {
try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();

registerZygoteSocket();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());

// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();

// Do an initial gc to clean up after startup
gc();

// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);

// If requested, start system server directly from Zygote
if (argv.length != 2) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}

if (argv[1].equals("start-system-server")) {
startSystemServer();
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}

Log.i(TAG, "Accepting command socket connections");

runSelectLoop();

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

通过下面代码可以看到Zygote是如何启动System Server的。

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
/**
* Prepare the arguments and fork for the system server process.
*/
private static boolean startSystemServer()
throws MethodAndArgsCaller, RuntimeException {
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003,3006,3007",
"--capabilities=130104352,130104352",
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;

int pid;

try {
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);

/* Request to fork the system server process */
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) {
handleSystemServerProcess(parsedArgs);
}

return true;
}

转载请标明出处病已blog https://ivonhoe.github.io/