赞
踩
内容预览.png
本文(基于Android O源码)主要讲解Zygote进程创建流程,线程容易创建,但进程的相关的东西都被系统很好的封装了,以至于进程的创建,很多人还是头一回。首先一张图来看看Zygote进程在系统中的地位。
Zygote的地位.png
Zygote进程又称受精卵进程,它由app_process启动,Zygote进程最大意义是作为一个Socket的Server端,接收着四面八方的进程创建请求,Android中所有的应用进程的创建都是一个应用进程通过Binder请求SystemServer进程,SystemServer进程发送socket消息给Zygote进程,统一由Zygote进程创建出来的。典型的C/S架构!!!。图中红色标注为Binder通信方式,蓝色标注为Socket通信方式。
话说为什么Android系统采用这种架构呢,为什么所有进程的创建都是由Zygote来做呢?原因有如下几点
Zygote进程在启动的时候会创建一个虚拟机实例,因此通过Zygote进程在父进程,创建的子进程都会继承这个虚拟机实例,App中的JAVA代码可以得到翻译执行。
进程与进程之间需要跨进程通信,由Zygote进程作为父进程还可以获得一个Binder线程池,这样进程之间就可以使用Binder进行跨进程通信了。
进程的“血液”可以理解成Message,启动四大组件靠的都是Looper消息机制,看过老罗的书,说由Zygote进程作为父进程,子进程可以获得一个消息循环。这句话我表示不理解,因为各个应用进程的Looper循环是自己在ActivityThread中创建的,SystemServer进程的消息循环也是自己创建的,那为什么说子进程可以继承Zygote进程的消息循环呢?这点我觉得不严谨,欢迎讨论。
所以这可以理解成Zygote进程作为所有应用进程的父进程的原因。
1、进入JAVA的世界,ZygoteInit的main方法
SystemServer进程的创建.png
这张序列图就是Zygote进程的创建流程,结合代码看一看。
- frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
- public static void main(String argv[]) {
- //1、创建ZygoteServer
- ZygoteServer zygoteServer = new ZygoteServer();
- .......
- try {
- .......
- boolean startSystemServer = false;
- String socketName = "zygote";
- String abiList = null;
- boolean enableLazyPreload = false;
- // 2、解析app_main.cpp传来的参数
- for (int i = 1; i < argv.length; i++) {
- if ("start-system-server".equals(argv[i])) {
- startSystemServer = true;
- } else if ("--enable-lazy-preload".equals(argv[i])) {
- enableLazyPreload = true;
- } else if (argv[i].startsWith(ABI_LIST_ARG)) {
- abiList = argv[i].substring(ABI_LIST_ARG.length());
- } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
- socketName = argv[i].substring(SOCKET_NAME_ARG.length());
- } else {
- throw new RuntimeException("Unknown command line argument: " + argv[i]);
- }
- }
-
- if (abiList == null) {
- throw new RuntimeException("No ABI list supplied.");
- }
- //3、创建一个Server端的Socket
- zygoteServer.registerServerSocket(socketName);
- // In some configurations, we avoid preloading resources and classes eagerly.
- // In such cases, we will preload things prior to our first fork.
- if (!enableLazyPreload) {
- bootTimingsTraceLog.traceBegin("ZygotePreload");
- EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
- SystemClock.uptimeMillis());
- //4、加载进程的资源和类
- preload(bootTimingsTraceLog);
- EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
- SystemClock.uptimeMillis());
- bootTimingsTraceLog.traceEnd(); // ZygotePreload
- } else {
- Zygote.resetNicePriority();
- }
- ........
- if (startSystemServer) {
- //5、开启SystemServer进程,这是受精卵进程的第一次分裂
- startSystemServer(abiList, socketName, zygoteServer);
- }
-
- Log.i(TAG, "Accepting command socket connections");
- //6、启动一个死循环监听来自Client端的消息
- zygoteServer.runSelectLoop(abiList);
- //7、关闭SystemServer的Socket
- zygoteServer.closeServerSocket();
- } catch (Zygote.MethodAndArgsCaller caller) {
- //8、这里捕获这个异常调用MethodAndArgsCaller的run方法。
- caller.run();
- } catch (Throwable ex) {
- Log.e(TAG, "System zygote died with exception", ex);
- zygoteServer.closeServerSocket();
- throw ex;
- }
- }

