JasonWang's Blog

Zygote进程启动过程详解

字数统计: 4.3k阅读时长: 23 min
2017/05/27

与Java程序类似,Android应用程序框架层(Application Framework)以及APP运行在一个Dalvik Virtual Machine之上,那么,Android启动时框架层是如何初始化的,从何处初始化的?为此,Android在启动时会首先初始化一个专门的系统进程zygote来负责启动与初始化Java代码,比如系统服务进程system_server的启动,系统启动时各种Java服务的初始化,APP资源文件的加载,APP进程的创建与启动。这篇文章,主要讲zygote进程的两个问题:

  • zygote进程如何初始化的;
  • APP进程是如何通过zygote创建的?

本文基于Android NN7.0

zygote进程的初始化

kernel初始化完成后,Android启动的第一个进程是init(pid = 0),此后启动的进程都是init进程的子进程;init进程在启动时,会解析init.rc脚本中的语句,以此来启动某个进程或者执行某个动作。

脚本init.zygotexx.rc(xx是不同平台的字长,有32/64两种)负责启动系统服务zygote

1
2
3
4
5
6
7
8
9
10
11
12

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 audioserver
onrestart restart cameraserver
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks

这里:

  • service表示该进程是一个系统服务进程;
  • zygote是该进程的名字;
  • /system/bin/app_process是进程代码所在的文件路径;
  • -Xzygote /system/bin --zygote --start-system-server: 是进程启动参数,单杠-是符号参数
  • socket zygote stream 660 root system: 创建一个/dev/socket/zygote的socket,zygote会监听该socket,一旦有APP进程启动请求即fork一个进程;
  • onrestart: 表示只要该service重启,就执行后面的动作。就是说,zygote服务重启的话,会重启audioserver,cameraserver等系统服务;
  • writepid: 属于服务所需要执行的函数,zygote进程fork完成后,将其PID写入该参数对应的文件;

init进程解析该脚本语句,通过Service.cpp中的函数start来启动zygote进程:

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

bool Service::Start() {

if (flags_ & SVC_RUNNING) {
return false;
}
....
NOTICE("Starting service '%s'...\n", name_.c_str());

pid_t pid = fork();
// 进程创建成功
if (pid == 0) {
umask(077);
// 创建socket
for (const auto& si : sockets_) {
int socket_type = ((si.type == "stream" ? SOCK_STREAM :
(si.type == "dgram" ? SOCK_DGRAM :
SOCK_SEQPACKET)));
const char* socketcon =
!si.socketcon.empty() ? si.socketcon.c_str() : scon.c_str();

int s = create_socket(si.name.c_str(), socket_type, si.perm,
si.uid, si.gid, socketcon);
if (s >= 0) {
PublishSocket(si.name, s);
}
}
// 保存PID到文件
std::string pid_str = StringPrintf("%d", getpid());
for (const auto& file : writepid_files_) {
if (!WriteStringToFile(pid_str, file)) {
ERROR("couldn't write %s to %s: %s\n",
pid_str.c_str(), file.c_str(), strerror(errno));
}
}

setpgid(0, getpid());
....
// 执行app_process二进制代码中的main函数
if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
ERROR("cannot execve('%s'): %s\n", strs[0], strerror(errno));
}

_exit(127);
}

if (pid < 0) {
ERROR("failed to start '%s'\n", name_.c_str());
pid_ = 0;
return false;
}

time_started_ = gettime();
pid_ = pid;
flags_ |= SVC_RUNNING;


NotifyStateChange("running");
return true;
}

执行app_main.cpp中的main函数,其中的argv[]是一个{-Xzygote,/system/bin,--zygote,--start-system-server}的字符串指针数组; 解析参数后,通过AppRuntime加载ZygoteInit类:

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


int main(int argc, char* const argv[])
{
// 运行时执行环境,加载JAVA代码
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
// Process command line arguments; ignore argv[0]
argc--;
argv++;

int i;
for (i = 0; i < argc; i++) {
if (argv[i][0] != '-') {
break;
}
if (argv[i][1] == '-' && argv[i][2] == 0) {
++i; // Skip --.
break;
}
// 保存-Xzygote参数
runtime.addOption(strdup(argv[i]));
}

// Parse runtime arguments. Stop at first unrecognized option.
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++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} 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 {
--i;
break;
}
}

