鍍金池/ 教程/ Android/ 第4章 ?深入理解 Zygote
第4章 ?深入理解 Zygote
第10章 深入理解MediaScanner
第3章 ?深入理解init
第8章 ?深入理解Surface系統(tǒng)
第5章 深入理解常見類
第7章 ?深入理解Audio系統(tǒng)
第一章 ?閱讀前的準(zhǔn)備工作
<span>第6章 深入理解Binder</span>
第9章 ?深入理解Vold和Rild
第2章? 深入理解JNI

第4章 ?深入理解 Zygote

本章主要內(nèi)容

·? 深入分析zygote,并介紹system_server進(jìn)程的初始化工作。

本章涉及的源代碼文件名及位置

下面是我們本章分析的源碼文件名及其位置。

·? App_main.cpp

framework/base/cmds/app_process/App_main.cpp

·? AndroidRuntime.h

framework/base/include/android_runtime/AndroidRuntime.h

·? android_debug_JNITest.cpp

framework/base/core/jni/android_debug_JNITest.cpp

·? ZygoteInit.java

framework/base/core/java/com/android/internal/os/ZygoteInit.java

·? dalvik_system_Zygote.c

dalvik/vm/native/dalvik_system_Zygote.c

·? RuntimeInit.java

framework/base/core/java/com/android/internal/os/RuntimeInit.java

·? SystemServer.java

framework/base/services/java/com/android/server/SystemServer.java

·? com_android_server_SystemServer.cpp

framework/base/services/jni/com_android_server_SystemServer.cpp

·? system_init.cpp

framework/base/cmds/system_server/library/system_init.cpp

·? Watchdog.java

framework/base/services/java/com/android/server/Watchdog.java

·? ActivityManagerService.java

framework/base/services/java/com/android/server/am/ActivityManagerService.java

·? Process.java

framework/base/core/java/android/os/Process.java

·? ZygoteConnection.java

framework/base/core/java/com/android/internal/os/ZygoteConnection.java

?

4.1 ?綜述

讀者可能已經(jīng)知道,Android系統(tǒng)存在著兩個(gè)完全不同的世界:

·? Java世界,Google放出的SDK主要就是針對這個(gè)世界的。在這個(gè)世界中運(yùn)行的程序都是基于Dalvik虛擬機(jī)的Java程序。

·? Native世界,也就是用Native語言C或C++開發(fā)的程序,它們組成了Native世界。

初次接觸Android的人,可能會(huì)有幾個(gè)疑問:

·? Android是基于Linux內(nèi)核構(gòu)建的,它最早存在的肯定是Native世界,那么Java世界是什么時(shí)候創(chuàng)建的呢?

·? 我們都知道,程序運(yùn)行時(shí)一定要有一個(gè)進(jìn)程,但是我們在編寫Activity、Service的時(shí)候卻絕少接觸到“進(jìn)程”這一概念。當(dāng)然這是Google有意為之,但這些Activity或Service卻又不能脫離“進(jìn)程”而存在。那么,這個(gè)“進(jìn)程”是怎么創(chuàng)建和運(yùn)行的呢?這是一個(gè)值得琢磨的問題。

·? 在程序中,我們經(jīng)常使用系統(tǒng)的Service,那么,這些Service在哪里呢?

這些問題的答案都和我們本章的兩位主人公zygote和system_server有關(guān)。zygote這個(gè)詞的中文意思是“受精卵”,它和Android系統(tǒng)中的Java世界有著重要關(guān)系。而system_server則“人如其名”,系統(tǒng)中重要的service都駐留于Java中。

zygote和system_server這兩個(gè)進(jìn)程分別是Java世界的半邊天,任何一個(gè)進(jìn)程的死亡,都會(huì)導(dǎo)致Java世界的崩潰,夠厲害吧?下面我們就來見識見識這兩個(gè)重量級人物。

?

4.2 ?Zygote分析

Zygote本身是一個(gè)Native的應(yīng)用程序,和驅(qū)動(dòng)、內(nèi)核等均無關(guān)系。根據(jù)第3章對于init的介紹我們可以知道,Zygote是由init進(jìn)程根據(jù)init.rc文件中的配置項(xiàng)而創(chuàng)建的。在分析它之前,我們有必要先簡單介紹一下“zygote”這個(gè)名字的來歷。zygote最初的名字叫“app_process”,這個(gè)名字是在Android.mk文件中被指定的,但app_process在運(yùn)行過程中,通過Linux下的pctrl系統(tǒng)調(diào)用將自己的名字換成了“zygote”,所以我們通過ps命令看到的進(jìn)程名是“zygote”。

zygote玩的這一套“換名把戲”并不影響我們的分析,它的原型app_process所對應(yīng)的源文件是App_main.cpp,代碼如下所示:

[-->App_main.cpp]

int main(int argc, const char* const argv[])

