本章主要內(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
?
讀者可能已經(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è)重量級人物。
?
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。
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)在讓我們來具體地觀察它們。
我們先看三部曲中的第一部: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ī)。
?
前面已經(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世界。
這個(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。
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ì)有幫助的。
現(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加載的。
我們現(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。
當(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)行討論。
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取名為盤古_女媧。
SystemServer的進(jìn)程名實(shí)際上叫做“system_server”,這里我們可將其簡稱為SS。SS做為Zygote的嫡長子,其重要性不言而喻。關(guān)于這一點(diǎn),通過代碼分析便可馬上知曉。
我們先回顧一下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。
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è)地分析。
先看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)注。
再來看第二個(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