在启动Zygote进程的分析中,我们知道其实是通过系统调用fork()函数来创建一个进程,然后执行Zygote.rc中的执行文件,从而开始Zygote进程业务。
本篇文章我们就来分析大名鼎鼎的Zygote进程的流程,前面init进程分析中都是C++代码,本篇文章将逐渐见到我们熟悉的虚拟机以及Java代码。
在Android系统中,Zygote进程非常重要,我们称它为孵化器或者受精卵,因为DVM和ART、应用程序进程以及运行Java Framework系统服务的SystemServer进程都是由Zygote进程来创建的。
通过fork的形式来创建应用进程和SystemServer进程,而且由于Zygote进程在启动时会创建DVM或者ART,因此通过fork而创建的应用程序进程和SystemServer进程可以在内部获取一个DVM或者ART的实例副本。
我们从上篇init进程分析中的启动Zygote来说起,在其中说到解析rc文件时,会先通过fork创建一个进程,然后最终会调用预置脚本的main()函数来开启Zygote进程的业务。
先简单看一下Native层流程图:
既然Zygote进程已经创建,而且已经开始运行,所以我们直接来看一下其业务开始的入口函数:
/frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[])
188 {
189 ...
278 while (i < argc) {
279 const char* arg = argv[i++];
280 if (strcmp(arg, "--zygote") == 0) {
//如果当前运行在Zygote进程中,则将zygote设置为ture
281 zygote = true;
282 niceName = ZYGOTE_NICE_NAME;
283 } else if (strcmp(arg, "--start-system-server") == 0) {
//如果当前运行在SystemServer进程中,则将startSystemServer设置为true
284 startSystemServer = true;
285 ...
296 }
297
298 ...
348
349 if (zygote) {
//启动Zygote进程
350 runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
351 } else if (className) {
352 runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
353 } else {
354 fprintf(stderr, "Error: no class name or --zygote supplied.\n");
355 app_usage();
356 LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
357 }
358}
Zygote进程是通过fork自己来创建子进程的,而fork我们在上一篇文章里说过,它是一个系统调用,其实就是复制自己,这样做可以减少创建进程时进行诸多配置,所以Zygote进程以及它的子进程都可以进入该函数,所以在main函数中要区分当前运行在哪个进程。
由代码中逻辑我们可知会调用runtime的start方法,runtime是AppRuntime类的对象,它是一个C++类:
/frameworks/base/cmds/app_process/app_main.cpp
class AppRuntime : public AndroidRuntime
但是发现该类并没有叫做start的方法,所以其实该方法定义是在其父类里面,我们来看一下:
/frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(const char* className, const Vector& options, bool zygote)
1035 {
1038 ...
//启动Java虚拟机
1067 JniInvocation jni_invocation;
1068 jni_invocation.Init(NULL);
1069 JNIEnv* env;
1070 if (startVm(&mJavaVM, &env, zygote) != 0) {
1071 return;
1072 }
1073 onVmCreated(env);
1074 //注册JNI方法
1078 if (startReg(env) < 0) {
1079 ALOGE("Unable to register all android natives\n");
1080 return;
1081 }
1082
1083 //有了JNI,我们这里就可以调用Java方法了
1088 jclass stringClass;
1089 jobjectArray strArray;
1090 jstring classNameStr;
1091 //由传进来的参数可以知道,Java世界的Zygote初始化类是
//“com.android.internal.os.ZygoteInit”
1092 stringClass = env->FindClass("java/lang/String");
1093 assert(stringClass != NULL);
1094 strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
1095 assert(strArray != NULL);
1096 classNameStr = env->NewStringUTF(className);
1097 assert(classNameStr != NULL);
1098 env->SetObjectArrayElement(strArray, 0, classNameStr);
1099
1100 for (size_t i = 0; i < options.size(); ++i) {
1101 jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
1102 assert(optionsStr != NULL);
1103 env->SetObjectArrayElement(strArray, i + 1, optionsStr);
1104 }
1105
1106 //将className的"."替换为"/"
1110 char* slashClassName = toSlashClassName(className != NULL ? className : "");
1111 jclass startClass = env->FindClass(slashClassName);
1112 if (startClass == NULL) {
1113 ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
1114 /* keep going */
1115 } else {
//找到了ZygoteInit的main方法
1116 jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
1117 "([Ljava/lang/String;)V");
1118 if (startMeth == NULL) {
1119 ALOGE("JavaVM unable to find main() in '%s'\n", className);
1120 /* keep going */
1121 } else {
//调用main方法,开启愉快的Java之旅
1122 env->CallStaticVoidMethod(startClass, startMeth, strArray);
1123
1124#if 0
1125 if (env->ExceptionCheck())
1126 threadExitUncaughtException(env);
1127#endif
1128 }
1129 }
1130 free(slashClassName);
1137}
这个类就是我们之前在说架构时的AndroidRuntime部分代码,它其实是C++代码,在文中都注释了非常明白了,主要做了如下事:
由于ZygoteInit的main方法由Java编写,这样Zygote就从Native层进入了Java框架层。
还是先来看一下大致调用流程图:
`话不多说,我们来看看Java世界的该方法:
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
//新建ZygoteServer实例
699 ZygoteServer zygoteServer = new ZygoteServer();
700
701 ...
747 //创建一个Server端的Socket,socketName就是"zygote"
748 zygoteServer.registerServerSocket(socketName);
749
751 if (!enableLazyPreload) {
752 bootTimingsTraceLog.traceBegin("ZygotePreload");
753 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
754 SystemClock.uptimeMillis());
//预加载资源
755 preload(bootTimingsTraceLog);
756 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
757 SystemClock.uptimeMillis());
758 bootTimingsTraceLog.traceEnd(); // ZygotePreload
759 } else {
760 Zygote.resetNicePriority();
761 }
762
763 ...
780
781 if (startSystemServer) {
//创建和启动SystemServer进程
782 Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
786 if (r != null) {
787 r.run();
788 return;
789 }
790 }
791
792 //等待AMS请求
796 caller = zygoteServer.runSelectLoop(abiList);
797 } catch (Throwable ex) {
798 Log.e(TAG, "System zygote died with exception", ex);
799 throw ex;
800 } finally {
//一直循环,这个只有Zygote进程死了才会执行
801 zygoteServer.closeServerSocket();
802 }
806 if (caller != null) {
807 caller.run();
808 }
809 }
这里简化了很多逻辑,我们只分析一些主要的流程,从上面注释我们可以知道,ZygoteInit的main函数主要做了如下几件事:
1.创建了一个Server端的Socket,该Socket的主要作用就一个,就是等待ActivityManagerService(AMS)的请求,来创建新的进程。关于AMS我们肯定听过,它负责Android四大组件的运行,而其中就有一个场景就是启动新的APP进程,这时就需要创建新进程,而创建新进程的工作就是这里。
2.加载类和资源。
3.孵化和启动SystemServer进程,该进程比较重要,我们熟悉的AMS、WMS等系统服务都是运行在该进程中,后面分析SystemServer进程时,我们再仔细分析。
上面就是Zygote进程在Java层所做的主要工作,我们来简单梳理一下。
主要是通过调用ZygoteServer中的registerServerSocket方法:
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
//新建ZygoteServer实例
699 ZygoteServer zygoteServer = new ZygoteServer();
700
701 ...
747 //创建一个Server端的Socket,socketName就是"zygote"
748 zygoteServer.registerServerSocket(socketName);
749
751 if (!enableLazyPreload) {
752 bootTimingsTraceLog.traceBegin("ZygotePreload");
753 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
754 SystemClock.uptimeMillis());
//预加载资源
755 preload(bootTimingsTraceLog);
756 EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
757 SystemClock.uptimeMillis());
758 bootTimingsTraceLog.traceEnd(); // ZygotePreload
759 } else {
760 Zygote.resetNicePriority();
761 }
762
763 ...
780
781 if (startSystemServer) {
//创建和启动SystemServer进程
782 Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
786 if (r != null) {
787 r.run();
788 return;
789 }
790 }
791
792 //等待AMS请求
796 caller = zygoteServer.runSelectLoop(abiList);
797 } catch (Throwable ex) {
798 Log.e(TAG, "System zygote died with exception", ex);
799 throw ex;
800 } finally {
//一直循环,这个只有Zygote进程死了才会执行
801 zygoteServer.closeServerSocket();
802 }
806 if (caller != null) {
807 caller.run();
808 }
809 }
这里注意创建本地Socket的代码是在ZygoteServer.java中,这个mServerSocket在后面会被使用,等会再说。
在Zygote进程的初始化过程中,会预加载一些必要的资源,方法如下:
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
static void preload(TimingsTraceLog bootTimingsTraceLog) {
123 //预加载类,这里使用类加载器加载/system/ect/preload-class下定义的类
//该文件是一个文本文件,以全包名的方式写了几百个类
128 preloadClasses();
129 //预加载资源,主要是加载一些图片、颜色等资源到内存中
131 preloadResources();
132 //预加载OpenGL
137 preloadOpenGL();
138 //通过System.loadLibrary方式加载3个共享库
//分别是android、compiler_rt、jnigraphics
139 preloadSharedLibraries();
//加载文本等资源
140 preloadTextResources();
141 ...
149 }
这里加载资源非常关键,由前面我们知道到目前Zygote进程已经有虚拟机实例、预加载了部分资源和Java类,以及预加载了共享库,这时创建子进程时,是通过fork形式的,即复制自己,新的进程也会有这些内容。
关于这部分加载类的细节,涉及类加载器、Class类等知识,后面文章会详细分析。
Zygote进程的另一个重要工作就是启动SystemServer进程,我们来看看Java世界中是如何启动进程的:
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static Runnable forkSystemServer(String abiList, String socketName,
621 ZygoteServer zygoteServer) {
622 long capabilities = posixCapabilitiesAsBits(
623 OsConstants.CAP_IPC_LOCK,
624 OsConstants.CAP_KILL,
625 OsConstants.CAP_NET_ADMIN,
626 OsConstants.CAP_NET_BIND_SERVICE,
627 OsConstants.CAP_NET_BROADCAST,
628 OsConstants.CAP_NET_RAW,
629 OsConstants.CAP_SYS_MODULE,
630 OsConstants.CAP_SYS_NICE,
631 OsConstants.CAP_SYS_PTRACE,
632 OsConstants.CAP_SYS_TIME,
633 OsConstants.CAP_SYS_TTY_CONFIG,
634 OsConstants.CAP_WAKE_ALARM
635 );
637 if (!SystemProperties.getBoolean(PROPERTY_RUNNING_IN_CONTAINER, false)) {
638 capabilities |= posixCapabilitiesAsBits(OsConstants.CAP_BLOCK_SUSPEND);
639 }
640 //设置参数
641 String args[] = {
642 "--setuid=1000",
643 "--setgid=1000",
644 "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,1032,3001,3002,3003,3006,3007,3009,3010",
645 "--capabilities=" + capabilities + "," + capabilities,
646 "--nice-name=system_server",
647 "--runtime-args",
648 "com.android.server.SystemServer",
649 };
650 ZygoteConnection.Arguments parsedArgs = null;
651
652 int pid;
653
654 try {
//这里是为了把硬编码的参数转换成特定类对象
655 parsedArgs = new ZygoteConnection.Arguments(args);
656 ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
657 ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
658
659 //fork新进程
660 pid = Zygote.forkSystemServer(
661 parsedArgs.uid, parsedArgs.gid,
662 parsedArgs.gids,
663 parsedArgs.debugFlags,
664 null,
665 parsedArgs.permittedCapabilities,
666 parsedArgs.effectiveCapabilities);
667 } catch (IllegalArgumentException ex) {
668 throw new RuntimeException(ex);
669 }
670
671 //pid为0,说明当前是子进程
672 if (pid == 0) {
673 if (hasSecondZygote(abiList)) {
674 waitForSecondaryZygote(socketName);
675 }
676 //子进程即SystemServer进程不需要监听socket
677 zygoteServer.closeServerSocket();
//SystemServer进程处理它的事务
678 return handleSystemServerProcess(parsedArgs);
679 }
680
681 return null;
682 }
该部分是创建、启动SystemServer进程,首先是用代码来创建args数组,也就是启动参数,从参数我们可以看出SystemServer进程的用户id和用户组id被设置为1000,并且拥有1001-1010、1018、1021、1032、3001-3010用户组的权限;进程名为system_server,启动的类名为com.android.server.SystemServer。
然后通过Zygote类的forkSystemServer函数创建了一个子进程,该方法底层调用了native方法,原理也就是Linux的fork系统调用。然后有个非常有意思的地方,就是pid为0表示是子进程,这里或许有点疑惑,这里是为什么?
这时就要从多进程和fork的含义来理解了,fork的意思是复制,即调用完fork后,新的systemServer进程会有和Zygote进程一样的信息,比如虚拟机、预加载的资源等,那这时就相当于2个进程都运行到这里了,那如何分道扬镳呢 就看这个pid的值,如果是0就说明是运行在子进程中。
这个还是很有意思的,关于Linux的fork系统调用,后面关于Linux知识时,再细说一下。
这个的设计也非常巧妙,runSelectLoop的作用就是从前面创建的Socket服务端中循环取出其他进程发来的消息,当消息结果caller不为空时,执行这个消息。
这里就要想个问题,因为是多进程,执行该方法也可能是其他进程,比如前面刚刚创建的systemServer进程,但是我们还记得创建的systemServer进程已经关闭socket了,所以这里的选择循环会一直运行在Zygote进程中。
该方法代码如下:
/frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
Runnable runSelectLoop(String abiList) {
144 ArrayList fds = new ArrayList();
145 ArrayList peers = new ArrayList();
146 //这个mServerSocket就是前面创建的服务端Socket
147 fds.add(mServerSocket.getFileDescriptor());
148 peers.add(null);
149 //无限循环等待AMS请求Zygote进程创建新的应用进程。
150 while (true) {
151 StructPollfd[] pollFds = new StructPollfd[fds.size()];
152 for (int i = 0; i < pollFds.length; ++i) {
153 pollFds[i] = new StructPollfd();
154 pollFds[i].fd = fds.get(i);
155 pollFds[i].events = (short) POLLIN;
156 }
157 try {
158 Os.poll(pollFds, -1);
159 } catch (ErrnoException ex) {
160 throw new RuntimeException("poll failed", ex);
161 }
162 for (int i = pollFds.length - 1; i >= 0; --i) {
163 if ((pollFds[i].revents & POLLIN) == 0) {
164 continue;
165 }
166 //i等于0,说明服务端Socket和客户端连接上了,即Zygote进程和AMS建立了链接
167 if (i == 0) {
168 ZygoteConnection newPeer = acceptCommandPeer(abiList);
169 peers.add(newPeer);
170 fds.add(newPeer.getFileDesciptor());
171 } else {
172 try {
173 ZygoteConnection connection = peers.get(i);
//会创建子进程
174 final Runnable command = connection.processOneCommand(this);
176 if (mIsForkChild) {
179 if (command == null) {
180 throw new IllegalStateException("command == null");
181 }
183 return command;
184 } else {
186 if (command != null) {
187 throw new IllegalStateException("command != null");
188 }
193 if (connection.isClosedByPeer()) {
194 connection.closeSocket();
195 peers.remove(i);
196 fds.remove(i);
197 }
198 }
199 } catch (Exception e) {
200 ...
222 }
223 }
224 }
225 }
226 }
这里说明了一种进程通信方式,即Zygote进程和AMS所在的进程(systemServer进程)的通信方式是Socket,关于这部分细节内容,等后面创建应用进程时再细说。
在Java层的Zygote进程流程分析中,涉及了如下几个Java类,这里简单总结一下:
Zygote进程作为开启Java世界大门的重要进程,简单总结一下其启动流程和作用:
在Native层:
1.创建Java虚拟机,这也是Android系统能运行Java代码的底层原因。
2.注册JNI函数,赋能JNI功能,JNI可以让Java和C++代码互相调用。
3.通过JNI功能,调用Java世界的ZygoteInit的main函数,开启Java的业务。
在Java层:
1.创建了本地Socket服务,并且循环监听,该服务的作用是和AMS所在的SystemServer进程通信,用来创建用户应用进程。这个而从另一方面也就说明了,Zygote进程和SystemServer进程的通信是Socket,在后面我们会介绍Android中大名鼎鼎的Binder通信。
2.预加载资源,包括类、图片资源等,这样的好处就是fork的新进程,就会持有这些信息。
3.创建和启动SystemServer进程,该进程管理和运行着我们熟悉的Java Framework中的各种服务。
Android Framework知识点学习手册:https://qr18.cn/AQpN4J