ZygoteInit的main方法大概就做了上面六件事情,一,创建ZygoteServer,在Android O上把与Socket的操作都封装到了ZygoteServer类中;二,解析app_main.cpp传来的参数。三、创建一个Server端的Socket,作用是当Zygote进程将SystemServer进程启动后,就会在这个Socket上来等待ActivityManagerService请求,即请求创建我们自己APP应用程序进程;四,预加载类和资源,包括颜色啊,R文件,drawable、类等;五,启动system_server进程,这是上层framework的运行载体,ActivityManagerService就是运行在这个进程里面的;六,开启一个循环,等待着接收ActivityManagerService的请求,随时待命,当接收到创建新进程的请求时立即唤醒并执行相应工作;
我觉得这段代码的主线是,ZygoteInit进程启动后,会注册一个Socket,在runSelectLoop方法中开启一个while死循环等待ActivityManagerService创建新进程的请求,其次,ZygoteInit启动了SystemServer进程,执行SystemServer的main方法。
这种模式其实可以理解成一个模板格式的代码,不信你在看看WebViewZygoteInit中的写法和ZygoteInit的写法是不是如出一辙呢?
- frameworks/base/core/java/com/android/internal/os/WebViewZygoteInit.java
- public static void main(String argv[]) {
- sServer = new WebViewZygoteServer();
-
- // Zygote goes into its own process group.
- try {
- Os.setpgid(0, 0);
- } catch (ErrnoException ex) {
- throw new RuntimeException("Failed to setpgid(0,0)", ex);
- }
-
- try {
- sServer.registerServerSocket("webview_zygote");
- sServer.runSelectLoop(TextUtils.join(",", Build.SUPPORTED_ABIS));
- sServer.closeServerSocket();
- } catch (Zygote.MethodAndArgsCaller caller) {
- caller.run();
- } catch (RuntimeException e) {
- Log.e(TAG, "Fatal exception:", e);
- }
-
- System.exit(0);
- }

如果要理解的更深一点,就需要再思考几个问题了。
好,现在解答这些问题,这些问题弄懂,Zygote进程创建流程也就OK了。
1.1、ZygoteInit方法是怎么调用的
从上面的流程图中看到ZygoteInit的main是从app_main.cpp来的。app_main是Zygote进程对应的主文件,Zygote进程被Init启动的时候,就会调用这个app_main.cpp的main函数。
- /frameworks/base/cmds/app_process/app_main.cpp
- 192int main(int argc, char* const argv[])
- 193{
- ......
- 282 // Parse runtime arguments. Stop at first unrecognized option.
- 283 bool zygote = false;
- 284 bool startSystemServer = false;
- 285 bool application = false;
- 286 String8 niceName;
- 287 String8 className;
- 288
- 289 ++i; // Skip unused "parent dir" argument.
- //init.rc中会配置一些参数,这里进行比较设置一些变量走进不同的分支
- 290 while (i < argc) {
- 291 const char* arg = argv[i++];
- 292 if (strcmp(arg, "--zygote") == 0) {
- //启动的是Zygote进程
- 293 zygote = true;
- 294 niceName = ZYGOTE_NICE_NAME;
- 295 } else if (strcmp(arg, "--start-system-server") == 0) {
- //启动的是system-server进程
- 296 startSystemServer = true;
- 297 } else if (strcmp(arg, "--application") == 0) {
- 298 application = true;
- 299 } else if (strncmp(arg, "--nice-name=", 12) == 0) {
- 300 niceName.setTo(arg + 12);
- 301 } else if (strncmp(arg, "--", 2) != 0) {
- 302 className.setTo(arg);
- 303 break;
- 304 } else {
- 305 --i;
- 306 break;
- 307 }
- 308 }
- 309
- .......
- //设置一个“好听的名字” zygote,之前的名称是app_process
- 357 if (!niceName.isEmpty()) {
- 358 runtime.setArgv0(niceName.string(), true /* setProcName */);
- 359 }
- 360
- 361 if (zygote) {
- //通过runtime启动zygote
- 364 runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
- 365 } else if (className) {
- 366 runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
- 367 } else {
- 368 fprintf(stderr, "Error: no class name or --zygote supplied.\n");
- 369 app_usage();
- 370 LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
- 371 }
- 372}