{

? /*

?? Zygote進(jìn)程由init通過fork而來,我們回顧一下init.rc中設(shè)置的啟動(dòng)參數(shù):

??? -Xzygote/system/bin --zygote --start-system-server

? */

??? mArgC= argc;

??? mArgV= argv;

???

???mArgLen = 0;

??? for(int i=0; i<argc; i++) {

???????mArgLen += strlen(argv[i]) + 1;

??? }

???mArgLen--;

???AppRuntime runtime;

??? // 調(diào)用Appruntime的addVmArguments,這個(gè)函數(shù)很簡單,讀者可以自行分析

??? int i= runtime.addVmArguments(argc, argv);

??? if (i< argc) {

?????? //設(shè)置runtime的mParentDir為/system/bin

???????runtime.mParentDir = argv[i++];

? ??}

?

??? if (i< argc) {

???????arg = argv[i++];

??????? if(0 == strcmp("--zygote", arg)) {

??????????//我們傳入的參數(shù)滿足if的條件,而且下面的startSystemServer的值為true

???????????bool startSystemServer = (i < argc) ?

??????????????????? strcmp(argv[i],"--start-system-server") == 0 : false;

???????????setArgv0(argv0, "zygote");

//設(shè)置本進(jìn)程名為zygote,這正是前文所講的“換名把戲”。

?????? ?????set_process_name("zygote");

???????????????? //①調(diào)用runtime的start,注意第二個(gè)參數(shù)startSystemServer為true

???????????runtime.start("com.android.internal.os.ZygoteInit",

??????? ??????????????????????startSystemServer);

??????? }

????????......

??? }

?? ??????......

}

Zygote的這個(gè)main函數(shù)雖很簡單,但其重要功能卻是由AppRuntime的start來完成的。下面,我們就來具體分析這個(gè)AppRuntime。

4.2.1 ?AppRuntime分析

AppRuntime類的聲明和實(shí)現(xiàn)均在App_main.cpp中,它是從AndroidRuntime類派生出來的,圖4-1顯示了這兩個(gè)類的關(guān)系和一些重要函數(shù):

http://wiki.jikexueyuan.com/project/deep-android-v1/images/chapter4/image001.png" alt="image" />

圖4-1 ?AppRuntime和AndroidRuntime的關(guān)系

由上圖我們可知:

·? AppRuntime重載了onStarted、onZygoteInit和onExit函數(shù)。

前面的代碼中調(diào)用了AndroidRuntime的start函數(shù),由圖4-1可知,這個(gè)start函數(shù)使用的是基類AndroidRuntime的start,我們來分析一下它,注意它的調(diào)用參數(shù)。

[-->AndroidRuntime.cpp]

void AndroidRuntime::start(const char*className, const bool startSystemServer)

{

??? //className的值是"com.android.internal.os.ZygoteInit"

??? //startSystemServer的值是true

??? char*slashClassName = NULL;

??? char*cp;

???JNIEnv* env;

?? ?blockSigpipe();//處理SIGPIPE信號

?? ??......

?

??? constchar* rootDir = getenv("ANDROID_ROOT");

if (rootDir == NULL) {

//如果環(huán)境變量中沒有ANDROID_ROOT,則新增該變量,并設(shè)置值為“/system"

???????rootDir = “/system";

??????? ......

???????setenv("ANDROID_ROOT", rootDir, 1);

??? }

?

??? //① 創(chuàng)建虛擬機(jī)

??? if(startVm(&mJavaVM, &env) != 0)

??????? goto bail;

?

? ???//②注冊JNI函數(shù)

??? if(startReg(env) < 0) {

????????goto bail;

??? ??}

?

??? jclassstringClass;

???jobjectArray strArray;

???jstring classNameStr;

???jstring startSystemServerStr;

?

???stringClass = env->FindClass("java/lang/String");

??? //創(chuàng)建一個(gè)有兩個(gè)元素的String數(shù)組,即Java代碼 String strArray[] = new String[2]

???strArray = env->NewObjectArray(2, stringClass, NULL);

?

??classNameStr = env->NewStringUTF(className);

?? //設(shè)置第一個(gè)元素為"com.android.internal.os.ZygoteInit"

???env->SetObjectArrayElement(strArray, 0, classNameStr);

???startSystemServerStr = env->NewStringUTF(startSystemServer ?

????????????????????????????????????????????????"true" : "false");

?? //設(shè)置第二個(gè)元素為"true",注意這兩個(gè)元素都是String類型,即字符串。

???env->SetObjectArrayElement(strArray, 1, startSystemServerStr);

?

??? jclassstartClass;

???jmethodID startMeth;

?

???slashClassName = strdup(className);

?? /*

???? 將字符串“com.android.internal.os.ZygoteInit”中的“. ”換成“/”,

???? 這樣就變成了“com/android/internal/os/ZygoteInit”,這個(gè)名字符合JNI規(guī)范,

??? ?我們可將其簡稱為ZygoteInit類。

?? */

??? for(cp = slashClassName; *cp != '\0'; cp++)

??????? if(*cp == '.')

???????????*cp = '/';

?

???startClass = env->FindClass(slashClassName);

????......

??? //找到ZygoteInit類的static main函數(shù)的jMethodId。

???startMeth = env->GetStaticMethodID(startClass, "main",

?????????????????????????????????????????????"([Ljava/lang/String;)V");

?????......

???? /*

??????? ③通過JNI調(diào)用Java函數(shù),注意調(diào)用的函數(shù)是main,所屬的類是

????????? com.android.internal.os.ZygoteInit,傳遞的參數(shù)是

????????? “com.android.internal.os.ZygoteInit true”,

????????? 調(diào)用ZygoteInit的main函數(shù)后,Zygote便進(jìn)入了Java世界!

????????? 也就是說,Zygote是開創(chuàng)Android系統(tǒng)中Java世界的盤古。

???? */

??? ??env->CallStaticVoidMethod(startClass,startMeth, strArray);

?? ?//Zygote退出,在正常情況下,Zygote不需要退出。

?? ?if(mJavaVM->DetachCurrentThread() != JNI_OK)

???????LOGW("Warning: unable to detach main thread\n");

??? if(mJavaVM->DestroyJavaVM() != 0)

???????LOGW("Warning: VM did not shut down cleanly\n");

?

bail:

???free(slashClassName);

}

