前言
俗話說的好肩榕,好記憶不如爛筆頭刚陡;從業(yè)Android開發(fā)已多年,東西是越學越多株汉,越學越忘筐乳,此系列文章是對過去的所學總結(jié)。
Zygote的理解
1).Zygote的作用
1.啟動SystemServer
2.孵化應用進程
關(guān)于第二點孵化應用進程可能是大家比較熟悉的點乔妈,其實SystemServer也是通過Zygote啟動的蝙云,因為SystemServer需要用到Zygote里面準備的一些系統(tǒng)資源:比如常用的一些類,注冊的JNI函數(shù)褒翰,主題資源贮懈,共享庫等等,具體看之后的源碼介紹
2).Zygote的啟動流程
Android里面進程常用套路:進程啟動->準備工作->Loop循環(huán)
Loop循環(huán)
就是不停的接收消息處理消息优训,這個消息是從哪來的呢朵你?他可能是通過這個Socket發(fā)過來的,也可能是Message揣非,也可能呢抡医,是Binder驅(qū)動發(fā)過來的消息
Zygote進程如何啟動
Zygote進程它是如何被啟動的呢?這個我們得感謝init進程早敬,它是Linux啟動之后用戶空間的第一個進程忌傻,Init進程啟動之后首先會去加載一個啟用配置文件(init.rc)。里面定義了哪些系統(tǒng)服務需要這時候啟動的搞监。Zygote就是要啟動的服務之一(我們很熟悉的ServiceManager進程也在其中)水孩。那這個進程是怎么啟動的呢?就是通過fork加execve系統(tǒng)調(diào)用琐驴。
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
writepid /dev/cpuset/foreground/tasks
init.rc語法就不擴展了俘种,其中有service名稱(zygote)秤标,有fork加execve系統(tǒng)調(diào)用所需的可執(zhí)行程序路徑(/system/bin/app_process64)以及后面所需的參數(shù)
Zygote進程啟動之后做了什么
1.Native世界
Zygote通過fork+ execve系統(tǒng)調(diào)用啟動進程,它執(zhí)行的是一個二進制的可執(zhí)行程序宙刘,用C++寫的里面有main函數(shù)作為入口苍姜。所以Zygote天生就是native的。做了如下三件事
簡單的邏輯代碼可參考如下:
int main(int argc, char *argv[]) {
JavaVM *jvm;
JNIEnv *env;
JNI_CreateJavaVM(&jvm, (void **) &env, &vm_args);
jclass clazz = env->FindClass("ZygoteInit");
jmethodID method = env->GetStaticMethodID(clazz, "Main", "([Ljava/lang/String;)V");
env->CallStaticVoidMethod(clazz, method, args);
jvm->DestroyJavaVM();
}
1.里邊首先通過 JNI_CreateJavaVM去創(chuàng)建一個虛擬機悬包。然后 再去找到一個叫ZygoteInit的Java類衙猪, 再去這個類里面找一個叫Main的靜態(tài)函數(shù),再通過這個CallStaticVoidMethod去調(diào)用這個函數(shù),最后呢布近,再去destroy這個java虛擬機 垫释。
2.JNI_CreateJavaVM去創(chuàng)建虛擬機。我們回想一下我們自己的應用撑瞧,里邊好像直接就可以JNI調(diào)用了啊饶号。沒有這么一句得先創(chuàng)建Java虛擬機的,那是為什么呢季蚂?因為這個Java虛擬機其實在Zygote進程里面就已經(jīng)創(chuàng)建好了茫船。咱們應用進程的是Zygote孵化出來的,就繼承了他的這個虛擬機扭屁,我們就不用再創(chuàng)建一遍了算谈,我們唯一要做的就是這個在進程啟動的時候重置一下這個虛擬機的狀態(tài) ,再重啟一下這個虛擬機料滥,里面的一些守護線程就可以了
2.Java世界
終于到了java世界了然眼,在java世界中做了哪些事情呢?主要有三件事
- 預加載資源:為了將來繼承給子進程,包括主題資源葵腹,常用類等
// 代碼來自Android23中:ZygoteInit.java
static void preload() {
Log.d(TAG, "begin preload");
preloadClasses();
preloadResources();
preloadOpenGL();
preloadSharedLibraries();
preloadTextResources();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
WebViewFactory.prepareWebViewInZygote();
Log.d(TAG, "end preload");
- 啟動SystemServer:SystemServer單獨跑在一個進程
// 代碼來自Android23中:ZygoteInit.java
private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
......
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
......
}
- 進入Loop循環(huán):等待的是socket消息
// 代碼來自Android23中:ZygoteInit.java
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
...
while (true) {
for (int i = pollFds.length - 1; i >= 0; --i) {
boolean done = peers.get(i).runOnce();
}
}
}
到這進入Loop循環(huán)后高每,等待Socket消息,拿到消息后執(zhí)行的是runOnce()
runOnce()
// 代碼來自Android23中:ZygoteInit.java
boolean runOnce() {
String[] args = readArgumentList();
int pid = Zygote.forkAndSpecialize();
if (pid == 0) {
// in child
handleChildProc(args, ...);
return true;
}
}
runOnce先會創(chuàng)建一個進程践宴,然后在子進程中最終會調(diào)用handleChildProc鲸匿,這個方法其實就是執(zhí)行了一個java類的main函數(shù),類名通過AMS跨進程傳過來阻肩,其實就是
這就通過Zygote孵化了一個進程带欢,進程的入口函數(shù)就是我們熟悉的ActivityThread的main方法。
總結(jié)
Zygote啟動流程如下:
- init進程fork出zygote進程
- 啟動虛擬機烤惊,注冊jni函數(shù)
- 預加載系統(tǒng)資源
- 啟動SystemServer
- 進入Socket Loop循環(huán)
思考點
1.Zygote的跨進程通信采用了Linux的Socket乔煞,而不是Binder,為什么不采用Binder呢柒室?(后面文章會解釋渡贾,不過理解了本篇文章的同學應該也能猜到的吧)