Zygote本身是一个Native的应用程序,刚开始的名字为“app_process”,运行过程中,通过调用setArgv0将名字改为Zygote,真正启动的地方是runtime的start方法,简单看一下runtime的start方法。
- /*
- 987 * Start the Android runtime. This involves starting the virtual machine
- 988 * and calling the "static void main(String[] args)" method in the class
- 989 * named by "className".
- 990 *
- 991 * Passes the main function two arguments, the class name and the specified
- 992 * options string.
- 993 */
- 994void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
- 995{
- 996 ALOGD(">>>>>> START %s uid %d <<<<<<\n",
- 997 className != NULL ? className : "(unknown)", getuid());
- 998
- 1026 /* start the virtual machine */
- 1027 JniInvocation jni_invocation;
- 1028 jni_invocation.Init(NULL);
- 1029 JNIEnv* env;
- 1030 if (startVm(&mJavaVM, &env, zygote) != 0) {
- 1031 return;
- 1032 }
- 1033 onVmCreated(env);
- 1034
- 1035 /*
- 1036 * Register android functions.
- 1037 */
- 1038 if (startReg(env) < 0) {
- 1039 ALOGE("Unable to register all android natives\n");
- 1040 return;
- 1041 }
- 1042
- 1043 /*
- 1044 * We want to call main() with a String array with arguments in it.
- 1045 * At present we have two arguments, the class name and an option string.
- 1046 * Create an array to hold them.
- 1047 */
- 1048 jclass stringClass;
- 1049 jobjectArray strArray;
- 1050 jstring classNameStr;
- 1051
- 1052 stringClass = env->FindClass("java/lang/String");
- 1053 assert(stringClass != NULL);
- 1054 strArray = env->NewObjectArray(options.size() + 1, stringClass, NULL);
- 1055 assert(strArray != NULL);
- 1056 classNameStr = env->NewStringUTF(className);
- 1057 assert(classNameStr != NULL);
- 1058 env->SetObjectArrayElement(strArray, 0, classNameStr);
- 1059
- 1060 for (size_t i = 0; i < options.size(); ++i) {
- 1061 jstring optionsStr = env->NewStringUTF(options.itemAt(i).string());
- 1062 assert(optionsStr != NULL);
- 1063 env->SetObjectArrayElement(strArray, i + 1, optionsStr);
- 1064 }
- 1065
- 1066 /*
- 1067 * Start VM. This thread becomes the main thread of the VM, and will
- 1068 * not return until the VM exits.
- 1069 */
- 1070 char* slashClassName = toSlashClassName(className);
- 1071 jclass startClass = env->FindClass(slashClassName);
- 1072 if (startClass == NULL) {
- 1073 ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
- 1074 /* keep going */
- 1075 } else {
- 1076 jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
- 1077 "([Ljava/lang/String;)V");
- 1078 if (startMeth == NULL) {
- 1079 ALOGE("JavaVM unable to find main() in '%s'\n", className);
- 1080 /* keep going */
- 1081 } else {
- 1082 env->CallStaticVoidMethod(startClass, startMeth, strArray);
- 1083
- 1084#if 0
- 1085 if (env->ExceptionCheck())
- 1086 threadExitUncaughtException(env);
- 1087#endif
- 1088 }
- 1089 }
- 1090 free(slashClassName);
- 1091 //这行Log比较常见,因为其他应用进程也是由zygote 进程fork 出来的,所有其他进程也包含这段代码,如果其他进程在java 层crash,那么也会走到这里
- 1092 ALOGD("Shutting down VM\n");
- 1093 if (mJavaVM->DetachCurrentThread() != JNI_OK)
- 1094 ALOGW("Warning: unable to detach main thread\n");
- 1095 if (mJavaVM->DestroyJavaVM() != 0)
- 1096 ALOGW("Warning: VM did not shut down cleanly\n");
- 1097}
- 1098

代码很简单,主要做了三件事情,一调用startVm开启虚拟机,二调用startReg注册JNI方法,三就是使用JNI把Zygote进程启动起来。
- 996 ALOGD(">>>>>> START %s uid %d <<<<<<\n",
- 997 className != NULL ? className : "(unknown)", getuid());
这个是进入Zygote进程的重要依据,开机的时候一般都会打印这一行Log。如
- 07-09 14:40:37.788 16504 16504 D AndroidRuntime: >>>>>> START com.android.internal.os.ZygoteInit uid 0 <<<<<<
如果遇到不能开机的情况,这行Log没有打开,极有可能不是上层的问题。
1.2、Socket是怎么注册的?
这个问题还用说嘛,看一下ZygoteServer类的registerServerSocket不就OK了吗,不要觉得这里很容易,其实彻底弄明白还是需要一些思考的。
- frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
- private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
-
- private LocalServerSocket mServerSocket;
- /**
- * Registers a server socket for zygote command connections
- *
- * @throws RuntimeException when open fails
- */
- void registerServerSocket(String socketName) {
- //看起来是用了一个单例
- if (mServerSocket == null) {
- int fileDesc;
- final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
- try {
- //从环境变量中获取名为ANDROID_SOCKET_zygote的fd
- String env = System.getenv(fullSocketName);
- fileDesc = Integer.parseInt(env);
- } catch (RuntimeException ex) {
- throw new RuntimeException(fullSocketName + " unset or invalid", ex);
- }
-
- try {
- //构建JAVA中的FD对象
- FileDescriptor fd = new FileDescriptor();
- fd.setInt$(fileDesc);
- //用上面的FD创建LocalServerSocket
- mServerSocket = new LocalServerSocket(fd);
- } catch (IOException ex) {
- throw new RuntimeException(
- "Error binding to local socket '" + fileDesc + "'", ex);
- }
- }
- }
-

其中 参数 socketName = "zygote";注册的过程实际上就是生成一个mServerSocket对象,用来接收Client端的请求,这里又有两个小问题了。
我们先看第二个问题,看看下面这张图。
Android Socket通信框架.png
LocalSocket就是作为客户端建立于服务端的连接,发送数据。LocalServerSocket作为服务端使用,建立服务端的socket监听客户端请求。典型的C/S架构!!!LocalServerSocket构造函数看到有两种方式:
第一种
- frameworks/base/core/java/android/net/LocalServerSocket.java
- /**
- * Creates a new server socket listening at specified name.
- * On the Android platform, the name is created in the Linux
- * abstract namespace (instead of on the filesystem).
- *
- * @param name address for socket
- * @throws IOException
- */
- public LocalServerSocket(String name) throws IOException
- {
- //1、创建服务端socket对象
- impl = new LocalSocketImpl();
-
- impl.create(LocalSocket.SOCKET_STREAM);
-
- //2、设置地址
- localAddress = new LocalSocketAddress(name);
- //3、绑定地址
- impl.bind(localAddress);
- //4、监听
- impl.listen(LISTEN_BACKLOG);
- }