通過上面的分析,我們找到了三個(gè)關(guān)鍵點(diǎn),它們共同組成了開創(chuàng)Android系統(tǒng)中Java世界的三部曲?,F(xiàn)在讓我們來具體地觀察它們。

1. 創(chuàng)建虛擬機(jī)——startVm

我們先看三部曲中的第一部:startVm,這個(gè)函數(shù)沒有特別之處,就是調(diào)用JNI的虛擬機(jī)創(chuàng)建函數(shù),但是虛擬機(jī)創(chuàng)建時(shí)的一些參數(shù)卻是在startVm中被確定的,其代碼如下所示:

[-->AndroidRuntime.cpp]

int AndroidRuntime::startVm(JavaVM** pJavaVM,JNIEnv** pEnv)

{

? ?//這個(gè)函數(shù)絕大部分代碼都是設(shè)置虛擬機(jī)的參數(shù),我們只分析其中的兩個(gè)。

??/*

???? ?下面的代碼是用來設(shè)置JNI check選項(xiàng)的。JNIcheck 指的是Native層調(diào)用JNI函數(shù)時(shí),

系統(tǒng)所做的一些檢查工作。例如調(diào)用NewUTFString函數(shù)時(shí),系統(tǒng)會(huì)檢查傳入的字符串是不是符合

???? UTF-8的要求。JNI check還能檢查資源是否正確釋放。但這個(gè)選項(xiàng)也有其副作用,比如:

???? 1)因?yàn)闄z查工作比較耗時(shí),所以會(huì)影響系統(tǒng)運(yùn)行速度。

???? 2)有些檢查過于嚴(yán)格,例如上面的字符串檢查,一旦出錯(cuò),則調(diào)用進(jìn)程就會(huì)abort。

??? ????所以,JNI check選項(xiàng)一般只在調(diào)試的eng版設(shè)置,而正式發(fā)布的user版則不設(shè)置該選項(xiàng)。

??? 下面這幾句代碼就控制著是否啟用JNI check,這是由系統(tǒng)屬性決定的,eng版如經(jīng)過特殊配置,也可以去掉JNI check。

?? */

??? property_get("dalvik.vm.checkjni",propBuf, "");

??? if(strcmp(propBuf, "true") == 0) {

???????checkJni = true;

??? } elseif (strcmp(propBuf, "false") != 0) {

???? ??property_get("ro.kernel.android.checkjni",propBuf, "");

??????? if(propBuf[0] == '1') {

???????????checkJni = true;

??????? }

?? ?????}

??? ......

?? /*

設(shè)置虛擬機(jī)heapsize,默認(rèn)為16MB。絕大多數(shù)廠商都會(huì)修改這個(gè)值,一般是32MB。

heapsize不能設(shè)置過小,否則在操作大尺寸的圖片時(shí)無法分配所需內(nèi)存。

??? ?這里有一個(gè)問題,即heapsize既然是系統(tǒng)級的屬性,那么能否根據(jù)不同應(yīng)用程序的需求來進(jìn)行動(dòng)

??????? ?態(tài)調(diào)整?我開始也考慮過能否實(shí)現(xiàn)這一構(gòu)想,不過希望很快就破滅了。對這一問題,我們將在拓展

??????? ?部分深入討論。

??? */

???strcpy(heapsizeOptsBuf, "-Xmx");

???property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");

???opt.optionString = heapsizeOptsBuf;

???mOptions.add(opt);

?

? ??if(checkJni) {

??????? opt.optionString ="-Xcheck:jni";

???????mOptions.add(opt);

??????? //JNIcheck中的資源檢查,系統(tǒng)中創(chuàng)建的Globalreference個(gè)數(shù)不能超過2000

???????opt.optionString = "-Xjnigreflimit:2000";

???????mOptions.add(opt);

?? }

? ??// 調(diào)用JNI_CreateJavaVM創(chuàng)建虛擬機(jī),pEnv返回當(dāng)前線程的JNIEnv變量

?? if(JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {

???????LOGE("JNI_CreateJavaVM failed\n");

???????goto bail;

??? }

?

??? result= 0;

?

bail:

???free(stackTraceFile);

??? returnresult;

}

關(guān)于dalvik虛擬機(jī)的詳細(xì)參數(shù),讀者可以參見Dalvik/Docs/Dexopt.html中的說明。這個(gè)Docs目錄下的內(nèi)容,或許可幫助我們更深入地了解dalvik虛擬機(jī)。

?

2. 注冊JNI函數(shù)——startReg

前面已經(jīng)介紹了如何創(chuàng)建虛擬機(jī),下一步則需要給這個(gè)虛擬機(jī)注冊一些JNI函數(shù)。正是因?yàn)楹罄m(xù)Java世界用到的一些函數(shù)是采用native方式來實(shí)現(xiàn)的,所以才必須提前注冊這些函數(shù)。

下面我們來看看這個(gè)startReg函數(shù),代碼如下所示:

[-->AndroidRuntime.cpp]

int AndroidRuntime::startReg(JNIEnv* env)

{

?//注意,設(shè)置Thread類的線程創(chuàng)建函數(shù)為javaCreateThreadEtc

?//它的作用,將在對Thread分析一部分(第5章)中做詳細(xì)介紹。

?androidSetCreateThreadFunc((android_create_thread_fn)javaCreateThreadEtc);

?

? env->PushLocalFrame(200);

? //注冊jni函數(shù),gRegJNI是一個(gè)全局?jǐn)?shù)組。

? if(register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0) {

???????env->PopLocalFrame(NULL);

???????return -1;

??? }

???env->PopLocalFrame(NULL);

??? //下面這句話應(yīng)當(dāng)是“碼農(nóng)”休閑時(shí)的小把戲。在日新月異的IT世界中,它現(xiàn)已絕對是“文物”了。

???//createJavaThread("fubar", quickTest, (void*)"hello");

??? return0;

}