Vector<String8> args;
if (!className.isEmpty()) {
runtime.setClassNameAndArgs(className, argc - i, argv + i);
} else {
// We're in zygote mode.
if (startSystemServer) {
args.add(String8("start-system-server"));
}
....
// 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模式,加载ZygoteInit类,这里的args为"start-system-server"
if (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;
}
}


代码: /android/frameworks/base/cmds/app_process/app_main.cpp

由于AppRuntime继承了AndroidRuntime,调用AndroidRuntime.start():创建一个VM实例,并注册系统JNI,然后调用ZygoteInit的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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
....
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
// 创建一个VM实例
if (startVm(&mJavaVM, &env, zygote) != 0) {
return;
}
onVmCreated(env);

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

jclass stringClass;
jobjectArray strArray;
jstring classNameStr;

stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);

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);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
} else {
// 获取main函数ID
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 {
// 调用main函数
env->CallStaticVoidMethod(startClass, startMeth, strArray);
}
}
free(slashClassName);

ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}


调用ZygoteInit.main, 监听来自客户端的请求;在子进程中,runSelectLoop会抛出一个MethodAndArgsCaller异常,该异常被捕获后,会去调用应用的入口方法ActivityThread.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

public static void main(String argv[]) {
/* set default handler; this applies to all threads in the VM */
RuntimeInit.__init__UncaughtHandler();

try {
//启动Android调试工具DDMS(Dalvik Debug Monitor Server)
RuntimeInit.enableDdms();

boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
primaryZygoteThreadRunning=true;
}
....
}
Log.i(TAG, "!@Zygote : primaryZygoteThreadRunning = " + primaryZygoteThreadRunning + " ZygoteAgentRunning = " + zygoteAgentRunning);
// 注册一个/dev/sockete/zyogote的socket,将其与一个FileDescriptor进行绑定
registerZygoteSocket(socketName);
// 预加载资源、共享库
preload();
// 启动system_server进程
if (startSystemServer) {
startSystemServer(abiList, socketName);
}
// 不断监听socket接口连接请求,子进程创建完成后,会抛出MethodAndArgsCaller异常
runSelectLoop(abiList);
// 如果进程退出,需要关闭zygote的socket
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}


runSelectLoop不断监听来自客户端的请求,如果有,则创建一个ZygoteConnection用于处理来自客户端的请求,负责解析应用启动的参数,调用fork启动一个新的进程,然后加载应用代码:

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

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;
}
// 监听socket端口,如果有请求则返回
try {
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
// 初始状态,pollFds只有一个服务端socket对应的fd
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
// acceptCommandPeer阻塞调用,直到有来自客户端的请求
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);
}
}
}
}
}


// acceptCommandPeer返回一个请求对应的ZygoteConnection用于读取socket中的数据
private static ZygoteConnection acceptCommandPeer(String abiList) {
try {
return new ZygoteConnection(sServerSocket.accept(), abiList);
} catch (IOException ex) {
throw new RuntimeException(
"IOException during accept()", ex);
}
}

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

boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;

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;
}

....

/**
* In order to avoid leaking descriptors to the Zygote child,
* the native code must close the two Zygote socket descriptors
* in the child process before it switches from Zygote-root to
* the UID and privileges of the application being launched.
*
* In order to avoid "bad file descriptor" errors when the
* two LocalSocket objects are closed, the Posix file
* descriptors are released via a dup2() call which closes
* the socket and substitutes an open descriptor to /dev/null.
*/

int [] fdsToClose = { -1, -1 };

FileDescriptor fd = mSocket.getFileDescriptor();

if (fd != null) {
fdsToClose[0] = fd.getInt$();
}

fd = ZygoteInit.getServerSocketFileDescriptor();

if (fd != null) {
fdsToClose[1] = fd.getInt$();
}

fd = null;
// 调用本地方法fork一个新的进程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.category, parsedArgs.accessInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir, parsedArgs.mountKnoxPoint);
} 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进程就启动完成了。接下来我们就来看一看,有APP启动时,zygote进程如何创建新的应用进程的?

zygote创建新的应用进程

在Activity启动过程中,如果当前应用尚未启动过,进程不存在,AMS(Activity Manager Service)会为应用启动一个新的进程:

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