第二种
- /**
- * Create a LocalServerSocket from a file descriptor that's already
- * been created and bound. listen() will be called immediately on it.
- * Used for cases where file descriptors are passed in via environment
- * variables
- *
- * @param fd bound file descriptor
- * @throws IOException
- */
- public LocalServerSocket(FileDescriptor fd) throws IOException
- {
- impl = new LocalSocketImpl(fd);
- impl.listen(LISTEN_BACKLOG);
- localAddress = impl.getSockAddress();
- }
从上面看到在Zygote中创建服务端的socket,使用的就是第二种。对于这种C/S架构,一般性的用法是这样子的。通常服务端会有个死循环不断响应客户端发送来的请求
- //创建socket并绑定监听 新创建的
- LocalServerSocket server = new LocalServerSocket(SOCKET_ADDRESS);
- while (true) {
- //等待建立连接
- LocalSocket receiver = server.accept();
-
- //接收获取数据流
- InputStream input = receiver.getInputStream();
-
- ……
- }
然后,客户端就可以用下面代码向服务端发送请求
- String message;
-
- //创建socket
- LocalSocket sender = new LocalSocket();
-
- //建立对应地址连接
- sender.connect(new LocalSocketAddress(SOCKET_ADDRESS));
-
- //发送写入数据
- sender.getOutputStream().write(message.getBytes());
-
- //关闭socket
- sender.getOutputStream().close();
在系统创建进程的时候,为了更好的管理LocalSocket的输入流和输出流对象,将这个过程的返回结果封装成了ZygoteState,都在ZygoteProcess的connect方法中。
- frameworks/base/core/java/android/os/ZygoteProcess.java
- public static ZygoteState connect(String socketAddress) throws IOException {
- DataInputStream zygoteInputStream = null;
- BufferedWriter zygoteWriter = null;
- final LocalSocket zygoteSocket = new LocalSocket();
-
- try {
- zygoteSocket.connect(new LocalSocketAddress(socketAddress,
- LocalSocketAddress.Namespace.RESERVED));
-
- zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
-
- zygoteWriter = new BufferedWriter(new OutputStreamWriter(
- zygoteSocket.getOutputStream()), 256);
- } catch (IOException ex) {
- try {
- zygoteSocket.close();
- } catch (IOException ignore) {
- }
-
- throw ex;
- }
-
- String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
- Log.i("Zygote", "Process: zygote socket " + socketAddress + " opened, supported ABIS: "
- + abiListString);
-
- return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
- Arrays.asList(abiListString.split(",")));
- }
-