我們來看看register_jni_procs,代碼如下所示:

[-->AndroidRuntime.cpp]

static int register_jni_procs(const RegJNIRecarray[], size_t count, JNIEnv* env)

{

??? for(size_t i = 0; i < count; i++) {

??????? if(array[i].mProc(env) < 0) {//僅僅是一個(gè)封裝,調(diào)用數(shù)組元素的mProc函數(shù)

???????return -1;

??????? }

??? ????}

?? ?????return 0;

}

上面的函數(shù)調(diào)用的不過是數(shù)組元素的mProc函數(shù),再讓我們直接看看這個(gè)全局?jǐn)?shù)組的gRegJNI變量。

[-->AndroidRuntime.cpp::gRegJNI聲明]

static const RegJNIRec gRegJNI[] = {

???REG_JNI(register_android_debug_JNITest),

???REG_JNI(register_com_android_internal_os_RuntimeInit),

???REG_JNI(register_android_os_SystemClock),

???REG_JNI(register_android_util_EventLog),

???REG_JNI(register_android_util_Log),

???? ...//共有100項(xiàng)

};

REG_JNI是一個(gè)宏,宏里邊包括的就是那個(gè)mProc函數(shù),這里,我們來分析一個(gè)例子。

[-->android_debug_JNITest.cpp]

int register_android_debug_JNITest(JNIEnv* env)

{

?? //為android.debug.JNITest類注冊它所需要的JNI函數(shù)

?? returnjniRegisterNativeMethods(env, "android/debug/JNITest",

??????? ??????????????????????????????????gMethods,NELEM(gMethods));

}

哦,原來mProc就是為Java類注冊JNI函數(shù)!

至此,虛擬機(jī)已創(chuàng)建好,JNI函數(shù)也已注冊,下一步就要分析CallStaticVoidMethod了。通過這個(gè)函數(shù),我們將進(jìn)入Android所精心打造的Java世界,而且最佳情況是,永遠(yuǎn)也不回到Native世界。

4.2.2 ?Welcome to Java World

這個(gè)Java世界的入口在哪里?根據(jù)前面的分析,CallStaticVoidMethod最終將調(diào)用com.android.internal.os.ZygoteInit的main函數(shù),下面就來看看這個(gè)入口函數(shù)。代碼如下所示:

[-->ZygoteInit.java]

public static void main(String argv[]) {

? try {

????? ??

????? ?SamplingProfilerIntegration.start();

?????? //①注冊Zygote用的socket

?????? registerZygoteSocket();

?????? //②預(yù)加載類和資源

?????? preloadClasses();

?????? preloadResources();

?????? ......

?????? // 強(qiáng)制一次垃圾收集

?? ????gc();

????? ?

???? ?//我們傳入的參數(shù)滿足if分支

? ????if (argv[1].equals("true")) {

??????????startSystemServer();//③啟動(dòng)system_server進(jìn)程

?????? }else if (!argv[1].equals("false")) {

????????? thrownew RuntimeException(argv[0] + USAGE_STRING);

??????? }

????? // ZYGOTE_FORK_MODE被定義為false,所以滿足else的條件

?????? if(ZYGOTE_FORK_MODE) {

????????????runForkMode();

?????? }else {

??????????runSelectLoopMode();//④zygote調(diào)用這個(gè)函數(shù)

?????? }

?????? closeServerSocket();//關(guān)閉socket

??????? }catch (MethodAndArgsCaller caller) {

? ?????????caller.run();//⑤很重要的caller run函數(shù),以后分析

??????? }catch (RuntimeException ex) {

??????????closeServerSocket();

???????????throw ex;

??????? }

?????......

??? }

在ZygoteInit的main函數(shù)中,我們列舉出了5大關(guān)鍵點(diǎn),下面對其一一進(jìn)行分析。先看第一點(diǎn):registerZygoteSocket。

1. 建立IPC通信服務(wù)端——registerZygoteSocket

Zygote以及系統(tǒng)中其他程序的通信沒有使用Binder,而是采用了基于AF_UNIX類型的Socket。registerZygoteSocket函數(shù)的使命正是建立這個(gè)Socket。代碼如下所示:

[-->ZygoteInit.java]

private static void registerZygoteSocket() {

??? if(sServerSocket == null) {

??????? intfileDesc;

??????? try{

?????????? //從環(huán)境變量中獲取Socket的fd,還記得第3章init中介紹的zygote是如何啟動(dòng)的嗎?

//這個(gè)環(huán)境變量由execv傳入。

??????????String env = System.getenv(ANDROID_SOCKET_ENV);

??????????fileDesc = Integer.parseInt(env);

?????? }

?????? try{

???????? //創(chuàng)建服務(wù)端Socket,這個(gè)Socket將listen并accept Client

???????? sServerSocket= new LocalServerSocket(createFileDescriptor(fileDesc));

?????? }

??? ???}

}

registerZygoteSocket很簡單,就是創(chuàng)建一個(gè)服務(wù)端的Socket。不過讀者應(yīng)該提前想到下面兩個(gè)問題:

·? 誰是客戶端?

·? 服務(wù)端會(huì)怎么處理客戶端的消息?

建議:讀者要好好學(xué)習(xí)與Socket相關(guān)的知識,這些知識對網(wǎng)絡(luò)編程或簡單的IPC使用,是會(huì)有幫助的。

