图解Android - Zygote, System Server 启动分析
Init 是所有Linux程序的起點(diǎn),而Zygote于Android,正如它的英文意思,是所有java程序的'孵化池'(玩過星際蟲族的兄弟都曉得的)。用ps 輸出可以看到
>adb shell ps | grep -E 'init|926'root 1 0 656 372 00000000 0805d546 S /initroot 926 1 685724 43832 ffffffff b76801e0 S zygotesystem 1018 926 795924 62720 ffffffff b767fff6 S system_serveru0_a6 1241 926 717704 39252 ffffffff b76819eb S com.android.systemuiu0_a37 1325 926 698280 29024 ffffffff b76819eb S com.android.inputmethod.latinradio 1349 926 711284 30116 ffffffff b76819eb S com.android.phoneu0_a7 1357 926 720792 41444 ffffffff b76819eb S com.android.launcheru0_a5 1523 926 703576 26416 ffffffff b76819eb S com.android.providers.calendaru0_a25 1672 926 693716 21328 ffffffff b76819eb S com.android.musicfxu0_a17 2040 926 716888 33992 ffffffff b76819eb S android.process.acoreu0_a21 2436 926 716060 23904 ffffffff b76819eb S com.android.calendarinit 是 zygote的父進(jìn)程, 而system_server和其他所有的com.xxx結(jié)尾的應(yīng)用程序都是從zygote fork 而來。本文將圖過圖表(輔予少量的代碼)的方式來描述Zygote,system server 以及android application的啟動(dòng)過程。
廢話少說,奉上兩張大圖開啟我們的Zygote之旅。 第一張圖是Zygote相關(guān)的所有類的結(jié)構(gòu)圖,另一張是Zygote啟動(dòng)的流程圖。
?
?
?
?
?
?按圖索驥,我們按照?qǐng)D一中的序號(hào)一一分解Zygote的啟動(dòng)過程。
1. App_Process?
- APP_Process: 啟動(dòng)zygote和其他Java程序的應(yīng)用程序, 代碼位于frameworks/base/cmds/app_process/app_main.cpp, 在init.rc 里面指定。
代碼如下
...else if (strcmp(arg, "--zygote") == 0) {zygote = true;niceName = "zygote"; } else if (strcmp(arg, "--start-system-server") == 0) {startSystemServer = true; } else if (strcmp(arg, "--application") == 0) {application = true; } ...if (zygote) {runtime.start("com.android.internal.os.ZygoteInit",startSystemServer ? "start-system-server" : ""); } else if (className) {// Remainder of args get passed to startup class main()runtime.mClassName = className;...runtime.start("com.android.internal.os.RuntimeInit",application ? "application" : "tool"); } else { }
?可以看到,app_process 里面定義了三種應(yīng)用程序類型:
? ? ? ?1. ?Zygote: ?com.android.internal.os.ZygoteInit
? ? ? ?2. ?System Server, 不單獨(dú)啟動(dòng),而是由Zygote啟動(dòng)
? ? ? ?3. ?其他指定類名的Java 程序,比如說常用的 am. /system/bin/am 其實(shí)是一個(gè)shell程序,它的真正實(shí)現(xiàn)是? ? ? ?
exec app_process $base/bin com.android.commands.am.Am "$@"這些Java的應(yīng)用都是通過 AppRuntime.start(className)開始的。從第一張大圖可以看出,其實(shí)AppRuntime是AndroidRuntime的子類,它主要實(shí)現(xiàn)了幾個(gè)回調(diào)函數(shù),而start()方法是實(shí)現(xiàn)在AndroidRuntime這個(gè)方法類里。什么是AnroidRuntime? 我們接下來馬上開始。
需要注意的是Zygote并不是Init啟動(dòng)的第一個(gè)程序,從PID可以看出來,在它之前,一下Native實(shí)現(xiàn)的重要System Daemon (后臺(tái)進(jìn)程)可能先起來,比如 ServiceManager (service的DNS服務(wù)).
?
2. AndroidRuntime
? ? ?首先,什么是Runtime ?看看Wiki給的幾種解釋:? ? ??
- Run time (program lifecycle phase), the period during which a computer program is executing
- Runtime library, a program library designed to implement functions built into a programming language
?
? ? ?我傾向這里指的是后者,看看更進(jìn)一步的解釋:
? ? ?In?computer programming, a?runtime library?is the?API?used by a?compiler?to invoke some of the behaviors of a?runtime system. The runtime system implements the execution model and other fundamental behaviors of a?programming language.?The compiler inserts calls to the runtime library into the executable binary. During execution (run time) of that?computer program, execution of those calls to the runtime library cause communication between the application and theruntime system. This often includes functions for input and output, or for memory management.
? ? ?歸納起來的意思就是,Runtime 是支撐程序運(yùn)行的基礎(chǔ)庫,它是與語言綁定在一起的。比如:
- C Runtime:就是C standard lib, 也就是我們常說的libc。(有意思的是, Wiki會(huì)自動(dòng)將“C runtime" 重定向到 "C Standard Library").
- Java Runtime: 同樣,Wiki將其重定向到” Java Virtual Machine", 這里當(dāng)然包括Java 的支撐類庫(.jar).
- AndroidRuntime: ?顯而易見,就是為Android應(yīng)用運(yùn)行所需的運(yùn)行時(shí)環(huán)境。這個(gè)環(huán)境包括以下東東:
- Dalvik VM: Android的Java VM, 解釋運(yùn)行Dex格式Java程序。每個(gè)進(jìn)程運(yùn)行一個(gè)虛擬機(jī)(什么叫運(yùn)行虛擬機(jī)?說白了,就是一些C代碼,不停的去解釋Dex格式的二進(jìn)制碼(Bytecode),把它們轉(zhuǎn)成機(jī)器碼(Machine code),然后執(zhí)行,當(dāng)然,現(xiàn)在大多數(shù)的Java 虛擬機(jī)都支持JIT,也就是說,bytecode可能在運(yùn)行前就已經(jīng)被轉(zhuǎn)換成機(jī)器碼,從而大大提高了性能。過去一個(gè)普遍的認(rèn)識(shí)是Java 程序比C,C++等靜態(tài)編譯的語言慢,但隨著JIT的介入和發(fā)展,這個(gè)已經(jīng)完全是過去時(shí)了,JIT的動(dòng)態(tài)性運(yùn)行允許虛擬機(jī)根據(jù)運(yùn)行時(shí)環(huán)境,優(yōu)化機(jī)器碼的生成,在某些情況下,Java甚至可以比C/C++跑得更快,同時(shí)又兼具平臺(tái)無關(guān)的特性,這也是為什么Java如今如此流行的原因之一吧)。
- Android的Java 類庫, 大部分來自于 Apache Hamony, 開源的Java API 實(shí)現(xiàn),如 java.lang, java.util, java.net. 但去除了AWT, Swing 等部件。
- JNI: C和Java互調(diào)的接口。
- Libc: Android也有很多C代碼,自然少不了libc,注意的是,Android的libc叫 bionic C.
? ???? OK, 那就首先看看AndroidRuntime是怎么搭建起來的吧 ? ??
?
? ? ? 上圖給出了Zygote啟動(dòng)的大概流程,入口是AndroidRuntime.start(), 根據(jù)傳入?yún)?shù)的不同可以有兩種啟動(dòng)方式,一個(gè)是?"com.android.internal.os.RuntimeInit", 另一個(gè)是 ”com.android.internal.os.ZygoteInit", 對(duì)應(yīng)RuntimeInit 和 ZygoteInit 兩個(gè)類, 圖中用綠色和粉紅色分別表示。這兩個(gè)類的主要區(qū)別在于Java端,可以明顯看出,ZygoteInit 相比 RuntimeInit 多做了很多事情,比如說 “preload", "gc" 等等。但是在Native端,他們都做了相同的事, startVM() 和 startReg(), 讓我們先從這里開始吧。
? ? ??從類圖中看出,JavaVM 和 JNIEnv 是連結(jié) AndroidRuntim 和 Dalvik VM 之間的唯一兩個(gè)關(guān)卡,它隱藏了Dalvik 里面的實(shí)現(xiàn)細(xì)節(jié),事實(shí)上,他就是兩個(gè)函數(shù)指針結(jié)構(gòu)體,給本地代碼提供訪問Java資源的接口。JNIEnv則相對(duì)于線程,通過JNIEnv的指針最終可以對(duì)應(yīng)到Dalvik VM 內(nèi)部的Thread 結(jié)構(gòu)體,所有的調(diào)用就在這個(gè)結(jié)構(gòu)體上下文完成。而JavaVM 對(duì)應(yīng)的是DVMGlobal, 一個(gè)進(jìn)程唯一的結(jié)構(gòu)體,他內(nèi)部維護(hù)了一個(gè)線程隊(duì)列threadList,存放每個(gè)Thread 結(jié)構(gòu)體對(duì)象, 同時(shí)還有各類狀態(tài)的對(duì)象列表,及存放GC的結(jié)構(gòu)體,等等。本文無法深入,只作簡單介紹。
-
? JavaVM 和 JNIENV
- struct _JavaVM {const struct JNIInvokeInterface* functions; //C的函數(shù)指針#if defined(__cplusplus) ...jint GetEnv(void** env, jint version){ return functions->GetEnv(this, env, version); }
#endif /*__cplusplus*/
};struct JNIInvokeInterface {void* reserved0;...jint (*DestroyJavaVM)(JavaVM*);jint (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*);jint (*DetachCurrentThread)(JavaVM*);jint (*GetEnv)(JavaVM*, void**, jint);jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*);
};
里面最常見的接口就是GetEnv(), 它返回一個(gè)JNIEnv對(duì)象,對(duì)應(yīng)于每個(gè)DVM線程。JNIEnv的定義很長,有興趣的同學(xué)可以到Jni.h 里面找,這里我們只看看這個(gè)對(duì)象是如何獲static jint GetEnv(JavaVM* vm, void** env,?jint version) {
- struct _JavaVM {const struct JNIInvokeInterface* functions; //C的函數(shù)指針#if defined(__cplusplus) ...jint GetEnv(void** env, jint version){ return functions->GetEnv(this, env, version); }
#endif /*__cplusplus*/
};struct JNIInvokeInterface {void* reserved0;...jint (*DestroyJavaVM)(JavaVM*);jint (*AttachCurrentThread)(JavaVM*, JNIEnv**, void*);jint (*DetachCurrentThread)(JavaVM*);jint (*GetEnv)(JavaVM*, void**, jint);jint (*AttachCurrentThreadAsDaemon)(JavaVM*, JNIEnv**, void*);
};
- Thread* self = dvmThreadSelf(); //獲取當(dāng)前線程對(duì)象。
if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) {return JNI_EVERSION; } //檢查版本號(hào),Android 4.3對(duì)應(yīng) 1.6
... *env = (void*) dvmGetThreadJNIEnv(self); //很簡單,見最下面一行dvmChangeStatus(self, THREAD_NATIVE); return (*env != NULL) ? JNI_OK : JNI_EDETACHED; }INLINE JNIEnv* dvmGetThreadJNIEnv(Thread* self) { return self->jniEnv; }很簡單嘛,原來就是從當(dāng)前所在線程的結(jié)構(gòu)體對(duì)象里讀取即可,這里面好像沒JavaVM什么事嗎,為什么當(dāng)參數(shù)傳入?不知道,也許Google留作將來擴(kuò)展?但不管怎么,要想調(diào)用GetEnv,還是需要JavaVM。將來要寫JNI代碼的同學(xué)可以參考以下的代碼看如何獲取JavaVM和JniENV.
JNIEnv* AndroidRuntime::getJNIEnv() {JNIEnv* env;JavaVM* vm = AndroidRuntime::getJavaVM();assert(vm != NULL);if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK)return NULL;return env; }到這里,我們知道JavaVM 和 JNIEnv 是本地(C/C++)代碼用來與Java代碼進(jìn)行互調(diào)的,那在Java那端一定就是Java虛擬機(jī)以及對(duì)應(yīng)的Java應(yīng)用了。Java虛擬機(jī)到底是什么東東,它是如何創(chuàng)建的?答案從AndroidRuntime::startVM() 函數(shù)開始。startVM
-
startVM()
- int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
{property_get("dalvik.vm.checkjni", propBuf, "");... initArgs.version = JNI_VERSION_1_4;...
//創(chuàng)建VM并返回JavaVM 和 JniEnv,pEnv對(duì)應(yīng)于當(dāng)前線程。if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {ALOGE("JNI_CreateJavaVM failed\n");goto bail;}
... }jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {memset(&gDvm, 0, sizeof(gDvm)); /* 這里才是真正的VM結(jié)構(gòu)體*/JavaVMExt* pVM = (JavaVMExt*) calloc(1, sizeof(JavaVMExt));pVM->funcTable = &gInvokeInterface; //初始化函數(shù)指針pVM->envList = NULL; ... gDvmJni.jniVm = (JavaVM*) pVM; //native代碼接觸的JavaVM原來只是JniVm而已 JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL); //創(chuàng)建JNIEnv,因?yàn)榻酉聛淼奶摂M機(jī)初始化需要訪問C/C++實(shí)現(xiàn) /* 開始初始化. */gDvm.initializing = true;
std::string status =dvmStartup(argc, argv.get(), args->ignoreUnrecognized, (JNIEnv*)pEnv);gDvm.initializing = false; dvmChangeStatus(NULL, THREAD_NATIVE);*p_env = (JNIEnv*) pEnv;*p_vm = (JavaVM*) pVM;return JNI_OK;
std::string dvmStartup(int argc, const char* const argv[],bool ignoreUnrecognized, JNIEnv* pEnv) {/** 檢查輸入并準(zhǔn)備初始化參數(shù)*/int cc = processOptions(argc, argv, ignoreUnrecognized);...
/* 真正初始化開始,初始化各個(gè)內(nèi)部模塊,并創(chuàng)建一系列線程*/ if (!dvmAllocTrackerStartup()) {return "dvmAllocTrackerStartup failed";}if (!dvmGcStartup()) {return "dvmGcStartup failed";}if (!dvmThreadStartup()) {return "dvmThreadStartup failed";}if (!dvmInlineNativeStartup()) {return "dvmInlineNativeStartup";}if (!dvmRegisterMapStartup()) {return "dvmRegisterMapStartup failed";}if (!dvmInstanceofStartup()) {return "dvmInstanceofStartup failed";}if (!dvmClassStartup()) {return "dvmClassStartup failed";}if (!dvmNativeStartup()) {return "dvmNativeStartup failed";}if (!dvmInternalNativeStartup()) {return "dvmInternalNativeStartup failed";}if (!dvmJniStartup()) {return "dvmJniStartup failed";}if (!dvmProfilingStartup()) {return "dvmProfilingStartup failed";}if (!dvmInitClass(gDvm.classJavaLangClass)) {return "couldn't initialized java.lang.Class";}if (!registerSystemNatives(pEnv)) {return "couldn't register system natives";}if (!dvmCreateStockExceptions()) {return "dvmCreateStockExceptions failed";}if (!dvmPrepMainThread()) {return "dvmPrepMainThread failed";}if (dvmReferenceTableEntries(&dvmThreadSelf()->internalLocalRefTable) != 0){ALOGW("Warning: tracked references remain post-initialization");dvmDumpReferenceTable(&dvmThreadSelf()->internalLocalRefTable, "MAIN");}if (!dvmDebuggerStartup()) {return "dvmDebuggerStartup failed";}if (!dvmGcStartupClasses()) {return "dvmGcStartupClasses failed";}if (gDvm.zygote) {if (!initZygote()) {return "initZygote failed";}} else {if (!dvmInitAfterZygote()) {return "dvmInitAfterZygote failed";}}return ""; }Java虛擬機(jī)的啟動(dòng)有太多的細(xì)節(jié)在這里無法展開,這里我們只需要知道它做了以下一些事情:
1.? 從property讀取一系列啟動(dòng)參數(shù)。
u0_a46 1284 1281 714900 57896 20 0 0 0 fg ffffffff 00000000 S GC //垃圾回收u0_a46 1285 1281 714900 57896 20 0 0 0 fg ffffffff 00000000 S Signal Catcher u0_a46 1286 1281 714900 57896 20 0 0 0 fg ffffffff 00000000 S JDWP //Java 調(diào)試u0_a46 1287 1281 714900 57896 20 0 0 0 fg ffffffff 00000000 S Compiler //JITu0_a46 1288 1281 714900 57896 20 0 0 0 fg ffffffff 00000000 S ReferenceQueueD u0_a46 1289 1281 714900 57896 20 0 0 0 fg ffffffff 00000000 S FinalizerDaemon //Finalizer監(jiān)護(hù)u0_a46 1290 1281 714900 57896 20 0 0 0 fg ffffffff 00000000 S FinalizerWatchd //
2.? 創(chuàng)建和初始化結(jié)構(gòu)體全局對(duì)象(每個(gè)進(jìn)程)gDVM,及對(duì)應(yīng)與JavaVM和JNIEnv的內(nèi)部結(jié)構(gòu)體 JavaVMExt, JNIEnvExt.
3.? 初始化java虛擬機(jī),并創(chuàng)建虛擬機(jī)線程。"ps -t",你可以發(fā)現(xiàn)每個(gè)Android應(yīng)用都有以下幾個(gè)線程4. 注冊(cè)系統(tǒng)的JNI,Java程序通過這些JNI接口來訪問底層的資源。
loadJniLibrary("javacore");loadJniLibrary("nativehelper");5. 為Zygote的啟動(dòng)做最后的準(zhǔn)備,包括設(shè)置SID/UID, 以及mount 文件系統(tǒng)。
6. 返回JavaVM 給Native代碼,這樣它就可以向上訪問Java的接口。
除了系統(tǒng)的JNI接口(”javacore", "nativehelper"), android framework 還有大量的Native實(shí)現(xiàn),Android將所有這些接口一次性的通過start_reg()來完成, -
startReg()
? ? ? ? ? ? Android native層有兩種Thread的創(chuàng)建方式:
#threads.cpp status_t Thread::run(const char* name, int32_t priority, size_t stack) {... if (mCanCallJava) {res = createThreadEtc(_threadLoop, this, name, priority, stack, &mThread);} else {res = androidCreateRawThreadEtc(_threadLoop,this, name, priority, stack, &mThread);}... }? ? ? ? ? 它們的區(qū)別在是是否能夠調(diào)用Java端函數(shù),普通的thread就是對(duì)pthread_create的簡單封裝。
? ? ? ? ??
int androidCreateRawThreadEtc(android_thread_func_t entryFunction,void *userData,const char* threadName,int32_t threadPriority,size_t threadStackSize,android_thread_id_t *threadId) {...int result = pthread_create(&thread, &attr,android_pthread_entry)entryFunction, userData);... }? ? ? ? ? ?而能夠訪問Java端的thread需要跟JVM進(jìn)行綁定,下面是具體的實(shí)現(xiàn)函數(shù)? ? ? ? ??
#AndroidRuntime.cpp int AndroidRuntime::javaCreateThreadEtc(android_thread_func_t entryFunction,void* userData,const char* threadName,int32_t threadPriority,size_t threadStackSize,android_thread_id_t* threadId) {args[0] = (void*) entryFunction; //將entryFunc 暫存在args[0]args[1] = userData;args[2] = (void*) strdup(threadName); result =AndroidCreateRawThreadEtc(AndroidRuntime::javaThreadShell, args, threadName, threadPriority, threadStackSize, threadId); //entryFunc變成javaThreadShell.return result; } int AndroidRuntime::javaThreadShell(void* args) {void* start = ((void**)args)[0];void* userData = ((void **)args)[1];char* name = (char*) ((void **)args)[2]; // we own this storage JNIEnv* env;/* 跟 VM 綁定 */if (javaAttachThread(name, &env) != JNI_OK)return -1;/* 運(yùn)行真正的'entryFunc' */result = (*(android_thread_func_t)start)(userData);/* unhook us */javaDetachThread();...return result; }? ? ? attachVM() 到底做什么事情? 篇幅有限無法展開,這里只需要知道這么幾點(diǎn):
-
- 一個(gè)進(jìn)程里有一個(gè)Java 虛擬機(jī),Java 虛擬機(jī)內(nèi)部有很多線程,如上面列到的 GC, FinalizeDaemon, 以及用戶創(chuàng)建的線程等等.
- 每個(gè)Java線程都維護(hù)一個(gè)JNIEnvExt對(duì)象,里面存放一個(gè)指向DVM 內(nèi)部Thread對(duì)象的指針,也就是說,所有從native到Java端的調(diào)用,都會(huì)引用到這個(gè)對(duì)象。
- 所有通過JVM創(chuàng)建的線程都會(huì)在VM內(nèi)部記錄在案,但是當(dāng)前,我們還沒有進(jìn)入Java世界,本地創(chuàng)建的線程VM自然就不知道,因此我們需要通過attach來通知VM來創(chuàng)建相應(yīng)的內(nèi)部數(shù)據(jù)結(jié)構(gòu)。
? ? ? 看看下面代碼,你就知道,其實(shí)Attach()做的一件重要的事情就是 創(chuàng)建thread和JNIEnvExt.
? ? ? ? ? ??
bool dvmAttachCurrentThread(const JavaVMAttachArgs* pArgs, bool isDaemon){Thread* self = NULL;...self = allocThread(gDvm.stackSize);...self->jniEnv = dvmCreateJNIEnv(self);...gDvm.threadList->next = self;...threadObj = dvmAllocObject(gDvm.classJavaLangThread, ALLOC_DEFAULT);vmThreadObj = dvmAllocObject(gDvm.classJavaLangVMThread, ALLOC_DEFAULT);...self->threadObj = threadObj;... }? ? 完了,就開始注冊(cè)本地的JNI接口函數(shù)了- register_jni_procs(), 這個(gè)函數(shù)其實(shí)就是對(duì)一個(gè)全局?jǐn)?shù)組gRegJni[] 進(jìn)行遍歷調(diào)用,這個(gè)數(shù)組展開可以得到以下的結(jié)果
? ? ??
static const RegJNIRec gRegJNI[] = {{register_android_debug_JNITest},{register_com_android_internal_os_RuntimeInit}.... }? ? 每個(gè) register_xxx是一個(gè)函數(shù)指針
int jniRegisterNativeMethods(C_JNIEnv* env, const char* className,const JNINativeMethod* gMethods, int numMethods);? ?RegisterNativeMethods 在VM內(nèi)部到底發(fā)生了什么? 同樣,這里只需要知道以下幾點(diǎn)即可:?
? ?gRegJni[]
?
?好了,經(jīng)過了千辛萬苦,Android的運(yùn)行時(shí)環(huán)境都已經(jīng)準(zhǔn)備就緒了,讓我們?cè)倩仡櫼幌翧ndroidRuntime的初始化都做了哪些工作,
這些操作都是相對(duì)耗時(shí)的工作,如果每個(gè)進(jìn)程都做同樣的工作勢(shì)必會(huì)影響到啟動(dòng)速度,這也是為什么我們需要通過Zygote來創(chuàng)建Android 應(yīng)用,因?yàn)橥ㄟ^Linux fork 的 copy_on_write的機(jī)制,子進(jìn)程可以將這些初始化好的內(nèi)存空間直接映射到自己的進(jìn)程空間里,不在需要做重復(fù)的工作,從而提高了應(yīng)用啟動(dòng)的速度。
可以是,Android系統(tǒng)只需要基本的運(yùn)行時(shí)環(huán)境就夠了嗎? 答案顯然是No。AndriodRuntime 只是提供了語言層面的基礎(chǔ)支持,在一個(gè)多任務(wù),多用戶的圖形操作系統(tǒng)上快速的孵化和運(yùn)行應(yīng)用程序,我們需要更多。這就是Zygote,這就是為什么在圖2中,ZygoteInit會(huì)比RuntimeInit做更多的事情。那接下來,讓我們真正進(jìn)入Zygote的世界。
?
?
3. ZygoteInit
? ? ? 當(dāng)VM準(zhǔn)備就緒,就可以運(yùn)行Java代碼了,系統(tǒng)也將在此第一次進(jìn)入Java世界,還記得app_main.cpp里面調(diào)到的 Runtime.start()的參數(shù)嗎, 那就是我們要運(yùn)行的Java類。Android支持兩個(gè)類做為起點(diǎn),一個(gè)是‘com.android.internal.os.ZygoteInit', 另一個(gè)是'com.android.internal.os.RuntimeInit'。
???? 此外Runtime_Init 類里還定義了一個(gè)ZygoteInit() 靜態(tài)方法。它在Zygote 創(chuàng)建一個(gè)新的應(yīng)用進(jìn)程的時(shí)候被創(chuàng)建,它和RuntimeInit 類的main() 函數(shù)做了以下相同的事情:
- redirectLogStreams(): 將System.out 和 System.err 輸出重定向到Android 的Log系統(tǒng)(定義在 android.util.Log).
- commonInit(): 初始化了一下系統(tǒng)屬性,其中最重要的一點(diǎn)就是設(shè)置了一個(gè)未捕捉異常的handler,當(dāng)代碼有任何未知異常,就會(huì)執(zhí)行它,調(diào)試過Android代碼的同學(xué)經(jīng)常看到的"*** FATAL EXCEPTION IN SYSTEM PROCESS" 打印就出自這里: Runtime_init.java
...
Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
...private static class UncaughtHandler implements Thread.UncaughtExceptionHandler {public void uncaughtException(Thread t, Throwable e) {try {// Don't re-enter -- avoid infinite loops if crash-reporting crashes.if (mCrashing) return;mCrashing = true;if (mApplicationObject == null) {Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);} else {Slog.e(TAG, "FATAL EXCEPTION: " + t.getName(), e);}ActivityManagerNative.getDefault().handleApplicationCrash(mApplicationObject, new ApplicationErrorReport.CrashInfo(e));} catch (Throwable t2) {...} finally {Process.killProcess(Process.myPid());System.exit(10);}}}
?
? ?? 接下來,RuntimeInit::main() 和 RuntimeInit::ZygoteInit() 分別調(diào)用里nativeFinishInit() 和 nativeZygoteInit(), 由此開始分道揚(yáng)鑣,RuntimeInit 的nativeFinishInit() 最終會(huì)調(diào)用到 app_main.cpp 里的 onStarted() 函數(shù),里面調(diào)用Java類的main() 函數(shù),然后結(jié)束進(jìn)程退出。
????
virtual void onStarted(){sp<ProcessState> proc = ProcessState::self();proc->startThreadPool();AndroidRuntime* ar = AndroidRuntime::getRuntime();ar->callMain(mClassName, mClass, mArgC, mArgV);IPCThreadState::self()->stopProcess();}???? 而 RuntimeInit::ZygoteInit() 則會(huì)調(diào)到 app_main.cpp 的 onZygoteInit()
virtual void onZygoteInit(){// Re-enable tracing now that we're no longer in Zygote.atrace_set_tracing_enabled(true);sp<ProcessState> proc = ProcessState::self();proc->startThreadPool();}??? 它僅僅是啟動(dòng)了一個(gè)ThreadPool, 剩下的工作則回到Java端由RuntimeInit::applicationInit()完成。
??? 所以,我們不妨這樣理解RuntimeInit::main(), RuntimeInit::ZygoteInit(), ZygoteInit::main()三者關(guān)系, RuntimeInit的main() 方法提供標(biāo)準(zhǔn)的Java程序運(yùn)行方式,而RuntimeInit的ZygoteInit() 則是關(guān)門為Android應(yīng)用啟動(dòng)的方法,它是在Zygote 創(chuàng)建一個(gè)新的應(yīng)用進(jìn)程的時(shí)候調(diào)用的,這部分代碼實(shí)現(xiàn)在ZygoteInit 類里。除了上面描述的差別,ZygoteInit 類里還多做了如下幾件事情,讓我們一一詳細(xì)解析。
?
? ? ?RegisterZygoteSocket()
? ? ? ?其實(shí)做的事情很簡單,就是初始化Server端(也就是Zygote)的socket。值得一提的是,這里用到的socket類型是LocalSocket, 它是Android對(duì)Linux 的 Local Socket的一個(gè)封裝。Local Socket 是Linux提供的一種基于Socket的進(jìn)程間通信方式,對(duì)Server端來講,唯一的區(qū)別就是bind到一個(gè)本地的文件描述符(fd)而不是某個(gè)IP地址和端口號(hào)。Android里很多地方用到了Local Socket做進(jìn)程間的通信,搜索一下init.rc, 你會(huì)看到很多這樣的語句:
socket adbd stream 660 system systemsocket vold stream 0660 root mountsocket netd stream 0660 root systemsocket dnsproxyd stream 0660 root inetsocket mdns stream 0660 root systemsocket rild stream 660 root radiosocket rild-debug stream 660 radio systemsocket zygote stream 660 root systemsocket installd stream 600 system systemsocket racoon stream 600 system systemsocket mtpd stream 600 system systemsocket dumpstate stream 0660 shell logsocket mdnsd stream 0660 mdnsr inet? ? ? ?當(dāng)init 解析到這樣一條語句,它將做這么幾件事:
? ? ? ? ? ? 1. 調(diào)用 create_socket() (system/core/init/util.c), 創(chuàng)建一個(gè)Socket fd, 將這個(gè)fd 與某個(gè)文件(/dev/socket/xxx, xxx 就是上面列到的名字,比如,zygote) 綁定(bind), 根據(jù)init.rc 里面定義來設(shè)定相關(guān)的用戶,組和權(quán)限。最后返回這個(gè)fd。
? ? ? ? ? ? 2. 將socket 名字(帶‘ANDROID_SOCKET_'前綴)(比如 zygote) 和 fd 注冊(cè)到init 進(jìn)程的環(huán)境變量里,這樣所有的其他進(jìn)程(所有進(jìn)程都是init的子進(jìn)程)都可以通過 getenv(name)獲取到這個(gè)fd.
? ? ? ?ZygoteInit 通過以下代碼來完成Socket Server端的配置:
? ? ? ?
private?static?final?String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";private static void registerZygoteSocket() {String env = System.getenv(ANDROID_SOCKET_ENV);fileDesc = Integer.parseInt(env);...sServerSocket = new LocalServerSocket(createFileDescriptor(fileDesc));... }
? ? Server端創(chuàng)建完畢,接下來就可以相應(yīng)客戶端連接請(qǐng)求了。我們前面講過,AndroidRuntime 一系列復(fù)雜的初始化工作可以通過fork來幫助子進(jìn)程來簡化這個(gè)過程,對(duì)了,Zygote創(chuàng)建Socket server 端就是用來響應(yīng)這個(gè)fork的請(qǐng)求。那發(fā)起請(qǐng)求的是誰?Zygote fork的子進(jìn)程又是誰?答案是ActivityManagerService 和 Android Application. 這個(gè)過程是怎樣的? 答案就在Andriod System Server的啟動(dòng)過程中。?
Preload
??? preload() 做了兩件事情:??
static void preload() {preloadClasses();preloadResources();}??? 這是Android啟動(dòng)過程中最耗時(shí)間的兩件事情。preloadClassess 將framework.jar里的preloaded-classes 定義的所有class load到內(nèi)存里,preloaded-classes 編譯Android后可以在framework/base下找到。而preloadResources 將系統(tǒng)的Resource(不是在用戶apk里定義的resource)load到內(nèi)存。
??? 資源preload到Zygoted的進(jìn)程地址空間,所有fork的子進(jìn)程將共享這份空間而無需重新load, 這大大減少了應(yīng)用程序的啟動(dòng)時(shí)間,但反過來增加了系統(tǒng)的啟動(dòng)時(shí)間。通過對(duì)preload 類和資源數(shù)目進(jìn)行調(diào)整可以加快系統(tǒng)啟動(dòng)。
GC??
static void gc() {final VMRuntime runtime = VMRuntime.getRuntime();System.gc();runtime.runFinalizationSync();System.gc();runtime.runFinalizationSync();System.gc();runtime.runFinalizationSync();}???? 為什么調(diào)了3次System.gc()和runFinalizationSync()? 這是因?yàn)間c()調(diào)用只是通知VM進(jìn)行垃圾回收,是否回收,什么時(shí)候回收全又VM內(nèi)部算法決定。GC的回收有一個(gè)復(fù)雜的狀態(tài)機(jī)控制,通過多次調(diào)用,可以使得盡可能多的資源得到回收。gc()必須在fork之前完成(接下來的StartSystemServer就會(huì)有fork操作),這樣將來被復(fù)制出來的子進(jìn)程才能有盡可能少的垃圾內(nèi)存沒有釋放。
Start SystemServer
? ? ? 想起init.rc 里面啟動(dòng)zygote的參數(shù)了嗎, "--start-system-server",?System Server 是Zygote fork 的第一個(gè)Java 進(jìn)程, 這個(gè)進(jìn)程非常重要,因?yàn)樗麄冇泻芏嗟南到y(tǒng)線程,提供所有核心的系統(tǒng)服務(wù),我們可以用 'ps -t |grep <system server pid>'來看看都有哪些線程,排除前面列出的幾個(gè)Java 虛擬機(jī)線程,還有
system 1176 1163 774376 51144 00000000 b76c4ab6 S SensorService system 1177 1163 774376 51144 00000000 b76c49eb S er.ServerThread system 1178 1163 774376 51144 00000000 b76c49eb S UI system 1179 1163 774376 51144 00000000 b76c49eb S WindowManager system 1180 1163 774376 51144 00000000 b76c49eb S ActivityManager system 1182 1163 774376 51144 00000000 b76c4d69 S ProcessStats system 1183 1163 774376 51144 00000000 b76c2bb6 S FileObserver system 1184 1163 774376 51144 00000000 b76c49eb S PackageManager system 1185 1163 774376 51144 00000000 b76c49eb S AccountManagerS system 1187 1163 774376 51144 00000000 b76c49eb S PackageMonitor system 1188 1163 774376 51144 00000000 b76c4ab6 S UEventObserver system 1189 1163 774376 51144 00000000 b76c4d69 S BatteryUpdateTi system 1190 1163 774376 51144 00000000 b76c49eb S PowerManagerSer system 1191 1163 774376 51144 00000000 b76c2ff6 S AlarmManager system 1192 1163 774376 51144 00000000 b76c4d69 S SoundPool system 1193 1163 774376 51144 00000000 b76c4d69 S SoundPoolThread system 1194 1163 774376 51144 00000000 b76c49eb S InputDispatcher system 1195 1163 774376 51144 00000000 b76c49eb S InputReader system 1196 1163 774376 51144 00000000 b76c49eb S BluetoothManage system 1197 1163 774376 51144 00000000 b76c49eb S MountService system 1198 1163 774376 51144 00000000 b76c4483 S VoldConnector system 1199 1163 774376 51144 00000000 b76c49eb S CallbackHandler system 1201 1163 774376 51144 00000000 b76c4483 S NetdConnector system 1202 1163 774376 51144 00000000 b76c49eb S CallbackHandler system 1203 1163 774376 51144 00000000 b76c49eb S NetworkStats system 1204 1163 774376 51144 00000000 b76c49eb S NetworkPolicy system 1205 1163 774376 51144 00000000 b76c49eb S WifiP2pService system 1206 1163 774376 51144 00000000 b76c49eb S WifiStateMachin system 1207 1163 774376 51144 00000000 b76c49eb S WifiService system 1208 1163 774376 51144 00000000 b76c49eb S ConnectivitySer system 1214 1163 774376 51144 00000000 b76c49eb S WifiManager system 1215 1163 774376 51144 00000000 b76c49eb S Tethering system 1216 1163 774376 51144 00000000 b76c49eb S CaptivePortalTr system 1217 1163 774376 51144 00000000 b76c49eb S WifiWatchdogSta system 1218 1163 774376 51144 00000000 b76c49eb S NsdService system 1219 1163 774376 51144 00000000 b76c4483 S mDnsConnector system 1220 1163 774376 51144 00000000 b76c49eb S CallbackHandler system 1227 1163 774376 51144 00000000 b76c49eb S SyncHandlerThre system 1228 1163 774376 51144 00000000 b76c49eb S AudioService system 1229 1163 774376 51144 00000000 b76c49eb S backup system 1233 1163 774376 51144 00000000 b76c49eb S AppWidgetServic system 1240 1163 774376 51144 00000000 b76c4d69 S AsyncTask #1 system 1244 1163 774376 51144 00000000 b76c42a3 S Thread-64 system 1284 1163 774376 51144 00000000 b76c4d69 S AsyncTask #2 system 1316 1163 774376 51144 00000000 b76c2bb6 S UsbService host system 1319 1163 774376 51144 00000000 b76c4d69 S watchdog system 1330 1163 774376 51144 00000000 b76c49eb S LocationManager system 1336 1163 774376 51144 00000000 b76c2ff6 S Binder_3 system 1348 1163 774376 51144 00000000 b76c49eb S CountryDetector system 1354 1163 774376 51144 00000000 b76c49eb S NetworkTimeUpda system 1360 1163 774376 51144 00000000 b76c2ff6 S Binder_4 system 1391 1163 774376 51144 00000000 b76c2ff6 S Binder_5 system 1395 1163 774376 51144 00000000 b76c2ff6 S Binder_6 system 1397 1163 774376 51144 00000000 b76c2ff6 S Binder_7 system 1516 1163 774376 51144 00000000 b76c4d69 S SoundPool system 1517 1163 774376 51144 00000000 b76c4d69 S SoundPoolThread system 1692 1163 774376 51144 00000000 b76c4d69 S AsyncTask #3 system 1694 1163 774376 51144 00000000 b76c4d69 S AsyncTask #4 system 1695 1163 774376 51144 00000000 b76c4d69 S AsyncTask #5 system 1791 1163 774376 51144 00000000 b76c4d69 S pool-1-thread-1 system 2758 1163 774376 51144 00000000 b76c4d69 S AudioTrack system 2829 1163 774376 51144 00000000 b76c49eb S KeyguardWidgetP看到大名鼎鼎的WindowManager, ActivityManager了嗎?對(duì)了,它們都是運(yùn)行在system_server的進(jìn)程里。還有很多“Binder-x"的線程,它們是各個(gè)Service為了響應(yīng)應(yīng)用程序遠(yuǎn)程調(diào)用請(qǐng)求而創(chuàng)建的。除此之外,還有很多內(nèi)部的線程,比如 ”UI thread", "InputReader", "InputDispatch" 等等,我們將在后續(xù)的文章里將這些模塊具體分析。本文,我們只關(guān)心System Server是如何創(chuàng)建起來的。
?
4. System Server 啟動(dòng)流程
這個(gè)過程代碼很多,涉及到很多類,我們用一張時(shí)序圖來描述這個(gè)過程。圖中不同的顏色代表運(yùn)行在不同的線程中。
?
1.? ZygoteInit fork 出一個(gè)新的進(jìn)程,這個(gè)進(jìn)程就是SystemServer進(jìn)程。
2. ?fork出來的子進(jìn)程在handleSystemServerProcess?里開始初始化工作,初始化分兩步,一部在native 完成,另外一部分(大部分)在Java端完成。 native端的工作在AppRuntime(AndroidRuntime的子類)::onZygoteInit()完成,做的一件事情就是啟動(dòng)了一個(gè)Thread, 這個(gè)Thread是SystemServer的主線程(最左邊的粉色方塊), 負(fù)責(zé)接收來至其他進(jìn)程的Binder調(diào)用請(qǐng)求。代碼如下
void ProcessState::spawnPooledThread(bool isMain) {if (mThreadPoolStarted) {String8 name = makeBinderThreadName(); //“Binder_1"sp<Thread> t = new PoolThread(isMain);t->run(name.string());} }virtual bool threadLoop() {
? ? ?IPCThreadState::self()->joinThreadPool(mIsMain); //阻塞知道被Binder driver喚醒
? ? ?return false;?
? }
3. nativeZygoteInit() 完成后, 接下來開始Java層的初始化,這個(gè)流程比較長,也比較復(fù)雜,我們分成很多步進(jìn)行講解。初始化的入口是SystemServer的main() 函數(shù),這里又調(diào)用了Native的 Init1(). Init1實(shí)現(xiàn)在com_android_server_SystemServer.cpp, ? 最終調(diào)用到的函數(shù)是system_init(). system_init()的實(shí)現(xiàn)如下:
extern "C" status_t system_init() { sp<ProcessState> proc(ProcessState::self());sp<IServiceManager> sm = defaultServiceManager(); sm->asBinder()->linkToDeath(grim, grim.get(), 0); property_get("system_init.startsurfaceflinger", propBuf, "1");if (strcmp(propBuf, "1") == 0) {// Start the SurfaceFlinger SurfaceFlinger::instantiate(); //初始化 SurfaceFlingerandroid_vt = 7;}property_get("system_init.startsensorservice", propBuf, "1");if (strcmp(propBuf, "1") == 0) {// Start the sensor service SensorService::instantiate(); // 初始化SensorService.} ALOGI("System server: starting Android runtime.\n");AndroidRuntime* runtime = AndroidRuntime::getRuntime(); JNIEnv* env = runtime->getJNIEnv();... jclass clazz = env->FindClass("com/android/server/SystemServer"); jmethodID methodId = env->GetStaticMethodID(clazz, "init2", "()V");... env->CallStaticVoidMethod(clazz, methodId); ProcessState::self()->startThreadPool();IPCThreadState::self()->joinThreadPool(); return NO_ERROR; }
?
?幾點(diǎn)需要注意:
?A. SurfaceFlinger Service可以運(yùn)行在System_Server 進(jìn)程里,也可以運(yùn)行在獨(dú)立的進(jìn)程里,如果是后者的話,需要在init.rc 里加上一句 "setprop system_init.startsurfaceflinger=1" 并且確保 service surfaceflinger 沒有被 “disable”
?B. init2 實(shí)現(xiàn)在System_Server.java,我們后面會(huì)詳細(xì)介紹。
?
4. system_init() 最后,join_threadpool() 將當(dāng)前線程掛起,等待binder的請(qǐng)求。這個(gè)thread的名字就是"Binder_1". 關(guān)于service 和 binder的內(nèi)部機(jī)制,請(qǐng)參考文章http://www.cnblogs.com/samchen2009/p/3316001.html
?
5. init2: 至此,system server的native初始化工作完成,又重新回到了Java端,在這里,很多非常重要的系統(tǒng)服務(wù)將被啟動(dòng)。 這些工作將在一個(gè)新的線程內(nèi)開始,線程名"android.server.ServerThread", 見下圖的綠色條塊。在ServerThread里,SystemServer 首先創(chuàng)建了兩個(gè)線程,UI thread 和 WindowManager thread, 見圖中的橙色和桃色條塊,這兩個(gè)thread的handle將被傳給某些Service的構(gòu)造函數(shù),部分的啟動(dòng)工作會(huì)分發(fā)到這兩個(gè)Thread內(nèi)進(jìn)行。
? ? 每個(gè)Thread都最終進(jìn)入等待循環(huán),這里用到了Android的Looper機(jī)制,Looper,Handler是Android的進(jìn)程內(nèi)的消息傳遞和處理機(jī)制,我們將會(huì)在文章?http://www.cnblogs.com/samchen2009/p/3316004.html?里詳細(xì)介紹,這里,我們只需要知道,Looper在某個(gè)線程里睡眠等待消息隊(duì)列里的消息,然后在某個(gè)特定的Handler里來處理這個(gè)消息。換句話說,指定某件事情在某個(gè)線程里進(jìn)行處理。
6. 接下來,System Server會(huì)啟動(dòng)一系列的Service, 其中最重要的就是Acitivity Manager 和Window Manager.
從圖中可以看出,Activity Manager 有一個(gè)Looper Thread, AThread。這里請(qǐng)注意Binder Thread和 Looper的區(qū)別,我們?cè)诤竺鏁?huì)有專門的文章介紹它們。Android里大量用到了Binder 與 Looper的組合,其中很重要的一個(gè)原因是為了解決多線程中復(fù)雜的同步問題,通過一個(gè)Looper和對(duì)應(yīng)的Message 隊(duì)列,可以將來著不同進(jìn)程的Binder 調(diào)用序列化,而不需要維護(hù)復(fù)雜的且容易出問題的鎖。
WindowManager 類似,他的Handler Thread 是我們剛才提到的System server 啟動(dòng)初期創(chuàng)建的兩個(gè)Handler線程之一,WMThread. 他的Binder線程會(huì)由Kernel的Binder Driver來指定。
除了ActivityManager Service 和 WindowManager Service, 還有很多其他的服務(wù)相繼啟動(dòng),這里不再詳述,只需要知道一個(gè)Service啟動(dòng)需要的幾個(gè)步驟:
?????? 1. 初始化Service 對(duì)象,獲得IBinder對(duì)象。
?????? 2. 啟動(dòng)后臺(tái)線程,并進(jìn)入Loop等待。
?????? 3. 將自己注冊(cè)到Service Manager, 讓其他進(jìn)程通過名字可以獲得遠(yuǎn)程調(diào)用必須的IBinder的對(duì)象。
7. 毫無疑問,這么多服務(wù)之間是有依賴關(guān)系的,比如說,ActivityManager Service 在WindowManager Service 初始化完成之前是不能啟動(dòng)應(yīng)用的。那如何控制這些先后順序的?這里由System server的啟動(dòng)線程(下圖中的綠色條快)通過SystemReady()接口來完成。每個(gè)系統(tǒng)服務(wù)必須實(shí)現(xiàn)一個(gè)SystemReady() 接口,當(dāng)被調(diào)用,表明系統(tǒng)已經(jīng)OK, 該服務(wù)可以訪問(直接或間接)其他服務(wù)的資源。最后一個(gè)被調(diào)到的服務(wù)就是AcitivyManager Service. AM的SystemReady() 是通過Runnable 在另外一個(gè)線程里完成,參加下圖中注釋8下方的那個(gè)箭頭。在這個(gè)Runnable里面要做的事情,就是將當(dāng)前排在最頂層的一個(gè)應(yīng)用程序啟動(dòng) - resumeTopActivityLocked(),通常來講,這就是我們常說的‘HOME’, 當(dāng)然,這里可以指定其他的應(yīng)用程序作為Startup應(yīng)用,比如說GoogleTV 里面可以將電視應(yīng)用作為啟動(dòng)程序,這樣用戶啟動(dòng)后直接可以看到節(jié)目,類似現(xiàn)在家里的機(jī)頂盒。此外,ActivityManager Service 還會(huì)廣播 BOOT_COMPLETED 事件給整個(gè)系統(tǒng),一般來說,很多應(yīng)用的后臺(tái)Service可以通過注冊(cè)這個(gè)Event的 Receiver 來監(jiān)聽并啟動(dòng)。啟動(dòng)Home的代碼如下
boolean startHomeActivityLocked(int userId) {...Intent intent = new Intent(...);... intent.addCategory(Intent.CATEGORY_HOME);... mMainStack.startActivityLocked(null, intent, null, aInfo,null, null, 0, 0, 0, null, 0, null, false, null);... }?
8.?Android應(yīng)用的啟動(dòng)比較復(fù)雜,我們會(huì)在專門的章節(jié)里面去研究ActivityManager的工作細(xì)節(jié),此處,我們只需要知道ActivityStack 是存在當(dāng)前運(yùn)行Activity的棧,resumeTopActivityLocked() 從其中找到要啟動(dòng)的那一個(gè)(在最開始,該棧是空的,因?yàn)樾枰ㄟ^moveTaskFromFrontLocked() 將‘Home' 推到該棧中),如果該應(yīng)用從來沒有啟動(dòng)過,我們需要通過AcitivyManagerService 為其創(chuàng)建一個(gè)進(jìn)程。注意!進(jìn)程 并不是由ActivityManager創(chuàng)建的,別忘了,我們前面提到Zygote是所有Android 應(yīng)用的孵化器,對(duì),ActivityManager 只是通知Zygote創(chuàng)建而已。這個(gè)通信是通過Process.java里面實(shí)現(xiàn)的,具體代碼如下:
static LocalSocket sZygoteSocket; private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)throws ZygoteStartFailedEx {openZygoteSocketIfNeeded();try {...sZygoteWriter.write(arg);}...sZygoteWriter.flush(); //發(fā)送后等待... ... result.pid = sZygoteInputStream.readInt();...return result;} sZygoteSocket = null;} }到此為止,System Server的啟動(dòng)已經(jīng)完成,Zygote的啟動(dòng)也已經(jīng)完成,接下來我們介紹Zygote進(jìn)程生命里做的唯一一件事,克隆自己。
5. Fork?
?在Process.java 發(fā)送fork 請(qǐng)求之前,Zygote已經(jīng)準(zhǔn)備好了服務(wù)器端,這個(gè)我們已經(jīng)在前面的Zygote Init 章節(jié)里介紹過了。此處我們簡要分析一下Zygote Server端收到請(qǐng)求的處理。代碼在ZygoteInit.java 的runSelectLoop()里,
?
private static void runSelectLoop() throws MethodAndArgsCaller {ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();FileDescriptor[] fdArray = new FileDescriptor[4];fds.add(sServerSocket.getFileDescriptor());peers.add(null);while (true) {/* 在fork 子進(jìn)程之前做把GC而不是在每個(gè)子進(jìn)程里自己做,可以提高效率,但也不能每次都做因?yàn)镚C還是很耗時(shí)的。*/if (loopCount <= 0) {gc();loopCount = GC_LOOP_COUNT;} else {loopCount--;}try {fdArray = fds.toArray(fdArray);index = selectReadable(fdArray); //select 阻塞等待} catch (IOException ex) {...}/* 接收新的連接 */else if (index == 0) {ZygoteConnection newPeer = acceptCommandPeer();peers.add(newPeer);fds.add(newPeer.getFileDesciptor());} else {boolean done;/* 在這里完成fork操作 */done = peers.get(index).runOnce();if (done) {peers.remove(index);fds.remove(index);}}}} boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {...try {args = readArgumentList();descriptors = mSocket.getAncillaryFileDescriptors();} catch (IOException ex) {...}FileDescriptor childPipeFd = null;FileDescriptor serverPipeFd = null;/*
if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) {
? ? ? ? ? ? ?FileDescriptor[] pipeFds = Libcore.os.pipe();?
? ? ? ? ? ? ?childPipeFd = pipeFds[1];?
? ? ? ? ? ? ?serverPipeFd = pipeFds[0];?
? ? ? ? ? ? ?ZygoteInit.setCloseOnExec(serverPipeFd, true);?
? ? ? ? ?}
Android 應(yīng)用的啟動(dòng)在handleChildProc里完成:
private void handleChildProc(Arguments parsedArgs,FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)throws ZygoteInit.MethodAndArgsCaller {closeSocket(); // 不需要服務(wù)端的socket ZygoteInit.closeServerSocket();...if (parsedArgs.runtimeInit) { //從Process.java 來的都為trueif (parsedArgs.invokeWith != null) {WrapperInit.execApplication(parsedArgs.invokeWith,parsedArgs.niceName, parsedArgs.targetSdkVersion,pipeFd, parsedArgs.remainingArgs); // 啟動(dòng)命令行程序} else {RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,parsedArgs.remainingArgs); // 幾乎所有的應(yīng)用啟動(dòng)都走這條路 }} else {...if (parsedArgs.invokeWith != null) {WrapperInit.execStandalone(parsedArgs.invokeWith,parsedArgs.classpath, className, mainArgs);} else {...try {ZygoteInit.invokeStaticMain(cloader, className, mainArgs);} catch (RuntimeException ex) {...}}}}這里走的是RuntimeInit.ZygoteInit(), 和startSystemServer 一樣,最后invokeStaticMain(,""android.app.ActivityThread",); invokeStatickMain() 函數(shù)實(shí)現(xiàn)是
static void invokeStaticMain(ClassLoader loader,String className, String[] argv) throws zygoteInit.MethodAndArgsCaller {...throw new ZygoteInit.MethodAndArgsCaller(m, argv);}?
細(xì)心的讀者可能會(huì)問這么幾個(gè)問題:
1. 為什么不直接Call 相應(yīng)的Java函數(shù),而是通過一個(gè)exception? ?MethodAndArgsCaller. 這里Android 巧妙的運(yùn)用到了Java Exception的一些設(shè)計(jì)特性。Execption一大特性就是當(dāng)發(fā)生或拋出異常的時(shí)候,可以從發(fā)生錯(cuò)誤的地方順著調(diào)用棧回溯直到找到捕捉該異常的代碼段。捕捉該異常的代碼如下
public static void main(String argv[]) {...try {runSelectLoop();closeServerSocket();} catch (MethodAndArgsCaller caller) {caller.run(); //真正的入口在這里。} catch (RuntimeException ex) {...}}這下你明白為什么總在dumpstate 文件里看到以下的調(diào)用棧了吧
...at java.lang.reflect.Method.invokeNative(Native Method)at java.lang.reflect.Method.invoke(Method.java:511)at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)at dalvik.system.NativeStart.main(Native Method) 2. 為什么所有的應(yīng)用都從“android.app.ActivityThread")開始? 在這里留個(gè)伏筆,我們會(huì)在http://www.cnblogs.com/samchen2009/p/3315993.html 系統(tǒng)的介紹Android Activity 從啟動(dòng)到顯示的整個(gè)過程。
應(yīng)用程序啟動(dòng)完畢,Zygote有重新睡去,等待新的應(yīng)用程序啟動(dòng)請(qǐng)求。
?
6. 善后工作
? ? ? 是不是到此之后,Zygote的工作變得很輕松了,可以宜養(yǎng)天年了?可惜現(xiàn)代社會(huì),哪個(gè)父母把孩子養(yǎng)大就可以撒手不管了?尤其是像Sytem Server 這樣肩負(fù)社會(huì)重任的大兒子,出問題了父母還是要幫一把的。這里,Zygote會(huì)默默的在后臺(tái)凝視這自己的大兒子,一旦發(fā)現(xiàn)System Server 掛掉了,將其回收,然后將自己殺掉,重新開始新的一生,?可憐天下父母心啊。這段實(shí)現(xiàn)在代碼 :dalvik/vm/native/dalvik_system_zygote.cpp 中,
? ? ??
static void Dalvik_dalvik_system_Zygote_forkSystemServer(const u4* args, JValue* pResult){...pid_t pid;pid = forkAndSpecializeCommon(args, true); ...if (pid > 0) {int status;gDvm.systemServerPid = pid; /* WNOHANG 會(huì)讓waitpid 立即返回,這里只是為了預(yù)防上面的賦值語句沒有完成之前SystemServer就crash 了*/if (waitpid(pid, &status, WNOHANG) == pid) {ALOGE("System server process %d has died. Restarting Zygote!", pid);kill(getpid(), SIGKILL);}}RETURN_INT(pid); }/* 真正的處理在這里 */ static void sigchldHandler(int s) {...pid_t pid;int status;...while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {...if (pid == gDvm.systemServerPid) { ...kill(getpid(), SIGKILL);}}... }static void Dalvik_dalvik_system_Zygote_fork(const u4* args, JValue* pResult) {pid_t pid;...setSignalHandler(); //signalHandler 在這里注冊(cè)...pid = fork();...RETURN_INT(pid); }
? ? 在Unix-like系統(tǒng),父進(jìn)程必須用 waitpid 等待子進(jìn)程的退出,否則子進(jìn)程將變成"Zombie" (僵尸)進(jìn)程,不僅系統(tǒng)資源泄漏,而且系統(tǒng)將崩潰(沒有system server,所有Android應(yīng)用程序都無法運(yùn)行)。但是waitpid() 是一個(gè)阻塞函數(shù)(WNOHANG參數(shù)除外),所以通常做法是在signal 處理函數(shù)里進(jìn)行無阻塞的處理,因?yàn)槊總€(gè)子進(jìn)程退出的時(shí)候,系統(tǒng)會(huì)發(fā)出 SIGCHID 信號(hào)。Zygote會(huì)把自己殺掉, 那父親死了,所有的應(yīng)用程序不就成為孤兒了? 不會(huì),因?yàn)楦高M(jìn)程被殺掉后系統(tǒng)會(huì)自動(dòng)給所有的子進(jìn)程發(fā)生SIGHUP信號(hào),該信號(hào)的默認(rèn)處理就是將殺掉自己退出當(dāng)前進(jìn)程。但是一些后臺(tái)進(jìn)程(Daemon)可以通過設(shè)置SIG_IGN參數(shù)來忽略這個(gè)信號(hào),從而得以在后臺(tái)繼續(xù)運(yùn)行。
? ? ??
?
總結(jié)
Zygote和System Server的啟動(dòng)過程終于介紹完了,讓我們對(duì)著上面這張完整的類圖再來重溫一下這個(gè)過程吧。
1. ?init 根據(jù)init.rc 運(yùn)行 app_process, 并攜帶‘--zygote' 和 ’--startSystemServer' 參數(shù)。
2. ?AndroidRuntime.cpp::start() 里將啟動(dòng)JavaVM,并且注冊(cè)所有framework相關(guān)的系統(tǒng)JNI接口。
3. ?第一次進(jìn)入Java世界,運(yùn)行ZygoteInit.java::main() 函數(shù)初始化Zygote. Zygote 并創(chuàng)建Socket的server 端。
4. ?然后fork一個(gè)新的進(jìn)程并在新進(jìn)程里初始化SystemServer. Fork之前,Zygote是preload常用的Java類庫,以及系統(tǒng)的resources,同時(shí)GC()清理內(nèi)存空間,為子進(jìn)程省去重復(fù)的工作。
5. ?SystemServer 里將所有的系統(tǒng)Service初始化,包括ActivityManager 和 WindowManager, 他們是應(yīng)用程序運(yùn)行起來的前提。
6. ?依次同時(shí),Zygote監(jiān)聽服務(wù)端Socket,等待新的應(yīng)用啟動(dòng)請(qǐng)求。
7. ?ActivityManager ready 之后尋找系統(tǒng)的“Startup” Application, 將請(qǐng)求發(fā)給Zygote。
8. ?Zygote收到請(qǐng)求后,fork出一個(gè)新的進(jìn)程。
9. ?Zygote監(jiān)聽并處理SystemServer 的 SIGCHID 信號(hào),一旦System Server崩潰,立即將自己殺死。init會(huì)重啟Zygote.
原文地址:?http://www.cnblogs.com/samchen2009/p/3294713.html
總結(jié)
以上是生活随笔為你收集整理的图解Android - Zygote, System Server 启动分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android 5.1 Lollipop
- 下一篇: android sina oauth2.