好,上面基本就是Android中socket通信框架。主要把握LocalSocket与LocalServerSocket的用法。现在继续研究第一个问题,FD是在哪里创建的呢,为什么可以从环境变量中获取呢。Socket的监听方式为使用Linux系统调用select()函数监听Socket文件描述符,当该文件描述符上有数据时,自动触发中断,在中断处理函数中去读取文件描述符中的数据。
在关机状态下,我们可以看到dev/socket的文件有
- android:/dev/socket # ls -la
- total 0
- drwxr-xr-x 2 root root 160 1970-12-23 09:50 .
- drwxr-xr-x 14 root root 3440 1970-12-23 09:49 ..
- srw-rw---- 1 system system 0 1970-12-23 09:50 adbd
- srw-rw-rw- 1 root root 0 1970-12-23 09:49 property_service
- srw-rw---- 1 system system 0 1970-12-23 09:49 thermal-recv-client
- srw-rw-rw- 1 system system 0 1970-12-23 09:49 thermal-recv-passive-client
- srw-rw-rw- 1 system system 0 1970-12-23 09:49 thermal-send-client
- srw-rw---- 1 system system 0 1970-12-23 09:49 thermal-send-rule
开机状态下呢
- jason:/dev/socket # ls -la
- total 0
- drwxr-xr-x 7 root root 840 2018-07-09 19:24 .
- drwxr-xr-x 14 root root 3660 1970-12-23 06:29 ..
- srw-rw---- 1 system system 0 2018-07-09 19:24 adbd
- srw-rw-rw- 1 system system 0 1970-12-23 06:29 audio_hw_socket
- srw-rw---- 1 root mount 0 1970-12-23 06:28 cryptd
- srw-rw---- 1 root inet 0 2018-07-09 16:05 dnsproxyd
- srw-rw---- 1 root system 0 2018-07-09 16:05 dpmd
- srw-rw---- 1 root inet 0 2018-07-09 16:05 dpmwrapper
- srw-rw---- 1 root inet 0 2018-07-09 16:05 fwmarkd
- srw-rw---- 1 system radio 0 2018-07-09 16:05 ims_datad
- srw-rw---- 1 system radio 0 1970-12-23 06:29 ims_qmid
- srw-rw---- 1 radio radio 0 2018-07-09 16:05 ipacm_log_file
- srw-rw---- 1 system system 0 1970-12-23 06:29 lmkd
- srw-rw-rw- 1 logd logd 0 1970-12-23 06:28 logd
- srw-rw-rw- 1 logd logd 0 1970-12-23 06:28 logdr
- s-w--w--w- 1 logd logd 0 1970-12-23 06:28 logdw
- srw-rw---- 1 root system 0 2018-07-09 16:05 mdns
- srw-rw-rw- 1 gps gps 0 2018-07-09 16:05 mlid
- srw-rw---- 1 root system 0 2018-07-09 16:05 netd
- drwxr-x--- 2 radio radio 60 2018-07-09 16:05 netmgr
- srw-rw---- 1 system system 0 1970-12-23 06:29 pps
- srw-rw-rw- 1 root root 0 1970-12-23 06:28 property_service
- drwxrws--- 2 media audio 40 1970-12-23 06:29 qmux_audio
- drwxrws--- 2 bluetooth bluetooth 40 1970-12-23 06:29 qmux_bluetooth
- drwxrws--- 2 gps gps 40 1970-12-23 06:29 qmux_gps
- drwxrws--- 2 radio radio 120 2018-07-09 16:05 qmux_radio
- srw-rw---- 1 radio system 0 2018-07-09 16:05 rild-debug2
- srw-rw---- 1 root radio 0 2018-07-09 16:05 rild2
- srw-rw-rw- 1 system system 0 2018-07-09 16:05 seempdw
- srw-rw---- 1 root inet 0 2018-07-09 16:05 tcm
- srw-rw---- 1 system system 0 1970-12-23 06:29 thermal-recv-client
- srw-rw-rw- 1 system system 0 1970-12-23 06:29 thermal-recv-passive-client
- srw-rw-rw- 1 system system 0 1970-12-23 06:29 thermal-send-client
- srw-rw---- 1 system system 0 1970-12-23 06:29 thermal-send-rule
- srw-rw-rw- 1 system system 0 2018-07-09 16:05 tombstoned_crash
- srw-rw-rw- 1 system system 0 2018-07-09 16:05 tombstoned_intercept
- srw-rw-rw- 1 system system 0 2018-07-09 16:05 tombstoned_java_trace
- srw-rw---- 1 root mount 0 1970-12-23 06:28 vold
- srw-rw---- 1 webview_zygote system 0 2018-07-09 16:05 webview_zygote
- srw-rw---- 1 wifi wifi 0 2018-07-09 16:05 wpa_wlan0
- srw-rw---- 1 root system 0 1970-12-23 06:29 zygote
- srw-rw---- 1 root system 0 1970-12-23 06:29 zygote_secondary

最后两行是不是多了一个zygote和zygote_secondary呢?这两个是怎么来的呢,这个就得从init.rc文件了,内核启动完成之后会去读取init.rc文件,启动开机需要启动的进程。
在Android5.0中,Zygote的启动发生了一些变化,以前直接放在init.rc中的代码块放到了单独的文件中,在init.rc中通过import的方式引入文件,如下:
import /init.${ro.zygote}.rc
所以init.rc并不是直接引入某个固定的文件,而是根据属性“ro.zygote”的内容来引入system/core/init/目录下不同的文件,这个目录下目前有Init.zygote64.rc,Init.zygote32.rc,Init.zygote32_64.rc,Init.zygot64_32.rc。与之对应的属性 ro.zygote 的值可为:zygote32、zygote64、zygote32_64、zygote64_32。
init.zygote32.rc:zygote 进程对应的执行程序是 app_process (纯 32bit 模式)
init.zygote64.rc:zygote 进程对应的执行程序是 app_process64 (纯 64bit 模式)
init.zygote32_64.rc:启动两个 zygote 进程 (名为 zygote 和 zygote_secondary),对应的执行程序分别是 app_process32 (主模式)、app_process64。
init.zygote64_32.rc:启动两个 zygote 进程 (名为 zygote 和 zygote_secondary),对应的执行程序分别是 app_process64 (主模式)、app_process32。
什么意思呢?举个例子看zygot64_32.rc。
- service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
- class main
- priority -20
- user root
- group root readproc
- 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
- onrestart restart wificond
- writepid /dev/cpuset/foreground/tasks
-
- service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote --socket-name=zygote_secondary --enable-lazy-preload
- class main
- priority -20
- user root
- group root readproc
- socket zygote_secondary stream 660 root system
- onrestart restart zygote
- writepid /dev/cpuset/foreground/tasks

