Zygote是什么?
在Android中,負責孵化新進程的這個進程叫做Zygote躺酒,安卓上其他的應(yīng)用進程都是由它孵化的。眾所周知蔑歌,安卓是Linux內(nèi)核羹应,安卓系統(tǒng)上運行的一切程序都是放在Dalvik虛擬機上的,Zygote也不例外次屠,事實上园匹,它是安卓運行的第一個Dalvik虛擬機進程。既然Zygote負責孵化其他的安卓進程劫灶,那么它自己是由誰孵化的呢裸违?既然Android是基于Linux內(nèi)核,那么Zygote當然就是Linux內(nèi)核啟動的用戶級進程Init創(chuàng)建的了本昏。
Zygote的作用是什么供汛?
對于Zygote的作用實際上可以概括為以下兩點:
- 創(chuàng)建SystemServer
- 孵化應(yīng)用進程
Zygote的啟動過程
-
Zygote進程在Init進程啟動過程中被以service服務(wù)的形式啟動:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server class main socket zygote stream 660 root system
調(diào)用app_main.cpp的main函數(shù)中的AppRuntime的start方法來啟動Zygote進程
調(diào)用startVm函數(shù)來創(chuàng)建虛擬機,調(diào)用startReg函數(shù)為java虛擬機注冊JNI方法
通過toSlashClassName找到ZygoteInit涌穆,通過GetStaticMethedID函數(shù)找到main方法然后調(diào)用怔昨,ZygoteInit的main方法是由Java語言編寫的,當前的運行邏輯在Native中蒲犬,這就需要JNI來調(diào)用Java朱监,這樣Zygote就從Native層進入了Java框架層岸啡。
ZygoteInit的main方法的源碼如下:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
//1原叮、創(chuàng)建ZygoteServer
ZygoteServer zygoteServer = new ZygoteServer();
.......
try {
.......
boolean startSystemServer = false;
String socketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;
// 2、解析app_main.cpp傳來的參數(shù)
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、創(chuàng)建一個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唯欣、啟動一個死循環(huán)監(jiān)聽來自Client端的消息
zygoteServer.runSelectLoop(abiList);
//7嘹吨、關(guān)閉SystemServer的Socket
zygoteServer.closeServerSocket();
} catch (Zygote.MethodAndArgsCaller caller) {
//8、這里捕獲這個異常調(diào)用MethodAndArgsCaller的run方法境氢。
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
zygoteServer.closeServerSocket();
throw ex;
}
}
總結(jié)下來的流程:
【1】通過registerServerSocket方法來創(chuàng)建一個Server端的socket蟀拷,這個name為zygote的socket用于等待ActivityManagerService請求Zygote來創(chuàng)建新的應(yīng)用程序進程
【2】預(yù)加載,預(yù)加載項如下:
preloadClasses();
preloadResources();
preloadOpenGL();
preloadSharedLibraries();
preloadTextResources();
WebViewFactory.prepareWebViewInZygote();
...
以下是Android應(yīng)用進程共享內(nèi)存圖:
通過上圖可以很容易理解在Zygote進程預(yù)加載系統(tǒng)資源后萍聊,然后通過它孵化出其他的虛擬機進程问芬,進而共享虛擬機內(nèi)存和框架層資源,這樣大幅度提高應(yīng)用程序的啟動和運行速度寿桨。
【3】啟動SystemServer進程
【4】執(zhí)行runSelectLoop()方法等待消息去創(chuàng)建應(yīng)用進程
Zygote注意細節(jié)
- Zygote進行fork的時候要是單線程此衅,為了避免造成死鎖或者狀態(tài)不一致等問題
- Zygote的跨進程通信沒有采用Binder機制,而是采用本地socket
關(guān)于Zygote的疑問
- 孵化應(yīng)用進程這種事為什么不交給SystemServer來做亭螟,而專門設(shè)計一個Zygote挡鞍?
我們知道,應(yīng)用在啟動的時候需要做很多準備工作预烙,包括啟動虛擬機墨微,加載各類系統(tǒng)資源等等,這些都是非常耗時的扁掸,如果能在zygote里就給這些必要的初始化工作做好欢嘿,子進程在fork的時候就能直接共享,那么這樣的話效率就會非常高也糊。這個就是zygote存在的價值炼蹦,這一點呢SystemServer是替代不了的,主要是因為SystemServer里跑了一堆系統(tǒng)服務(wù)狸剃,這些是不能繼承到應(yīng)用進程的掐隐。而且我們應(yīng)用進程在啟動的時候,內(nèi)存空間除了必要的資源外钞馁,最好是干干凈凈的虑省,不要繼承一堆亂七八糟的東西。所以呢僧凰,不如給SystemServer和應(yīng)用進程里都要用到的資源抽出來單獨放在一個進程里探颈,也就是這的zygote進程,然后zygote進程再分別孵化出SystemServer進程和應(yīng)用進程训措。孵化出來之后伪节,SystemServer進程和應(yīng)用進程就可以各干各的事了光羞。
- Zygote的IPC通信機制為什么不采用binder?如果采用binder的話會有什么問題么怀大?
第一個原因纱兑,我們可以設(shè)想一下采用binder調(diào)用的話該怎么做,首先zygote要啟用binder機制化借,需要打開binder驅(qū)動潜慎,獲得一個描述符,再通過mmap進行內(nèi)存映射蓖康,還要注冊binder線程铐炫,這還不夠,還要創(chuàng)建一個binder對象注冊到serviceManager蒜焊,另外AMS要向zygote發(fā)起創(chuàng)建應(yīng)用進程請求的話驳遵,要先從serviceManager查詢zygote的binder對象,然后再發(fā)起binder調(diào)用山涡,這來來回回好幾趟非常繁瑣堤结,相比之下,zygote和SystemServer進程本來就是父子關(guān)系鸭丛,對于簡單的消息通信竞穷,用管道或者socket非常方便省事。第二個原因鳞溉,如果zygote啟用binder機制瘾带,再fork出SystemServer,那么SystemServer就會繼承了zygote的描述符以及映射的內(nèi)存熟菲,這兩個進程在binder驅(qū)動層就會共用一套數(shù)據(jù)結(jié)構(gòu)看政,這顯然是不行的,所以還得先給原來的舊的描述符關(guān)掉抄罕,再重新啟用一遍binder機制允蚣,這個就是自找麻煩了。
在網(wǎng)上看到一個Zygote工作流程圖呆贿,感覺描述的非常清晰嚷兔,可以參考一下:
好了,關(guān)于Zygote的理解就到這里了做入,有什么不對的地方希望大家指正冒晰!共同進步!