private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
....

try {
final int userId = UserHandle.getUserId(app.uid);
....
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.

Process.ProcessStartResult startResult = null;

if(userid>0 && (bbcId>0 && userid == bbcId) && app.info.bbcseinfo!=null){
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.bbcseinfo, app.info.bbccategory, app.info.accessInfo,
requiredAbi, instructionSet,
app.info.dataDir, mountKnoxPoint, entryPointArgs);
}else {
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, aasaSeInfo != null ? new String(aasaSeInfo) : app.info.seinfo, //AASA--4 : changed orginal : only "app.info.seinfo"
app.info.category, app.info.accessInfo,
requiredAbi, instructionSet,
app.info.dataDir, mountKnoxPoint, entryPointArgs);
}
} catch(RemoteException re){
//
}

}


调用Process.start()启动一个新的进程:

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


public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
int category,
int accessInfo,
String abi,
String instructionSet,
String appDataDir,
boolean mountKnoxPoint,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo, category, accessInfo,
abi, instructionSet, appDataDir, mountKnoxPoint, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}


通过zygote创建一个新的进程:

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


private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
int category,
int accessInfo,
String abi,
String instructionSet,
String appDataDir,
boolean mountKnoxPoint,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
ArrayList<String> argsForZygote = new ArrayList<String>();

// 添加启动参数
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
....
// 进程名
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
....
argsForZygote.add(processClass);

if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
// openZygoteSocketIfNeeded 连接socket
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}

将启动进程所需的参数通过/dev/socket/zygote发送给zygote进程,并将创建的PID返回:

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


private static ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {

/**
* See com.android.internal.os.ZygoteInit.readArgumentList()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
*/
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;

writer.write(Integer.toString(args.size()));
writer.newLine();

for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);
writer.newLine();
}
// 写入socket
writer.flush();

// Should there be a timeout on this?
ProcessStartResult result = new ProcessStartResult();

// Always read the entire result from the input stream to avoid leaving
// bytes in the stream for future process starts to accidentally stumble
// upon.
result.pid = inputStream.readInt();
result.usingWrapper = inputStream.readBoolean();

if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}


在之前分析zygote启动时,我们了解到,每当有进程创建请求时,都会通过runSelectLoop函数创建一个ZygoteConnectionZygoteConnecton中的runOnce()函数负责将进程启动的参数写入到socket,并着手创建新的进程,创建完成后将子进程PID写回到socket:

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


boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {

String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;

try {
// 从Socket中读取数据
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
closeSocket();
return true;
}
....
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;

try {
parsedArgs = new Arguments(args);

if (parsedArgs.abiListQuery) {
return handleAbiListQuery();
}
....
/**
* In order to avoid leaking descriptors to the Zygote child,
* the native code must close the two Zygote socket descriptors
* in the child process before it switches from Zygote-root to
* the UID and privileges of the application being launched.
*
* In order to avoid "bad file descriptor" errors when the
* two LocalSocket objects are closed, the Posix file
* descriptors are released via a dup2() call which closes
* the socket and substitutes an open descriptor to /dev/null.
*/

int [] fdsToClose = { -1, -1 };

FileDescriptor fd = mSocket.getFileDescriptor();

if (fd != null) {
fdsToClose[0] = fd.getInt$();
}

fd = ZygoteInit.getServerSocketFileDescriptor();

if (fd != null) {
fdsToClose[1] = fd.getInt$();
}

fd = null;
// 创建进程,并返回
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.category, parsedArgs.accessInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir, parsedArgs.mountKnoxPoint);
} 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) {
// 子进程继承了zygote进程的FD,需要关闭
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;
// 将子进程PID写入socket
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}


调用zygote.forkAndSpecialize创建进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, int mountExternal, String seInfo, int category, int accessInfo, String niceName, int[] fdsToClose,String instructionSet, String appDataDir, int mountKnoxPoint) {
VM_HOOKS.preFork();
// 调用native方法创建进程
int pid = nativeForkAndSpecialize(
uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, category, accessInfo, niceName, fdsToClose,
instructionSet, appDataDir, mountKnoxPoint);
// Enable tracing as soon as possible for the child process.
if (pid == 0) {
Trace.setTracingEnabled(true);

// Note that this event ends at the end of handleChildProc,
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
}
VM_HOOKS.postForkCommon();
return pid;
}