2. 預(yù)加載類和資源

現(xiàn)在我們要分析的就是preloadClasses和preloadResources函數(shù)了。先來看看preloadClasses。

[-->ZygoteInit.java]

private static void preloadClasses() {

???? finalVMRuntime runtime = VMRuntime.getRuntime();

???? //預(yù)加載類的信息存儲在PRELOADED_CLASSES變量中,它的值為"preloaded-classes"

????InputStream is = ZygoteInit.class.getClassLoader().getResourceAsStream(

???????????????????????????PRELOADED_CLASSES);

??????? if(is == null) {

???????????Log.e(TAG, "Couldn't find " + PRELOADED_CLASSES +".");

??????? }else {

??????????????...... //做一些統(tǒng)計(jì)和準(zhǔn)備工作

?

???????? ???try {

???????????????BufferedReader br

??????????????????? = new BufferedReader(newInputStreamReader(is), 256);

???????????????//讀取文件的每一行,忽略#開頭的注釋行

???????????????int count = 0;

???????????????String line;

???????????????String missingClasses = null;

???????????????while ((line = br.readLine()) != null) {

????????????????????? line = line.trim();

??????????????????? if(line.startsWith("#") || line.equals("")) {

??????????????????????? continue;

??????????????????? }

?

??????????????????? try {

?? ?????????????????????//通過Java反射來加載類,line中存儲的是預(yù)加載的類名

?????????????????????? ?Class.forName(line);

?????????????????????? ......

??????????????????????? count++;

??????????????????? } catch(ClassNotFoundException e) {

?????????????????????? ......

???????????????????} catch (Throwable t) {

??????????????????????? ......

??????????????????? }

???????????????????}

? ?????????????...... //掃尾工作

??????? }

??? ????}

preloadClasses看起來是如此簡單,但是你知道它有多少個(gè)類需要預(yù)先加載嗎?

用coolfind在framework中搜索名為“preloaded-classes”的文件,最后會(huì)在framework/base目錄下找到。它是一個(gè)文本文件,內(nèi)容如下:

# Classes which are preloaded bycom.android.internal.os.ZygoteInit.

# Automatically generated by

# frameworks/base/tools/preload/WritePreloadedClassFile.java.

# MIN_LOAD_TIME_MICROS=1250? //超時(shí)控制

android.R$styleable

android.accounts.AccountManager

android.accounts.AccountManager$4

android.accounts.AccountManager$6

android.accounts.AccountManager$AmsTask

android.accounts.AccountManager$BaseFutureTask

android.accounts.AccountManager$Future2Task

android.accounts.AuthenticatorDescription

android.accounts.IAccountAuthenticatorResponse$Stub

android.accounts.IAccountManager$Stub

android.accounts.IAccountManagerResponse$Stub

......//一共有1268行

這個(gè)preload-class一共有1268行,試想,加載這么多類得花多少時(shí)間!

說明:preload_class文件由framework/base/tools/preload工具生成,它需要判斷每個(gè)類加載的時(shí)間是否大于1250微秒,超過這個(gè)時(shí)間的類就會(huì)被寫到preload-classes文件中,最后由zygote預(yù)加載。這方面的內(nèi)容,讀者可參考有關(guān)preload工具中的說明,這里就不再贅述。

preloadClass函數(shù)的執(zhí)行時(shí)間比較長,這是導(dǎo)致Android系統(tǒng)啟動(dòng)慢的原因之一。對這一塊可以做一些優(yōu)化,但優(yōu)化是基于對整個(gè)系統(tǒng)有比較深入了解才能實(shí)現(xiàn)的。

注意:在拓展思考部分中,我們會(huì)討論Android啟動(dòng)速度問題。

preloadResources和preloadClass類似,它主要是加載framework-res.apk中的資源。這里就不再介紹它了。

說明:在UI編程中常使用的com.android.R.XXX資源,是系統(tǒng)默認(rèn)的資源,它們就是由Zygote加載的。

3. 啟動(dòng)system_server

我們現(xiàn)在要分析的是第三個(gè)關(guān)鍵點(diǎn):startSystemServer。這個(gè)函數(shù)會(huì)創(chuàng)建Java世界中系統(tǒng)Service所駐留的進(jìn)程system_server,該進(jìn)程是framework的核心。如果它死了,就會(huì)導(dǎo)致zygote自殺。先來看看這個(gè)核心進(jìn)程是如何啟動(dòng)的。

[-->ZygoteInit.java]

private static boolean startSystemServer()

???????????throws MethodAndArgsCaller, RuntimeException {

??????? //設(shè)置參數(shù)

???????String args[] = {

?? ?????????"--setuid=1000",//uid和gid等設(shè)置

???????????"--setgid=1000",

??????? ????"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,

??????????????????????????? 3001,3002,3003",

???????????"--capabilities=130104352,130104352",

???????????"--runtime-init",

???????????"--nice-name=system_server",?//進(jìn)程名,叫system_server

???????????"com.android.server.SystemServer", //啟動(dòng)的類名

??????? };

???????ZygoteConnection.Arguments parsedArgs = null;

???????int pid;

???????try {

????????? //把上面字符串?dāng)?shù)組參數(shù)轉(zhuǎn)換成Arguments對象。具體內(nèi)容請讀者自行分析。

???????????parsedArgs = new ZygoteConnection.Arguments(args);

???????????int debugFlags = parsedArgs.debugFlags;

??????????//fork一個(gè)子進(jìn)程,看來,這個(gè)子進(jìn)程就是system_server進(jìn)程。

???????????pid = Zygote.forkSystemServer(

??????????????????? parsedArgs.uid,parsedArgs.gid,

??????????????????? parsedArgs.gids,debugFlags, null);

??????? }catch (IllegalArgumentException ex) {

???????????throw new RuntimeException(ex);

??????? }

???? /*

???? ?關(guān)于fork的知識,請讀者務(wù)花些時(shí)間去研究。如果對fork具體實(shí)現(xiàn)還感興趣,可參考

???? 《Linux內(nèi)核源代碼情景分析》一書。(該書由浙江大學(xué)出版社出版,作者為毛德操、胡希明)

????? 下面代碼中,如果pid為零,則表示處于子進(jìn)程中,也就是處于system_server進(jìn)程中。

???? */

??????? if(pid == 0) {

?????????//① system_server進(jìn)程的工作

???????????handleSystemServerProcess(parsedArgs);

??????? }

???????//zygote返回true

???????return true;

??? }

OK,這里出現(xiàn)了一個(gè)分水嶺,即Zygote進(jìn)行了一次無性繁殖,分裂出了一個(gè)system_server進(jìn)程。關(guān)于它的故事,我們會(huì)在后文做專門分析,這里先說Zygote。

4. 有求必應(yīng)之等待請求——runSelectLoopMode

當(dāng)Zygote從startSystemServer返回后,將進(jìn)入第四個(gè)關(guān)鍵函數(shù):runSelectLoopMode。前面,在第一個(gè)關(guān)鍵點(diǎn)registerZygoteSocket中注冊了一個(gè)用于IPC的Socket,不過那時(shí)還沒有地方用到它。它的用途將在這個(gè)runSelectLoopMode中體現(xiàn)出來,請看下面的代碼:

[-->ZygoteInit.java]

private static void runSelectLoopMode()

throws MethodAndArgsCaller {

???????ArrayList<FileDescriptor> fds = new ArrayList();

???????ArrayList<ZygoteConnection> peers = new ArrayList();

???????FileDescriptor[] fdArray = new FileDescriptor[4];

??????//sServerSocket是我們先前在registerZygoteSocket建立的Socket

???????fds.add(sServerSocket.getFileDescriptor());

???????peers.add(null);

?

???????int loopCount = GC_LOOP_COUNT;

???????while (true) {

???????????int index;

?????????????try {

???????????????fdArray = fds.toArray(fdArray);

??????? /*

??????????selectReadable內(nèi)部調(diào)用select,使用多路復(fù)用I/O模型。

??????????當(dāng)有客戶端連接或有數(shù)據(jù)時(shí),則selectReadable就會(huì)返回。

????????*/

??????????????index = selectReadable(fdArray);

???????????}

??? ??????else if (index == 0) {

???????????? //如有一個(gè)客戶端連接上,請注意客戶端在Zygote的代表是ZygoteConnection

???????????????ZygoteConnection newPeer = acceptCommandPeer();

???????????????peers.add(newPeer);

???????????????fds.add(newPeer.getFileDesciptor());

???????????} else {

???????????????boolean done;

??????????????//客戶端發(fā)送了請求,peers.get返回的是ZygoteConnection

?????????????//后續(xù)處理將交給ZygoteConnection的runOnce函數(shù)完成。

???????????????done = peers.get(index).runOnce();

??????? }

??? }

runSelectLoopMode比較簡單,就是:

·? 處理客戶連接和客戶請求。其中客戶在Zygote中用ZygoteConnection對象來表示。

·? 客戶的請求由ZygoteConnection的runOnce來處理。

建議:runSelectLoopMode比較簡單,但它使用的select的背后所代表的思想?yún)s并非簡單。建議讀者以此為契機(jī),認(rèn)真學(xué)習(xí)常用的I/O模型,包括阻塞式、非阻塞式、多路復(fù)用、異步I/O等,掌握這些知識,對于未來編寫大型系統(tǒng)很有幫助。

關(guān)于Zygote是如何處理請求的,將單獨(dú)用一節(jié)內(nèi)容進(jìn)行討論。

4.2.3 關(guān)于 Zygote的總結(jié)

Zygote是創(chuàng)建Android系統(tǒng)中Java世界的盤古,它創(chuàng)建了第一個(gè)Java虛擬機(jī),同時(shí)它又是女媧,它成功地繁殖了framework的核心system_server進(jìn)程。做為Java語言的受益者,我們理應(yīng)回顧一下Zygote創(chuàng)建Java世界的步驟:

·? 第一天:創(chuàng)建AppRuntime對象,并調(diào)用它的start。此后的活動(dòng)則由AppRuntime來控制。

·? 第二天:調(diào)用startVm創(chuàng)建Java虛擬機(jī),然后調(diào)用startReg來注冊JNI函數(shù)。

·? 第三天:通過JNI調(diào)用com.android.internal.os.ZygoteInit類的main函數(shù),從此進(jìn)入了Java世界。然而在這個(gè)世界剛開創(chuàng)的時(shí)候,什么東西都沒有。

·? 第四天:調(diào)用registerZygoteSocket。通過這個(gè)函數(shù),它可以響應(yīng)子孫后代的請求。同時(shí)Zygote調(diào)用preloadClasses和preloadResources,為Java世界添磚加瓦。

·? 第五天:Zygote覺得自己工作壓力太大,便通過調(diào)用startSystemServer分裂一個(gè)子進(jìn)程system_server來為Java世界服務(wù)。

·? 第六天:Zygote完成了Java世界的初創(chuàng)工作,它已經(jīng)很滿足了。下一步該做的就是調(diào)用runSelectLoopMode后,便沉沉地睡去了。

·? 以后的日子:Zygote隨時(shí)守護(hù)在我們的周圍,當(dāng)接收到子孫后代的請求時(shí),它會(huì)隨時(shí)醒來,為它們工作。

如果支持中文編碼的話,我一定要為Zygote取名為盤古_女媧。

4.3 ?SystemServer分析

SystemServer的進(jìn)程名實(shí)際上叫做“system_server”,這里我們可將其簡稱為SS。SS做為Zygote的嫡長子,其重要性不言而喻。關(guān)于這一點(diǎn),通過代碼分析便可馬上知曉。

4.3.1 ?SystemServer的誕生

我們先回顧一下SS是怎么創(chuàng)建的。

String args[] = {

???????????"--setuid=1000",

???????????"--setgid=1000",

???????????"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,

???????????????????????????? 3001,3002,3003",

???????????"--capabilities=130104352,130104352",

???????????"--runtime-init",

???????????"--nice-name=system_server",

???????????"com.android.server.SystemServer",

??????? };

???????ZygoteConnection.Arguments parsedArgs = null;

?

???????int pid;

??????parsedArgs = new ZygoteConnection.Arguments(args);

?????? intdebugFlags = parsedArgs.debugFlags;

? ?????pid = Zygote.forkSystemServer(? //調(diào)用forkSystemServer

??????????????????? parsedArgs.uid,parsedArgs.gid,

??????????????????? parsedArgs.gids,debugFlags, null);

?

從上面的代碼中可以看出,SS是由Zygote通過Zygote.forkSystemServer函數(shù)fork誕生出來的。這里會(huì)有什么玄機(jī)嗎?先來一起看看forkSystemServer的實(shí)現(xiàn)。它是一個(gè)native函數(shù),實(shí)現(xiàn)在dalvik_system_Zygote.c中,如下所示:

[-->dalvik_system_Zygote.c]

static voidDalvik_dalvik_system_Zygote_forkSystemServer(

?????? ?????????????????const u4* args, JValue* pResult)

{

???? pid_tpid;

??? //根據(jù)參數(shù),fork一個(gè)子進(jìn)程

??? pid =forkAndSpecializeCommon(args);

? ??if (pid > 0) {

???????int status;

???????gDvm.systemServerPid = pid;//保存system_server的進(jìn)程id

????? //函數(shù)退出前須先檢查剛創(chuàng)建的子進(jìn)程是否退出了。

??????? if(waitpid(pid, &status, WNOHANG) == pid) {

???????????//如果system_server退出了,Zygote直接干掉了自己

???????????//看來Zygote和SS的關(guān)系異常緊密,簡直是生死與共!

? ??????????kill(getpid(), SIGKILL);

??????? }

??? }

???RETURN_INT(pid);

}

下面,再看看forkAndSpecializeCommon,代碼如下所示:

[-->dalvik_system_Zygote.c]

static pid_t forkAndSpecializeCommon(const u4*args)

{

??? pid_tpid;

??? uid_tuid = (uid_t) args[0];

??? gid_tgid = (gid_t) args[1];

???ArrayObject* gids = (ArrayObject *)args[2];

??? u4debugFlags = args[3];

???ArrayObject *rlimits = (ArrayObject *)args[4];

?? //設(shè)置信號處理,待會(huì)兒要看看這個(gè)函數(shù)。??

???setSignalHandler();?????

??? pid =fork(); //fork子進(jìn)程

?? if (pid== 0) {

? ???//對子進(jìn)程要根據(jù)傳入的參數(shù)做一些處理,例如設(shè)置進(jìn)程名,設(shè)置各種id(用戶id,組id等)

?? }

......

}

最后看看setSignalHandler函數(shù),它由Zygote在fork子進(jìn)程前調(diào)用,代碼如下所示:

[-->dalvik_system_Zygote.c]

static void setSignalHandler()

{

??? interr;

??? structsigaction sa;

???memset(&sa, 0, sizeof(sa));

???sa.sa_handler = sigchldHandler;

??? err =sigaction (SIGCHLD, &sa, NULL);//設(shè)置信號處理函數(shù),該信號是子進(jìn)程死亡的信號

}

//我們直接看這個(gè)信號處理函數(shù)sigchldHandler

static void sigchldHandler(int s)

{

??? pid_tpid;

??? intstatus;

????

??? while((pid = waitpid(-1, &status, WNOHANG)) > 0) {

????? ???????} else if (WIFSIGNALED(status)) {

??????????}

??????? }

??????? //如果死去的子進(jìn)程是SS,則Zygote把自己也干掉了,這樣就做到了生死與共!

??????? if(pid == gDvm.systemServerPid) {

???????????kill(getpid(), SIGKILL);

??????? }

?? }

