Zygote是什么?
在Android中,负责孵化新进程的这个进程叫做Zygote,安卓上其他的应用进程都是由它孵化的。众所周知,安卓是Linux内核,安卓系统上运行的一切程序都是放在Dalvik虚拟机上的,Zygote也不例外,事实上,它是安卓运行的第一个Dalvik虚拟机进程。既然Zygote负责孵化其他的安卓进程,那么它自己是由谁孵化的呢?既然Android是基于Linux内核,那么Zygote当然就是Linux内核启动的用户级进程Init创建的了。
Zygote的作用是什么?
对于Zygote的作用实际上可以概括为以下两点:
- 创建SystemServer
- 孵化应用进程
Zygote的启动过程
-
Zygote进程在Init进程启动过程中被以service服务的形式启动:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main socket zygote stream 660 root system
调用app_main.cpp的main函数中的AppRuntime的start方法来启动Zygote进程
调用startVm函数来创建虚拟机,调用startReg函数为java虚拟机注册JNI方法
通过toSlashClassName找到ZygoteInit,通过GetStaticMethedID函数找到main方法然后调用,ZygoteInit的main方法是由Java语言编写的,当前的运行逻辑在Native中,这就需要JNI来调用Java,这样Zygote就从Native层进入了Java框架层。
ZygoteInit的main方法的源码如下:
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;
}
}
总结下来的流程:
【1】通过registerServerSocket方法来创建一个Server端的socket,这个name为zygote的socket用于等待ActivityManagerService请求Zygote来创建新的应用程序进程
【2】预加载,预加载项如下:
preloadClasses();
preloadResources();
preloadOpenGL();
preloadSharedLibraries();
preloadTextResources();
WebViewFactory.prepareWebViewInZygote();
...
以下是Android应用进程共享内存图:
通过上图可以很容易理解在Zygote进程预加载系统资源后,然后通过它孵化出其他的虚拟机进程,进而共享虚拟机内存和框架层资源,这样大幅度提高应用程序的启动和运行速度。
【3】启动SystemServer进程
【4】执行runSelectLoop()方法等待消息去创建应用进程
Zygote注意细节
- Zygote进行fork的时候要是单线程,为了避免造成死锁或者状态不一致等问题
- Zygote的跨进程通信没有采用Binder机制,而是采用本地socket
关于Zygote的疑问
- 孵化应用进程这种事为什么不交给SystemServer来做,而专门设计一个Zygote?
我们知道,应用在启动的时候需要做很多准备工作,包括启动虚拟机,加载各类系统资源等等,这些都是非常耗时的,如果能在zygote里就给这些必要的初始化工作做好,子进程在fork的时候就能直接共享,那么这样的话效率就会非常高。这个就是zygote存在的价值,这一点呢SystemServer是替代不了的,主要是因为SystemServer里跑了一堆系统服务,这些是不能继承到应用进程的。而且我们应用进程在启动的时候,内存空间除了必要的资源外,最好是干干净净的,不要继承一堆乱七八糟的东西。所以呢,不如给SystemServer和应用进程里都要用到的资源抽出来单独放在一个进程里,也就是这的zygote进程,然后zygote进程再分别孵化出SystemServer进程和应用进程。孵化出来之后,SystemServer进程和应用进程就可以各干各的事了。
- Zygote的IPC通信机制为什么不采用binder?如果采用binder的话会有什么问题么?
第一个原因,我们可以设想一下采用binder调用的话该怎么做,首先zygote要启用binder机制,需要打开binder驱动,获得一个描述符,再通过mmap进行内存映射,还要注册binder线程,这还不够,还要创建一个binder对象注册到serviceManager,另外AMS要向zygote发起创建应用进程请求的话,要先从serviceManager查询zygote的binder对象,然后再发起binder调用,这来来回回好几趟非常繁琐,相比之下,zygote和SystemServer进程本来就是父子关系,对于简单的消息通信,用管道或者socket非常方便省事。第二个原因,如果zygote启用binder机制,再fork出SystemServer,那么SystemServer就会继承了zygote的描述符以及映射的内存,这两个进程在binder驱动层就会共用一套数据结构,这显然是不行的,所以还得先给原来的旧的描述符关掉,再重新启用一遍binder机制,这个就是自找麻烦了。
在网上看到一个Zygote工作流程图,感觉描述的非常清晰,可以参考一下:
好了,关于Zygote的理解就到这里了,有什么不对的地方希望大家指正!共同进步!