找到forkAndSpecialize对应的native方法,实际是创建一个Linux进程,子进程与父进程拥有共同的内存空间,至此一个应用的进程就创建完成了。但此时应用本身的代码还没有加载。

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


static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
jint debug_flags, jobjectArray javaRlimits,
jlong permittedCapabilities, jlong effectiveCapabilities,
jint mount_external,
jstring java_se_info, jint category, jint accessInfo, jstring java_se_name,
bool is_system_server, jintArray fdsToClose,
jstring instructionSet, jstring dataDir, jint mountKnoxPoint) {
SetSigChldHandler();
....
sigset_t sigchld;
sigemptyset(&sigchld);
sigaddset(&sigchld, SIGCHLD);
....
// 创建进程
pid_t pid = fork();

if (pid == 0) {
// The child process.
gMallocLeakZygoteChild = 1;

// Clean up any descriptors which must be closed immediately
DetachDescriptors(env, fdsToClose);
....
if (!is_system_server) {
int rc = createProcessGroup(uid, getpid());
if (rc != 0) {
if (rc == -EROFS) {
ALOGW("createProcessGroup failed, kernel missing CONFIG_CGROUP_CPUACCT?");
} else {
ALOGE("createProcessGroup(%d, %d) failed: %s", uid, pid, strerror(-rc));
}
}
}
....
// VM post fork for child process
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
is_system_server, instructionSet);
if (env->ExceptionCheck()) {
RuntimeAbort(env, __LINE__, "Error calling post fork hooks.");
}
} else if (pid > 0) {
// the parent process
....
}
return pid;
}


Android中的native方法所在文件命名是由Java包名基础上加上Java文件名组成,例如nativeForkAndSpecialize所在类zygote.java对应的包名为com.android.internal.os,那么其该native方法对应的文件为com_android_internal_os_zygote.cpp

最后在新的子进程中,需要对APP进程的执行环境进行初始化,调用RuntimeInit.zygoteInit对APP进行初始化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr) throws ZygoteInit.MethodAndArgsCaller {
....
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}

// End of the postFork event.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
VMRuntime.getCurrentInstructionSet(),
pipeFd, parsedArgs.remainingArgs);
} else {
//初始化运行时执行环境, 这里的remainingArgs实际是每个APP的入口`android.app.ActivityThread`
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}


zygoteInit主要负责如下几件事情:

  • 通用初始化commonInit(): 设置未捕获异常的处理函数;设置默认时区;
  • VM本地初始化nativeZygoteInit()
  • 应用初始化applicationInit(): 这里正是APP代码加载的地方;
1
2
3
4
5
6
7
8
9
10
11
12
13
14

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
redirectLogStreams();

commonInit();
nativeZygoteInit();
applicationInit(targetSdkVersion, argv, classLoader);
}


方法applicationInit在设置完堆内存的使用率(可能引发GC)和应用目标SDK后;通过invokeStaticMain抛出一个MethodAndArgsCaller异常的方式调用ActivityThread.main,这样这个应用就算加载完成了。这篇文章旨在梳理zygote进程的一些逻辑,有关某个具体应用的加载流程请参考:Android Phone进程启动过程分析

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


private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
// If the application calls System.exit(), terminate the process
// immediately without running any shutdown hooks. It is not possible to
// shutdown an Android application gracefully. Among other things, the
// Android runtime shutdown hooks close the Binder driver, which can cause
// leftover running threads to crash before the process actually exits.
nativeSetExitWithoutCleanup(true);

// We want to be fairly aggressive about heap utilization, to avoid
// holding on to a lot of memory that isn't needed.
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

final Arguments args;
try {
args = new Arguments(argv);
} catch (IllegalArgumentException ex) {
Slog.e(TAG, ex.getMessage());
// let the process exit
return;
}

// The end of of the RuntimeInit event (see #zygoteInit).
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

// Remaining arguments are passed to the start class's static main
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}

原文作者:Jason Wang

更新日期:2021-08-11, 15:02:45

版权声明:本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可

CATALOG
  1. 1. zygote进程的初始化
  2. 2. zygote创建新的应用进程