OK,做為Zygote的嫡長子,SS確實(shí)具有非常高的地位,竟然到了與Zygote生死與共的地步!它為什么這么重要呢?我們現(xiàn)在就從forkSystemServer來分析SS究竟承擔(dān)了怎樣的工作使命。

關(guān)于源代碼定位的問題,不少人當(dāng)面對浩瀚的代碼時(shí),常常不知道具體函數(shù)是在哪個(gè)文件中定義的。這里,就Source insight的使用提幾點(diǎn)建議:

?? 1)加入工程的時(shí)候,不要把所有目錄全部加進(jìn)去,否則會(huì)導(dǎo)致解析速度異常緩慢。我們可以先加入framework目錄,如以后另有需要時(shí),再加入其他目錄。

2)除了Sourceinsight的工具外,還需要有一個(gè)能搜索文件中特定字符串的工具,我用的是coolfind。forkSystemServer這個(gè)函數(shù),就是通過它在源碼中搜索到的,并且找到了實(shí)現(xiàn)文件dalvik_system_Zygote.c。在Linux下也有對應(yīng)工具,但工作速度比coolfind緩慢。

3) 在Linux下,可通過wine(一個(gè)支持Linux平臺安裝Windows軟件的工具)安裝Source insight。

4.3.2 ?SystemServer的重要使命

SS誕生后,便和生父Zygote分道揚(yáng)鑣,它有了自己的歷史使命。它的使命是什么呢?其代碼如下所示:

??? pid =Zygote.forkSystemServer();

???? if(pid == 0) { //SS進(jìn)程返回0,那么下面這句話就是SS的使命:

???????????handleSystemServerProcess(parsedArgs);

??? }

SS調(diào)用handleSystemServerProcess來承擔(dān)自己的職責(zé)。

[-->ZygoteInit.java]

private static void handleSystemServerProcess(

?????? ZygoteConnection.ArgumentsparsedArgs)

??????throws ZygoteInit.MethodAndArgsCaller {

?????? ?//關(guān)閉從Zygote那里繼承下來的Socket。?

??????? closeServerSocket();

????? //設(shè)置SS進(jìn)程的一些參數(shù)。

??????? setCapabilities(parsedArgs.permittedCapabilities,

?????????????????? parsedArgs.effectiveCapabilities);

??????? //調(diào)用ZygoteInit函數(shù)。

????????RuntimeInit.zygoteInit(parsedArgs.remainingArgs);

? }

?好了,SS走到RuntimeInit了,它的代碼在RuntimeInit.java中,如下所示:???

[-->RuntimeInit.java]

public static final void zygoteInit(String[]argv)

???????????throws ZygoteInit.MethodAndArgsCaller {

???? //做一些常規(guī)初始化

???? commonInit();

???? //①native層的初始化。

????zygoteInitNative();

???? intcurArg = 0;

???? for (/* curArg */ ; curArg < argv.length; curArg++) {

???? ??????String arg = argv[curArg];

?

???????????if (arg.equals("--")) {

???????????????curArg++;

???????????????break;

???????????} else if (!arg.startsWith("--")) {

???????????????break;

???????????} else if (arg.startsWith("--nice-name=")) {

???????????????String niceName = arg.substring(arg.indexOf('=') + 1);

??? ???????????//設(shè)置進(jìn)程名為niceName,也就是"system_server"

???????????????Process.setArgV0(niceName);

???????????}

??????? }

???????//startClass名為"com.android.server.SystemServer"

???????String startClass = argv[curArg++];

???????String[] startArgs = new String[argv.length - curArg];

???????System.arraycopy(argv, curArg, startArgs, 0, startArgs.length);

?????? //②調(diào)用startClass,也就是com.android.server.SystemServer類的main函數(shù)。

???????invokeStaticMain(startClass, startArgs);

}

對于上面列舉出的兩個(gè)關(guān)鍵點(diǎn),我們一個(gè)一個(gè)地分析。

1. zygoteInitNative分析

先看zygoteInitNative,它是一個(gè)native函數(shù),實(shí)現(xiàn)在AndroidRuntime.cpp中。

[-->AndroidRuntime.cpp]

static voidcom_android_internal_os_RuntimeInit_zygoteInit(

JNIEnv* env,jobject clazz)

{

???gCurRuntime->onZygoteInit();

}

//gCurRuntime是什么?還記得我們在本章開始說的app_process的main函數(shù)嗎?

int main(int argc, const char* const argv[])

{

??AppRuntime runtime;// 就是這個(gè)。當(dāng)時(shí)我們沒顧及它的構(gòu)造函數(shù),現(xiàn)在回過頭看看。

}

//AppRuntime的定義

class AppRuntime : public AndroidRuntime

static AndroidRuntime* gCurRuntime = NULL; // gCurRuntime為全局變量。

AndroidRuntime::AndroidRuntime()

{

???SkGraphics::Init();//Skia庫初始化

???SkImageDecoder::SetDeviceConfig(SkBitmap::kRGB_565_Config);

???SkImageRef_GlobalPool::SetRAMBudget(512 * 1024);

??? gCurRuntime= this; //gCurRuntime被設(shè)置為AndroidRuntime對象自己

}

由于SS是從Zygote fork出來的,所以它也擁有Zygote進(jìn)程中定義的這個(gè)gCurRuntime,也就是AppRuntime對象。那么,它的onZygoteInit會(huì)干些什么呢?它的代碼在App_main.cpp中,我們一起來看:

[-->App_main.cpp]

???virtual void onZygoteInit()

??? {

??????? //下面這些東西和Binder有關(guān)系,但讀者可以先不管它。

???????sp<ProcessState> proc = ProcessState::self();

??????? if(proc->supportsProcesses()) {

????????????proc->startThreadPool();//啟動(dòng)一個(gè)線程,用于Binder通信。

???????}??????

}

一言以蔽之,SS調(diào)用zygoteInitNative后,將和Binder通信系統(tǒng)建立聯(lián)系,這樣SS就能夠使用Binder了。關(guān)于Binder的知識,在第6章中將詳細(xì)介紹,讀者朋友現(xiàn)在不必關(guān)注。

2. invokeStaticMain分析

再來看第二個(gè)關(guān)鍵點(diǎn)invokeStaticMain。代碼如下所示:

[-->RuntimeInit.java]

private static void invokeStaticMain(StringclassName, String[] argv)

???????????throws ZygoteInit.MethodAndArgsCaller {

?

??????......//注意我們的參數(shù),className為"com.android.server.SystemServer"

???????Class<?&g