其中
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
这行表示zygote进程以服务的方式启动,对应的native应用程序是/system/bin/app_process64,给这个zygote进程传递了5个参数,分别是-Xzygote,/system/bin,--zygote,--start-system-server,--socket-name=zygote。可以看到zygot64_32.rc里面定义了两个Zygote服务:zygote和zygote_secondary。zygote为主,zygote_secondary为辅。
- onrestart restart cameraserver
- onrestart restart media
- onrestart restart netd
- onrestart restart wificond
onrestart后面跟的Zygote重启需要执行的命令,audioserver,cameraserver,media,netd,wificond,当Zygote进程重启了,这些进程都会重启。
socket zygote stream 660 root system
这行表示Zygote进程在启动过程中,会在dev/socket目录下创建一个Socket,权限为660,表示所有的用户都可以对他进行读写,当init 解析到这样一条语句,它将做下面两件事:
- system/core/init/descriptors.cpp
-
- 45#define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_"
- 46#define ANDROID_SOCKET_DIR "/dev/socket"
-
- 50void DescriptorInfo::CreateAndPublish(const std::string& globalContext) const {
- 51 // Create
- 52 const std::string& contextStr = context_.empty() ? globalContext : context_;
- 53 int fd = Create(contextStr);
- 54 if (fd < 0) return;
- 55
- 56 // Publish
- 57 std::string publishedName = key() + name_;
- 58 std::for_each(publishedName.begin(), publishedName.end(),
- 59 [] (char& c) { c = isalnum(c) ? c : '_'; });
- 60
- 61 std::string val = android::base::StringPrintf("%d", fd);
- //将创建的socket 的fd 放入 环境变量:ANDROID_SOCKET_zygote 中,以便在zygote进程中,获取此socket的fd
- 62 add_environment(publishedName.c_str(), val.c_str());
- 63
- 64 // make sure we don't close on exec
- 65 fcntl(fd, F_SETFD, 0);
- 66}

- 80int SocketInfo::Create(const std::string& context) const {
- 81 int flags = ((type() == "stream" ? SOCK_STREAM :
- 82 (type() == "dgram" ? SOCK_DGRAM :
- 83 SOCK_SEQPACKET)));
- //创建名为zygote 的socket
- 84 return create_socket(name().c_str(), flags, perm(), uid(), gid(), context.c_str());
- 85}
- 86
- 87const std::string SocketInfo::key() const {
- 88 return ANDROID_SOCKET_ENV_PREFIX;
- 89}
- 123const std::string FileInfo::key() const {
- 124 return ANDROID_FILE_ENV_PREFIX;
- 125}
现在应该明白了registerServerSocket的来龙去脉了吧,尤其是这个socket的fd是怎么来的
- frameworks/base/core/java/com/android/internal/os/ZygoteServer.java
- private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
-
- private LocalServerSocket mServerSocket;
- /**
- * Registers a server socket for zygote command connections
- *
- * @throws RuntimeException when open fails
- */
- void registerServerSocket(String socketName) {
- //看起来是用了一个单例
- if (mServerSocket == null) {
- int fileDesc;
- final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
- try {
- //从环境变量中获取名为ANDROID_SOCKET_zygote的fd
- String env = System.getenv(fullSocketName);
- fileDesc = Integer.parseInt(env);
- } catch (RuntimeException ex) {
- throw new RuntimeException(fullSocketName + " unset or invalid", ex);
- }
-
- try {
- //构建JAVA中的FD对象
- FileDescriptor fd = new FileDescriptor();
- fd.setInt$(fileDesc);
- //用上面的FD创建LocalServerSocket
- mServerSocket = new LocalServerSocket(fd);
- } catch (IOException ex) {
- throw new RuntimeException(
- "Error binding to local socket '" + fileDesc + "'", ex);
- }
- }
- }

总结:init进程中add环境变量,Zygote进程中get环境变量。
1.3、Zygote进程预加载资源
- /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
- 124 static void preload(BootTimingsTraceLog bootTimingsTraceLog) {
- 125 Log.d(TAG, "begin preload");
- 126 bootTimingsTraceLog.traceBegin("BeginIcuCachePinning");
- 127 beginIcuCachePinning();
- 128 bootTimingsTraceLog.traceEnd(); // BeginIcuCachePinning
- 129 bootTimingsTraceLog.traceBegin("PreloadClasses");
- 130 preloadClasses();
- 131 bootTimingsTraceLog.traceEnd(); // PreloadClasses
- 132 bootTimingsTraceLog.traceBegin("PreloadResources");
- 133 preloadResources();
- 134 bootTimingsTraceLog.traceEnd(); // PreloadResources
- 135 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
- 136 preloadOpenGL();
- 137 Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
- 138 preloadSharedLibraries();
- 139 preloadTextResources();
- 140 // Ask the WebViewFactory to do any initialization that must run in the zygote process,
- 141 // for memory sharing purposes.
- 142 WebViewFactory.prepareWebViewInZygote();
- 143 endIcuCachePinning();
- 144 warmUpJcaProviders();
- 145 Log.d(TAG, "end preload");
- 146
- 147 sPreloadComplete = true;
- 148 }
-

系统哪些资源被预加载了?加载的有类,资源,共享库,
1.3.1 加载类----preloadClasses
preload方法中会调用会preloadClasses预加载一些类,这些类记录在[frameworks/base/preloaded-classes](http://androidxref.com/8.0.0_r4/xref/frameworks/base/preloaded-classes)文本文件里。大概有四千多个,下面列举一下。
- 32[Landroid.accounts.Account;
- 33[Landroid.animation.Animator;
- 34[Landroid.animation.Keyframe$FloatKeyframe;
- 35[Landroid.animation.Keyframe$IntKeyframe;
- 36[Landroid.animation.PropertyValuesHolder;
- 37[Landroid.app.LoaderManagerImpl;
- 38[Landroid.app.Notification$Action;
- 39[Landroid.app.NotificationChannel;
- 40[Landroid.app.RemoteInput;
- 41[Landroid.app.job.JobInfo$TriggerContentUri;
- 42[Landroid.bluetooth.BluetoothDevice;
- 43[Landroid.content.ContentProviderResult;
- 44[Landroid.content.ContentValues;
- 45[Landroid.content.Intent;
- 46[Landroid.content.UndoOwner;
- 47[Landroid.content.pm.ActivityInfo;
- 48[Landroid.content.pm.ConfigurationInfo;
- 49[Landroid.content.pm.FeatureGroupInfo;
- 50[Landroid.content.pm.FeatureInfo;
- 51[Landroid.content.pm.InstrumentationInfo;
- 52[Landroid.content.pm.PathPermission;
- 53[Landroid.content.pm.PermissionInfo;
- 54[Landroid.content.pm.ProviderInfo;
- 55[Landroid.content.pm.ServiceInfo;
- 56[Landroid.content.pm.Signature;
- 57[Landroid.content.res.Configuration;
- 58[Landroid.content.res.StringBlock;
- 59[Landroid.content.res.XmlBlock;
- 60[Landroid.database.CursorWindow;
- 61[Landroid.database.sqlite.SQLiteConnection$Operation;
- 62[Landroid.database.sqlite.SQLiteConnectionPool$AcquiredConnectionStatus;
- 63[Landroid.graphics.Bitmap$CompressFormat;
- 64[Landroid.graphics.Bitmap$Config;
- 65[Landroid.graphics.Bitmap;
- 66[Landroid.graphics.Canvas$EdgeType;
- 67[Landroid.graphics.ColorSpace$Model;
- 68[Landroid.graphics.ColorSpace$Named;
- 69[Landroid.graphics.ColorSpace;
- 70[Landroid.graphics.FontFamily;
- 71[Landroid.graphics.Interpolator$Result;

上面文件中列举的四千多个类都要通过Class.forName加载到系统中,生成字节码。
- 229 /**
- 230 * Performs Zygote process initialization. Loads and initializes
- 231 * commonly used classes.
- 232 *
- 233 * Most classes only cause a few hundred bytes to be allocated, but
- 234 * a few will allocate a dozen Kbytes (in one case, 500+K).
- 235 */
- 236 private static void preloadClasses() {
- 237 final VMRuntime runtime = VMRuntime.getRuntime();
- 238
- 239 InputStream is;
- 240 try {
- 241 is = new FileInputStream(PRELOADED_CLASSES);
- 242 } catch (FileNotFoundException e) {
- 243 Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES + ".");
- 244 return;
- 266 droppedPriviliges = true;
- 267 }
- ........
- 274 try {
- 275 BufferedReader br = new BufferedReader(new InputStreamReader(is), 256);
- 278 int count = 0;
- 279 String line;
- 280 while ((line = br.readLine()) != null) {
- 281 // Skip comments and blank lines.
- 282 line = line.trim();
- //跳过文件中注释的部分
- 283 if (line.startsWith("#") || line.equals("")) {
- 284 continue;
- 285 }
- 286
- 287 Trace.traceBegin(Trace.TRACE_TAG_DALVIK, line);
- 288 try {
- 289 if (false) {
- 290 Log.v(TAG, "Preloading " + line + "...");
- 291 }
- 292 // Load and explicitly initialize the given class. Use
- 293 // Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups
- 294 // (to derive the caller's class-loader). Use true to force initialization, and
- 295 // null for the boot classpath class-loader (could as well cache the
- 296 // class-loader of this class in a variable).
- 297 Class.forName(line, true, null);
- 298 count++;
- 299 } catch (ClassNotFoundException e) {
- 300 Log.w(TAG, "Class not found for preloading: " + line);
- 301 } catch (UnsatisfiedLinkError e) {
- 302 Log.w(TAG, "Problem preloading " + line + ": " + e);
- 303 } catch (Throwable t) {
- 304 ........
- 314 }
- 315
- 316 Log.i(TAG, "...preloaded " + count + " classes in "
- 317 + (SystemClock.uptimeMillis()-startTime) + "ms.");
- 318 } catch (IOException e) {
- 319 Log.e(TAG, "Error reading " + PRELOADED_CLASSES + ".", e);
- 320 } finally {
- .....
- 339 }
- 340 }

1.3.2 加载资源----preloadResources
系统中有大量的资源可以直接被App所使用,比如一个颜色,一个drawble,这些都是通过preloadResources加载的。
- /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
- 342 /**
- 343 * Load in commonly used resources, so they can be shared across
- 344 * processes.
- 345 *
- 346 * These tend to be a few Kbytes, but are frequently in the 20-40K
- 347 * range, and occasionally even larger.
- 348 */
- 349 private static void preloadResources() {
- 350 final VMRuntime runtime = VMRuntime.getRuntime();
- 351
- 352 try {
- 353 mResources = Resources.getSystem();
- 354 mResources.startPreloading();
- 355 if (PRELOAD_RESOURCES) {
- 356 Log.i(TAG, "Preloading resources...");
- 357
- 358 long startTime = SystemClock.uptimeMillis();
- //1、加载preloaded_drawables中定义的资源,这里面定义的基本是图片
- 359 TypedArray ar = mResources.obtainTypedArray(
- 360 com.android.internal.R.array.preloaded_drawables);
- 361 int N = preloadDrawables(ar);
- 362 ar.recycle();
- 363 Log.i(TAG, "...preloaded " + N + " resources in "
- 364 + (SystemClock.uptimeMillis()-startTime) + "ms.");
- 365
- 366 startTime = SystemClock.uptimeMillis();
- //2、加载preloaded_color_state_lists中定义的资源,这里面定义的基本是颜色
- 367 ar = mResources.obtainTypedArray(
- 368 com.android.internal.R.array.preloaded_color_state_lists);
- //如果是颜色资源,需要调用preloadColorStateLists加载,见下面的preloadColorStateLists代码的解释
- 369 N = preloadColorStateLists(ar);
- 370 ar.recycle();
- 371 Log.i(TAG, "...preloaded " + N + " resources in "
- 372 + (SystemClock.uptimeMillis()-startTime) + "ms.");
- 373
- //3、加载config_freeformWindowManagement中定义的资源,这里面定义的基本是图片
- 374 if (mResources.getBoolean(
- 375 com.android.internal.R.bool.config_freeformWindowManagement)) {
- 376 startTime = SystemClock.uptimeMillis();
- 377 ar = mResources.obtainTypedArray(
- 378 com.android.internal.R.array.preloaded_freeform_multi_window_drawables);
- 379 N = preloadDrawables(ar);
- 380 ar.recycle();
- 381 Log.i(TAG, "...preloaded " + N + " resource in "
- 382 + (SystemClock.uptimeMillis() - startTime) + "ms.");
- 383 }
- 384 }
- 385 mResources.finishPreloading();
- 386 } catch (RuntimeException e) {
- 387 Log.w(TAG, "Failure preloading resources", e);
- 388 }
- 389 }

preloaded_drawables、preloaded_color_state_lists、preloaded_freeform_multi_window_drawables都是在/frameworks/base/core/res/res/values/arrays.xml中定义的
- /frameworks/base/core/res/res/values/arrays.xml
- 20<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- 21
- 22 <!-- Do not translate. These are all of the drawable resources that should be preloaded by
- 23 the zygote process before it starts forking application processes. -->
- 24 <array name="preloaded_drawables">
- 25 <item>@drawable/ab_share_pack_material</item>
- 26 <item>@drawable/ab_solid_shadow_material</item>
- 27 <item>@drawable/action_bar_item_background_material</item>
- 28 <item>@drawable/activated_background_material</item>
- ......
- 138 <item>@drawable/toast_frame</item>
- 139 </array>
-
-
- 141 <!-- Do not translate. These are all of the color state list resources that should be
- 142 preloaded by the zygote process before it starts forking application processes. -->
- 143 <array name="preloaded_color_state_lists">
- 144 <item>@color/primary_text_dark</item>
- 145 <item>@color/primary_text_dark_disable_only</item>
- 146 <item>@color/primary_text_dark_nodisable</item>
- .......
- 186 <item>@color/search_url_text_material_light</item>
- 187 </array>
-
- 189 <array name="preloaded_freeform_multi_window_drawables">
- 190 <item>@drawable/decor_maximize_button_dark</item>
- 191 <item>@drawable/decor_maximize_button_light</item>
- 192 </array>

对于颜色资源,需要调用preloadColorStateLists来加载
- /frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
- 391 private static int preloadColorStateLists(TypedArray ar) {
- 392 int N = ar.length();
- 393 for (int i=0; i<N; i++) {
- 394 int id = ar.getResourceId(i, 0);
- 395 if (false) {
- 396 Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
- 397 }
- 398 if (id != 0) {
- 399 if (mResources.getColorStateList(id, null) == null) {
- 400 throw new IllegalArgumentException(
- 401 "Unable to find preloaded color resource #0x"
- 402 + Integer.toHexString(id)
- 403 + " (" + ar.getString(i) + ")");
- 404 }
- 405 }
- 406 }
- 407 return N;
- 408 }

对于preloadOpenGL、preloadSharedLibraries和preloadTextResources在此不一一分析了,原来ZygoteInit中的preload方法加载了这么多资源,这个也就是为什么开机慢而打开一个应用快的原因之一。我们能不能把加载资源的这些耗时操作放到子线程中做呢?
- 671 public static void main(String argv[]) {
- 672 ZygoteServer zygoteServer = new ZygoteServer();
- 673
- 674 // Mark zygote start. This ensures that thread creation will throw
- 675 // an error.
- 676 ZygoteHooks.startZygoteNoThreadCreation();
- 677
- .......
- 756 ZygoteHooks.stopZygoteNoThreadCreation();
- 757 }
禁止使用子线程.png
看到为防止多线程带来的同步问题,google这个地方禁止开启多线程。故网上有很多说法,尝试把这些代码放到子线程中去做应该是不对的(Android O)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。