[toc]
基于 Android 7.1.1 源码,分析进程的创建!
1 前言
当 Android 系统在启动一个应用进程时,如果发现某个进程没有创建,那就要先创建这个进程, Android 系统中每一个应用进程,包括 SystemServer 进程都是由 Zygote 直接孵化出来的!
本片文章,就来总结下进程的 fork 流程!
2 Process - prepare fork
我们来继续看:
2.1 Process.start
框架层开始创建进程会调用 Process.start 方法,我们进入这个方法来看看:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String[] zygoteArgs) {
try {
//【1】这里是进入 Zygote 方法了!
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
2.2 Process.startViaZygote
我们接着来看,进入了:startViaZygote 方法,参数传递:
- final String processClass,
- final String niceName,
- final int uid,
- final int gid,
- final int[] gids,
- int debugFlags,
- int mountExternal,
- int targetSdkVersion,
- String seInfo,
- tring abi,
- String instructionSet,
- String appDataDir,
- String[] extraArgs
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
104private 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,
String abi,
String instructionSet,
String appDataDir,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
//【1】创建 cmd 命令libeia!
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {
argsForZygote.add("--enable-jni-logging");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
argsForZygote.add("--enable-safemode");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
argsForZygote.add("--enable-debugger");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
argsForZygote.add("--enable-checkjni");
}
if ((debugFlags & Zygote.DEBUG_GENERATE_DEBUG_INFO) != 0) {
argsForZygote.add("--generate-debug-info");
}
if ((debugFlags & Zygote.DEBUG_ALWAYS_JIT) != 0) {
argsForZygote.add("--always-jit");
}
if ((debugFlags & Zygote.DEBUG_NATIVE_DEBUGGABLE) != 0) {
argsForZygote.add("--native-debuggable");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
argsForZygote.add("--enable-assert");
}
if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
argsForZygote.add("--mount-external-default");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
argsForZygote.add("--mount-external-read");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
argsForZygote.add("--mount-external-write");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
//TODO optionally enable debuger
//argsForZygote.add("--enable-debugger");
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
if (instructionSet != null) {
argsForZygote.add("--instruction-set=" + instructionSet);
}
if (appDataDir != null) {
argsForZygote.add("--app-data-dir=" + appDataDir);
}
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
//【2.3】接着调用 zygoteSendArgsAndGetResult 方法,让爱更进一步!
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
这个的过程是生成 argsForZygote 数组,里面分装了 Zygote 需要的参数!!
2.2.1 Process.openZygoteSocketIfNeeded
这里调用了 openZygoteSocketIfNeeded 方法,根据当前的 abi 选择 Zygote 的位数:32 位还是 64 位的,然后连接 Zygote,并返回 Zygote 的引用对象:
1 | private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx { |
我们接着下面来看!
2.3 Process.zygoteSendArgsAndGetResult
最后,发送参数列表给 Zygote 进程,Zygote 进程会 fork 一个子进程,并返回子进程的 pid!
1 | private static ProcessStartResult zygoteSendArgsAndGetResult( |
这个方法的主要功能:通过 socket 向 Zygote 进程发送一个参数列表,然后进入阻塞等待状态,直到远端的 Socket 服务端发送回来新创建的进程 pid 才返回!!
以上这些过程仍然在 SystemServer 进程中,接下来,就要进入 Zygote 进程了!!!
3 Zygote - fork Process
3.1 ZygoteInit.main
接着是,进入了 Zygote 进程,我们先去看看 Zygote 的 main 方法看看:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public static void main(String argv[]) {
ZygoteHooks.startZygoteNoThreadCreation();
try {
... ... ...// 这部分代码是启动 Zygote 时触发的,这个省略不看!
Log.i(TAG, "Accepting command socket connections");
//【3.2】进入 runSeletLoop 方法!
runSelectLoop(abiList);
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
//【3.4】上面的 runSelectLoop 方法会抛出 MethodAndArgsCaller 异常就会进入 caller.run 方法
// 我们后面再看!
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
接着来看,进入了 runSelectLoop 方法,runSelectLoop 是一个死循环,不断的读取发送到 Zygote 的消息!
3.2 ZygoteInit.runSelectLoop
这个方法很关键,在 openZygoteSocketIfNeeded 方法中,System Sever 会通过 Socket 建立和 Zygote 进程的连接,并向 Zygote 写入执行参数!
而 ZygoteInit.runSelectLoop 会创建一个循环,不断的读取 abiList 中的指令,进行处理!
1 | private static void runSelectLoop(String abiList) throws MethodAndArgsCaller { |
没有连接请求时会进入休眠状态,当有创建新进程的连接请求时,唤醒 Zygote 进程,创建 Socket 通道 ZygoteConnection,然后执行 ZygoteConnection 的 runOnce() 方法。
3.3 ZygoteConnection.runOnce
这里我们看到 runOnce 方法会抛出一个 MethodAndArgsCaller 异常,但实际上 MethodAndArgsCaller 并不是在 runOnce 中抛出的!
1 | boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { |
3.3.1 Zygote.forkAndSpecialize - fork 子进程核心阶段
这里开始 Fork 子进程!!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
String instructionSet, String appDataDir) {
//【3.3.1.1】fork 前的准备工作
VM_HOOKS.preFork();
//【3.3.1.2】这里是 fork 子进程,调用了一个 naitve 方法。这个方法会返回 2 次!
int pid = nativeForkAndSpecialize(
uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
instructionSet, appDataDir);
if (pid == 0) {
// 监控子进程,直到 handleChildProc 结束!
Trace.setTracingEnabled(true);
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
}
//【3.3.1.3】fork 结束后的相关操作!
VM_HOOKS.postForkCommon();
return pid;
}
这里有一变量:
1 | private static final ZygoteHooks VM_HOOKS = new ZygoteHooks(); |
nativeForkAndSpecialize 方法会返回 2 次,一次 pid 为 0,表示是在子进程中;一次 pid 大于 0,表示是在 Zygote 进程中,意味着,postForkCommon 会执行 2 次!
接着来看:
3.3.1.1 ZygoteHooks.preFork - fork 准备工作
ZygoteHooks 的源码位于:D:\google\libcore\dalvik\src\main\java\dalvik\system\ZygoteHooks.java
1 | public void preFork() { |
3.3.1.1.1 Daemons.stop
1 | public static void stop() { |
Zygote 是有 4 个子线程的,这里是需要停止这四个子线程,为 fork 操作空出资源来!
此处守护线程 Stop 方式是先调用目标线程 interrrupt 方法,然后再调用目标线程 join 方法,等待线程执行完成。
3.3.1.1.2 ZygoteHooks.waitUntilAllThreadsStopped
1 | private static void waitUntilAllThreadsStopped() { |
3.3.1.1.3 ZygoteHooks.nativePreFork
nativePreFork 通过 JNI 最终调用的是 dalvik_system_ZygoteHooks.cc 中的 ZygoteHooks_nativePreFork() 方法,如下:
1 | static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) { |
可以看出:ZygoteHooks.preFork 方法主要的作用是:停止 Zygote 的停止这四个子线程,确保 fork 进程时,Zygote 是单线程的,同时初始化 gc 堆!!
ZygoteHooks_nativePreFork
3.3.1.1.3.1 Runtime:nativePreFork
1 | void Runtime::PreZygoteFork() { |
3.3.1.2 Zygote.nativeForkAndSpecialize - fork 子进程
调用这个方法 nativeForkAndSpecialize 来进行 fork 进程!
1 | native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int debugFlags, |
这是一个本地方法,最后调用的是 com_android_internal_os_Zygote_nativeForkAndSpecialize 方法,位于 frameworks\base\core\jni\com_android_internal_os_Zygote.cpp 中:
1 | static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( |
接着,继续调用:ForkAndSpecializeCommon 方法,继续 fork!
1 | static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids, |
Zygote 进程是所有 Android 进程的母体,包括 system_server 进程以及 App 进程都是由 Zygote 进程孵化而来。
zygote 利用 fork() 方法生成新进程,对于新进程 A 复用 Zygote 进程本身的资源,再加上新进程 A 相关的资源,构成新的应用进程 A 。
关于 native bridge,我没有过多研究,大家可以看看这个博客:
https://blog.csdn.net/sinat_38172893/article/details/73274591
3.3.1.2.1 Zygote.CallPostForkChildHooks - 子进程调用
上面通过反射再次调用了 Zygote 的 CallPostForkChildHooks 方法:
1 | private static void callPostForkChildHooks(int debugFlags, boolean isSystemServer, |
这边有调用了 ZygoteHooks 的 postForkChild 方法:
3.3.1.2.1.1 ZygoteHooks.postForkChild
这个方法是在 Zygote fork 出的子进程中调用的!!
1 | public void postForkChild(int debugFlags, boolean isSystemServer, String instructionSet) { |
我们可以看到,这里传入了一个 token,这是是一个 long 型的值,用来保存线程的类型,在前面:1
3.3.1.1.3 ZygoteHooks.nativePreFork
nativePreFork 会将 Zygote 主线程的类型转换为 long 型,保存到 ZygoteHooks.token 中!
3.3.1.2.1.2 ZygoteHooks.nativePostForkChild
我们继续看:1
2private static native void nativePostForkChild(long token, int debugFlags,
boolean isSystemServer, String instructionSet);
这是一个 navtive 方法,最终调用 “\art\runtime\native\dalvik_system_ZygoteHooks.cc” 的 ZygoteHooks_nativePostForkChild 方法:
1 | static void ZygoteHooks_nativePostForkChild(JNIEnv* env, |
这里我们主要分析下,非 SystemServer 子进程的逻辑处理,对于 SystemServer 进程的处理,请看开机启动流程文章内容!
3.3.1.2.1.3 Runtime.InitNonZygoteOrPostFork
1 | void Runtime::InitNonZygoteOrPostFork( |
3.3.1.3 ZygoteHooks.postForkCommon - fork 结束
这个方法会在父进程 Zygote 和子进程中各调用一次,也就是说,在父进程 Zygote 中是恢复 4 个 Daemon 线程,而在子进程中,是启动 4 个 Daemon 线程!
1 | public void postForkCommon() { |
3.3.1.3.1 Daemons.start
ZygoteHooks.postForkCommon 方法很简单,启动 4 个 Daemon 线程,java堆整理,引用队列,以及析构线程。
1 | public static void start() { |
3.3.1.4 阶段总结
首先来看看调用函数流程:
1 | Zygote.forkAndSpecialize |
这个流程很清楚啦,不都说了啦,嘿嘿嘿!
3.3.2 ZygoteConncection.handleChildProc - 子进程处理
我们知道,Zygote.forkAndSpecialize 会返回 2 次,当返回值为 0 时,进入子进程: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
42private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller { // 抛出异常!
//【1】进程创建完毕,关闭 Socket 连接!
closeSocket();
ZygoteInit.closeServerSocket();
if (descriptors != null) {
try {
Os.dup2(descriptors[0], STDIN_FILENO);
Os.dup2(descriptors[1], STDOUT_FILENO);
Os.dup2(descriptors[2], STDERR_FILENO);
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
newStderr = System.err;
} catch (ErrnoException ex) {
Log.e(TAG, "Error reopening stdio", ex);
}
}
if (parsedArgs.niceName != null) {
//【2】设置进程的 niceName
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 {
//【3.3.2.1】看前面的参数传递,parsedArgs.invokeWith 为 null,进入这个分支!
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
我们继续看:
3.3.2.1 RuntimeInit.zygoteInit
1 | public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) |
啦啦啦啦啦
3.3.2.1.1 RuntimeInit.commonInit - 进程通用初始化
进程的通用初始化:
1 | private static final void commonInit() { |
3.3.2.1.2 RuntimeInit.nativeZygoteInit - 进程本地初始化
nativeZygoteInit 是一个 native 方法:
1 | private static final native void nativeZygoteInit(); |
显然这是一个 native 方法,对应的 native 方法为 com_android_internal_os_RuntimeInit_nativeZygoteInit 方法,位于 AndroidRuntime.cpp 文件中:1
2
3
4
5static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
//【1】调用了运行时的 onZygoteInit 方法!
gCurRuntime->onZygoteInit();
}
接着,进入 App_main.cpp 文件中:1
2
3
4
5
6
7
8
9virtual void onZygoteInit()
{
//【1】获得当前进程的 ProcessState 对象!!
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
//【2】创建一个新的 Binder 线程,不断的 talkWithDriver!!
proc->startThreadPool();
}
这里的 ProcessState 对象是一个单例模式,他会打开 /dev/binder 驱动设备,分配内核空间,然后 start 一个 binder 线程,不断地 talkWithDriver,用于进行进程间通信!
3.3.2.1.3 RuntimeInit.applicationInit - 初始化进程的 Application 对象
这里很重要,初始化进程的 Application 对象!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
29private 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);
//【1】设置 java 堆内存的利用率为 75%,以及目标 sdk 平台的版本!
VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
final Arguments args;
try {
//【2】解析参数!
args = new Arguments(argv);
} catch (IllegalArgumentException ex) {
Slog.e(TAG, ex.getMessage());
return;
}
//【3】结束对子进程的监控!
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//【3.3.2.1.3.1】进一步解析参数,执行 startClass 类的 main 方法!!
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
这里有人要问了,这个 startClass 是什么类,此处 args.startClass 为 “android.app.ActivityThread”。
3.3.2.1.3.1 RuntimeInit.invokeStaticMain
1 | private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader) |
这里通过反射,获得了 ActivityThread.main 方法,然后创建了一个异常:MethodAndArgsCaller,抛了出去!
这个异常会通过 ZygoteConnection.runOnce 方法传递出去,进入了 ZygoteInit.main 方法,那里会对这个异常进行 catch 并处理!
3.3.3 ZygoteConncection.handleParentProc - 父进程处理
当 fork 的返回值大于 0,那就进入父进程 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
48
49
50
51
52
53
54
55
56
57
58
59
60private boolean handleParentProc(int pid,
FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
//【1】判断一下返回值,若大于 0,说明 fork 成功,
// 设置子进程的 pgid!
if (pid > 0) {
//【*3.3.3.1】设置进程的 pgid!
setChildPgid(pid);
}
if (descriptors != null) {
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
}
boolean usingWrapper = false;
if (pipeFd != null && pid > 0) {
DataInputStream is = new DataInputStream(new FileInputStream(pipeFd));
int innerPid = -1;
try {
innerPid = is.readInt();
} catch (IOException ex) {
Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
} finally {
try {
is.close();
} catch (IOException ex) {
}
}
// Ensure that the pid reported by the wrapped process is either the
// child process that we forked, or a descendant of it.
if (innerPid > 0) {
int parentPid = innerPid;
while (parentPid > 0 && parentPid != pid) {
parentPid = Process.getParentPid(parentPid);
}
if (parentPid > 0) {
Log.i(TAG, "Wrapped process has pid " + innerPid);
pid = innerPid;
usingWrapper = true;
} else {
Log.w(TAG, "Wrapped process reported a pid that is not a child of "
+ "the process that we forked: childPid=" + pid
+ " innerPid=" + innerPid);
}
}
}
try {
mSocketOutStream.writeInt(pid);
mSocketOutStream.writeBoolean(usingWrapper);
} catch (IOException ex) {
Log.e(TAG, "Error writing to command socket", ex);
return true;
}
return false;
}
3.3.3.1 setChildPgid
设置 fork 出的进程的 pgid:
1 | private void setChildPgid(int pid) { |
3.4 MethodAndArgsCaller.run - 处理异常
MethodAndArgsCaller 类位于 ZygoteInit.java 中:
1 | public static class MethodAndArgsCaller extends Exception |
这里就正式进入了新进程的 ActivityThread.main 方法,我们知道 ActivityThread.main 是应用程序进程的入口,到这里就将从 native 进入 java 层了,进行进一步的进程启动!
4 总结
4.1 通信方式总结
可以看出,主要有以下的两种通信方式:Binder 和 Socket !!
- 启动方进程 -> SystemServer 进程: Binder
- SystemServer 进程 -> Zygote 进程:Socket
- Zygote 进程 -> 被启动进程:Socket
主要的流程图如下:
4.2 调用流程总结
UML 序列图先埋坑,以后再填。。
[1]: