Android == Zygote, System Server 啓動分析

      Init 是所有Linux程序的起點,而Zygote於Android,正如它的英文意思,是所有java程序的'孵化池'(玩過星際蟲族的兄弟都曉得的)。用ps 輸出可以看到

>adb shell ps | grep -E 'init|926'
 root      1     0     656    372   00000000 0805d546 S /init
 root      926   1     685724 43832 ffffffff b76801e0 S zygote
 system    1018  926   795924 62720 ffffffff b767fff6 S system_server
 u0_a6     1241  926   717704 39252 ffffffff b76819eb S com.android.systemui
 u0_a37    1325  926   698280 29024 ffffffff b76819eb S com.android.inputmethod.latin
 radio     1349  926   711284 30116 ffffffff b76819eb S com.android.phone
 u0_a7     1357  926   720792 41444 ffffffff b76819eb S com.android.launcher
 u0_a5     1523  926   703576 26416 ffffffff b76819eb S com.android.providers.calendar
 u0_a25    1672  926   693716 21328 ffffffff b76819eb S com.android.musicfx
 u0_a17    2040  926   716888 33992 ffffffff b76819eb S android.process.acore
 u0_a21    2436  926   716060 23904 ffffffff b76819eb S com.android.calendar

init 是 zygote的父進程, 而system_server和其他所有的com.xxx結尾的應用程序都是從zygote fork 而來。本文將圖過圖表(輔予少量的代碼)的方式來描述Zygote,system server 以及android application的啓動過程。

廢話少說,奉上兩張大圖開啓我們的Zygote之旅。 第一張圖是Zygote相關的所有類的結構圖,另一張是Zygote啓動的流程圖。

 

Zyogote 類結構圖

 

 

 

 

 按圖索驥,我們按照圖一中的序號一一分解Zygote的啓動過程。

1. App_Process 

  • APP_Process: 啓動zygote和其他Java程序的應用程序, 代碼位於frameworks/base/cmds/app_process/app_main.cpp, 在init.rc 裏面指定。
#init.rc
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server

代碼如下

...
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 裏面定義了三種應用程序類型:

       1.  Zygote:  com.android.internal.os.ZygoteInit

       2.  System Server, 不單獨啓動,而是由Zygote啓動

       3.  其他指定類名的Java 程序,比如說常用的 am. /system/bin/am 其實是一個shell程序,它的真正實現是       

exec app_process $base/bin com.android.commands.am.Am "$@"

這些Java的應用都是通過 AppRuntime.start(className)開始的。從第一張大圖可以看出,其實AppRuntime是AndroidRuntime的子類,它主要實現了幾個回調函數,而start()方法是實現在AndroidRuntime這個方法類裏。什麼是AnroidRuntime? 我們接下來馬上開始。

需要注意的是Zygote並不是Init啓動的第一個程序,從PID可以看出來,在它之前,一下Native實現的重要System Daemon (後臺進程)可能先起來,比如 ServiceManager (service的DNS服務).

 

2. AndroidRuntime

     首先,什麼是Runtime ?看看Wiki給的幾種解釋:      

 

     我傾向這裏指的是後者,看看更進一步的解釋:

     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 是支撐程序運行的基礎庫,它是與語言綁定在一起的。比如:

  • C Runtime:就是C standard lib, 也就是我們常說的libc。(有意思的是, Wiki會自動將“C runtime" 重定向到 "C Standard Library").
  • Java Runtime: 同樣,Wiki將其重定向到” Java Virtual Machine", 這裏當然包括Java 的支撐類庫(.jar).
  • AndroidRuntime:  顯而易見,就是爲Android應用運行所需的運行時環境。這個環境包括以下東東:
    • Dalvik VM: Android的Java VM, 解釋運行Dex格式Java程序。每個進程運行一個虛擬機(什麼叫運行虛擬機?說白了,就是一些C代碼,不停的去解釋Dex格式的二進制碼(Bytecode),把它們轉成機器碼(Machine code),然後執行,當然,現在大多數的Java 虛擬機都支持JIT,也就是說,bytecode可能在運行前就已經被轉換成機器碼,從而大大提高了性能。過去一個普遍的認識是Java 程序比C,C++等靜態編譯的語言慢,但隨着JIT的介入和發展,這個已經完全是過去時了,JIT的動態性運行允許虛擬機根據運行時環境,優化機器碼的生成,在某些情況下,Java甚至可以比C/C++跑得更快,同時又兼具平臺無關的特性,這也是爲什麼Java如今如此流行的原因之一吧)。
    • Android的Java 類庫, 大部分來自於 Apache Hamony, 開源的Java API 實現,如 java.lang, java.util, java.net. 但去除了AWT, Swing 等部件。
    • JNI: C和Java互調的接口。
    • Libc: Android也有很多C代碼,自然少不了libc,注意的是,Android的libc叫 bionic C.

       OK, 那就首先看看AndroidRuntime是怎麼搭建起來的吧     

 

      上圖給出了Zygote啓動的大概流程,入口是AndroidRuntime.start(), 根據傳入參數的不同可以有兩種啓動方式,一個是 "com.android.internal.os.RuntimeInit", 另一個是 ”com.android.internal.os.ZygoteInit", 對應RuntimeInit 和 ZygoteInit 兩個類, 圖中用綠色和粉紅色分別表示。這兩個類的主要區別在於Java端,可以明顯看出,ZygoteInit 相比 RuntimeInit 多做了很多事情,比如說 “preload", "gc" 等等。但是在Native端,他們都做了相同的事, startVM() 和 startReg(), 讓我們先從這裏開始吧。

      從類圖中看出,JavaVM 和 JNIEnv 是連結 AndroidRuntim 和 Dalvik VM 之間的唯一兩個關卡,它隱藏了Dalvik 裏面的實現細節,事實上,他就是兩個函數指針結構體,給本地代碼提供訪問Java資源的接口。JNIEnv則相對於線程,通過JNIEnv的指針最終可以對應到Dalvik VM 內部的Thread 結構體,所有的調用就在這個結構體上下文完成。而JavaVM 對應的是DVMGlobal, 一個進程唯一的結構體,他內部維護了一個線程隊列threadList,存放每個Thread 結構體對象, 同時還有各類狀態的對象列表,及存放GC的結構體,等等。本文無法深入,只作簡單介紹。

  •   JavaVM 和 JNIENV

    • struct _JavaVM {
          const struct JNIInvokeInterface* functions; //C的函數指針
      
      #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(), 它返回一個JNIEnv對象,對應於每個DVM線程。JNIEnv的定義很長,有興趣的同學可以到Jni.h 裏面找,這裏我們只看看這個對象是如何獲static jint GetEnv(JavaVM* vm, void** env, jint version) {

  •     Thread* self = dvmThreadSelf(); //獲取當前線程對象。
        if (version < JNI_VERSION_1_1 || version > JNI_VERSION_1_6) {
            return JNI_EVERSION; 
        } //檢查版本號,Android 4.3對應 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; }

    很簡單嘛,原來就是從當前所在線程的結構體對象裏讀取即可,這裏面好像沒JavaVM什麼事嗎,爲什麼當參數傳入?不知道,也許Google留作將來擴展?但不管怎麼,要想調用GetEnv,還是需要JavaVM。將來要寫JNI代碼的同學可以參考以下的代碼看如何獲取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代碼進行互調的,那在Java那端一定就是Java虛擬機以及對應的Java應用了。Java虛擬機到底是什麼東東,它是如何創建的?答案從AndroidRuntime::startVM() 函數開始。startVM

  • startVM()

  • int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv)
    {
        property_get("dalvik.vm.checkjni", propBuf, "");
        ...    
        initArgs.version = JNI_VERSION_1_4;
        ...
        //創建VM並返回JavaVM 和 JniEnv,pEnv對應於當前線程。
        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結構體*/
        JavaVMExt* pVM = (JavaVMExt*) calloc(1, sizeof(JavaVMExt));
        pVM->funcTable = &gInvokeInterface; //初始化函數指針
        pVM->envList = NULL; 
        ...
        gDvmJni.jniVm = (JavaVM*) pVM; //native代碼接觸的JavaVM原來只是JniVm而已
        JNIEnvExt* pEnv = (JNIEnvExt*) dvmCreateJNIEnv(NULL); //創建JNIEnv,因爲接下來的虛擬機初始化需要訪問C/C++實現
        /* 開始初始化. */
        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)
    {
        /*
         * 檢查輸入並準備初始化參數
         */
        int cc = processOptions(argc, argv, ignoreUnrecognized);
        ...
    
    
        /* 真正初始化開始,初始化各個內部模塊,並創建一系列線程*/     
        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虛擬機的啓動有太多的細節在這裏無法展開,這裏我們只需要知道它做了以下一些事情:

    1.  從property讀取一系列啓動參數。
    2.  創建和初始化結構體全局對象(每個進程)gDVM,及對應與JavaVM和JNIEnv的內部結構體 JavaVMExt, JNIEnvExt.
    3.  初始化java虛擬機,並創建虛擬機線程。"ps -t",你可以發現每個Android應用都有以下幾個線程


     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 調試
     u0_a46    1287  1281  714900 57896 20    0     0     0     fg  ffffffff 00000000 S Compiler           //JIT
     u0_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監護
     u0_a46    1290  1281  714900 57896 20    0     0     0     fg  ffffffff 00000000 S FinalizerWatchd    //

    4. 註冊系統的JNI,Java程序通過這些JNI接口來訪問底層的資源。

        loadJniLibrary("javacore");
        loadJniLibrary("nativehelper");

    5. 爲Zygote的啓動做最後的準備,包括設置SID/UID, 以及mount 文件系統。
    6. 返回JavaVM 給Native代碼,這樣它就可以向上訪問Java的接口。

    除了系統的JNI接口(”javacore", "nativehelper"), android framework 還有大量的Native實現,Android將所有這些接口一次性的通過start_reg()來完成,

  • startReg()


int AndroidRuntime::startReg(JNIEnv* env){
    androidSetCreateThreadFunc((android_create_thread_fn) javaCreateThreadEtc); //創建JVM能訪問的線程必須通過特定的接口。

    env->PushLocalFrame(200);

    if (register_jni_procs(gRegJNI, NELEM(gRegJNI), env) < 0)    {
        env->PopLocalFrame(NULL);
        return -1;
    }
    env->PopLocalFrame(NULL);
    return 0;
}

            Android native層有兩種Thread的創建方式:


#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);
    }
   ...
}

          它們的區別在是是否能夠調用Java端函數,普通的thread就是對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進行綁定,下面是具體的實現函數          


#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;

    /* 運行真正的'entryFunc' */
    result = (*(android_thread_func_t)start)(userData);


    /* unhook us */
    javaDetachThread();
    ...
    return result;
}

      attachVM() 到底做什麼事情? 篇幅有限無法展開,這裏只需要知道這麼幾點:

    • 一個進程裏有一個Java 虛擬機,Java 虛擬機內部有很多線程,如上面列到的 GC, FinalizeDaemon, 以及用戶創建的線程等等.
    • 每個Java線程都維護一個JNIEnvExt對象,裏面存放一個指向DVM 內部Thread對象的指針,也就是說,所有從native到Java端的調用,都會引用到這個對象。
    • 所有通過JVM創建的線程都會在VM內部記錄在案,但是當前,我們還沒有進入Java世界,本地創建的線程VM自然就不知道,因此我們需要通過attach來通知VM來創建相應的內部數據結構。

      看看下面代碼,你就知道,其實Attach()做的一件重要的事情就是 創建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;
    ...
}

    完了,就開始註冊本地的JNI接口函數了- register_jni_procs(), 這個函數其實就是對一個全局數組gRegJni[] 進行遍歷調用,這個數組展開可以得到以下的結果

      

static const RegJNIRec gRegJNI[] = {
   {register_android_debug_JNITest},
   {register_com_android_internal_os_RuntimeInit}.
    ...
}

    每個 register_xxx是一個函數指針

int jniRegisterNativeMethods(
      C_JNIEnv* env, 
      const char* className,
      const JNINativeMethod* gMethods, 
      int numMethods);

   RegisterNativeMethods 在VM內部到底發生了什麼? 同樣,這裏只需要知道以下幾點即可: 

   gRegJni[]

 

 好了,經過了千辛萬苦,Android的運行時環境都已經準備就緒了,讓我們再回顧一下AndroidRuntime的初始化都做了哪些工作,

  1. 創建了Dalvik VM.
  2. 獲取Native 訪問Java的兩個接口對象,JavaVM 和 JNIENV。
  3. 註冊了一批 (見gRegJni[]) native接口給VM。

這些操作都是相對耗時的工作,如果每個進程都做同樣的工作勢必會影響到啓動速度,這也是爲什麼我們需要通過Zygote來創建Android 應用,因爲通過Linux fork 的 copy_on_write的機制,子進程可以將這些初始化好的內存空間直接映射到自己的進程空間裏,不在需要做重複的工作,從而提高了應用啓動的速度。

可以是,Android系統只需要基本的運行時環境就夠了嗎? 答案顯然是No。AndriodRuntime 只是提供了語言層面的基礎支持,在一個多任務,多用戶的圖形操作系統上快速的孵化和運行應用程序,我們需要更多。這就是Zygote,這就是爲什麼在圖2中,ZygoteInit會比RuntimeInit做更多的事情。那接下來,讓我們真正進入Zygote的世界。

 

 

3. ZygoteInit

      當VM準備就緒,就可以運行Java代碼了,系統也將在此第一次進入Java世界,還記得app_main.cpp裏面調到的 Runtime.start()的參數嗎, 那就是我們要運行的Java類。Android支持兩個類做爲起點,一個是‘com.android.internal.os.ZygoteInit', 另一個是'com.android.internal.os.RuntimeInit'。

     此外Runtime_Init 類裏還定義了一個ZygoteInit() 靜態方法。它在Zygote 創建一個新的應用進程的時候被創建,它和RuntimeInit 類的main() 函數做了以下相同的事情:

  • redirectLogStreams(): 將System.out 和 System.err 輸出重定向到Android 的Log系統(定義在 android.util.Log).
  • commonInit(): 初始化了一下系統屬性,其中最重要的一點就是設置了一個未捕捉異常的handler,當代碼有任何未知異常,就會執行它,調試過Android代碼的同學經常看到的"*** 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() 分別調用裏nativeFinishInit() 和 nativeZygoteInit(), 由此開始分道揚鑣,RuntimeInit 的nativeFinishInit() 最終會調用到 app_main.cpp 裏的 onStarted() 函數,裏面調用Java類的main() 函數,然後結束進程退出。

  

     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() 則會調到 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();
     }
複製代碼

    它僅僅是啓動了一個ThreadPool, 剩下的工作則回到Java端由RuntimeInit::applicationInit()完成。

    所以,我們不妨這樣理解RuntimeInit::main(), RuntimeInit::ZygoteInit(), ZygoteInit::main()三者關係, RuntimeInit的main() 方法提供標準的Java程序運行方式,而RuntimeInit的ZygoteInit() 則是關門爲Android應用啓動的方法,它是在Zygote 創建一個新的應用進程的時候調用的,這部分代碼實現在ZygoteInit 類裏。除了上面描述的差別,ZygoteInit 類裏還多做了如下幾件事情,讓我們一一詳細解析。

  1.  registerZygoteSocket();
  2.  startSystemServer();
  3.  runSelectLoopMode();

 

     RegisterZygoteSocket()

       其實做的事情很簡單,就是初始化Server端(也就是Zygote)的socket。值得一提的是,這裏用到的socket類型是LocalSocket, 它是Android對Linux 的 Local Socket的一個封裝。Local Socket 是Linux提供的一種基於Socket的進程間通信方式,對Server端來講,唯一的區別就是bind到一個本地的文件描述符(fd)而不是某個IP地址和端口號。Android裏很多地方用到了Local Socket做進程間的通信,搜索一下init.rc, 你會看到很多這樣的語句:

複製代碼
    socket adbd stream 660 system system
    socket vold stream 0660 root mount
    socket netd stream 0660 root system
    socket dnsproxyd stream 0660 root inet
    socket mdns stream 0660 root system
    socket rild stream 660 root radio
    socket rild-debug stream 660 radio system
    socket zygote stream 660 root system
    socket installd stream 600 system system
    socket racoon stream 600 system system
    socket mtpd stream 600 system system
    socket dumpstate stream 0660 shell log
    socket mdnsd stream 0660 mdnsr inet
複製代碼

       當init 解析到這樣一條語句,它將做這麼幾件事:

            1. 調用 create_socket() (system/core/init/util.c), 創建一個Socket fd, 將這個fd 與某個文件(/dev/socket/xxx, xxx 就是上面列到的名字,比如,zygote) 綁定(bind), 根據init.rc 裏面定義來設定相關的用戶,組和權限。最後返回這個fd。
            2. 將socket 名字(帶‘ANDROID_SOCKET_'前綴)(比如 zygote) 和 fd 註冊到init 進程的環境變量裏,這樣所有的其他進程(所有進程都是init的子進程)都可以通過 getenv(name)獲取到這個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端創建完畢,接下來就可以相應客戶端連接請求了。我們前面講過,AndroidRuntime 一系列複雜的初始化工作可以通過fork來幫助子進程來簡化這個過程,對了,Zygote創建Socket server 端就是用來響應這個fork的請求。那發起請求的是誰?Zygote fork的子進程又是誰?答案是ActivityManagerService 和 Android Application. 這個過程是怎樣的? 答案就在Andriod System Server的啓動過程中。 

Preload

    preload() 做了兩件事情:  

    static void preload() {
        preloadClasses();
        preloadResources();
    }

    這是Android啓動過程中最耗時間的兩件事情。preloadClassess 將framework.jar裏的preloaded-classes 定義的所有class load到內存裏,preloaded-classes 編譯Android後可以在framework/base下找到。而preloadResources 將系統的Resource(不是在用戶apk裏定義的resource)load到內存。

    資源preload到Zygoted的進程地址空間,所有fork的子進程將共享這份空間而無需重新load, 這大大減少了應用程序的啓動時間,但反過來增加了系統的啓動時間。通過對preload 類和資源數目進行調整可以加快系統啓動。

GC  

複製代碼
  static void gc() {
        final VMRuntime runtime = VMRuntime.getRuntime();
        System.gc();
        runtime.runFinalizationSync();
        System.gc();
        runtime.runFinalizationSync();
        System.gc();
        runtime.runFinalizationSync();
    }
複製代碼

     爲什麼調了3次System.gc()和runFinalizationSync()? 這是因爲gc()調用只是通知VM進行垃圾回收,是否回收,什麼時候回收全又VM內部算法決定。GC的回收有一個複雜的狀態機控制,通過多次調用,可以使得儘可能多的資源得到回收。gc()必須在fork之前完成(接下來的StartSystemServer就會有fork操作),這樣將來被複製出來的子進程纔能有儘可能少的垃圾內存沒有釋放。

Start SystemServer

      想起init.rc 裏面啓動zygote的參數了嗎, "--start-system-server", System Server 是Zygote fork 的第一個Java 進程, 這個進程非常重要,因爲他們有很多的系統線程,提供所有核心的系統服務,我們可以用 'ps -t |grep <system server pid>'來看看都有哪些線程,排除前面列出的幾個Java 虛擬機線程,還有

複製代碼
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了嗎?對了,它們都是運行在system_server的進程裏。還有很多“Binder-x"的線程,它們是各個Service爲了響應應用程序遠程調用請求而創建的。除此之外,還有很多內部的線程,比如 ”UI thread", "InputReader", "InputDispatch" 等等,我們將在後續的文章裏將這些模塊具體分析。本文,我們只關心System Server是如何創建起來的。

 

4. System Server 啓動流程

這個過程代碼很多,涉及到很多類,我們用一張時序圖來描述這個過程。圖中不同的顏色代表運行在不同的線程中。

 

1.  ZygoteInit fork 出一個新的進程,這個進程就是SystemServer進程。

2.  fork出來的子進程在handleSystemServerProcess 裏開始初始化工作,初始化分兩步,一部在native 完成,另外一部分(大部分)在Java端完成。 native端的工作在AppRuntime(AndroidRuntime的子類)::onZygoteInit()完成,做的一件事情就是啓動了一個Thread, 這個Thread是SystemServer的主線程(最左邊的粉色方塊), 負責接收來至其他進程的Binder調用請求。代碼如下

複製代碼
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層的初始化,這個流程比較長,也比較複雜,我們分成很多步進行講解。初始化的入口是SystemServer的main() 函數,這裏又調用了Native的 Init1(). Init1實現在com_android_server_SystemServer.cpp,   最終調用到的函數是system_init(). system_init()的實現如下:

複製代碼
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(); //初始化 SurfaceFlinger
        android_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;
}
複製代碼

 

 幾點需要注意:

 A. SurfaceFlinger Service可以運行在System_Server 進程裏,也可以運行在獨立的進程裏,如果是後者的話,需要在init.rc 里加上一句 "setprop system_init.startsurfaceflinger=1" 並且確保 service surfaceflinger 沒有被 “disable”

 B. init2 實現在System_Server.java,我們後面會詳細介紹。

 

4. system_init() 最後,join_threadpool() 將當前線程掛起,等待binder的請求。這個thread的名字就是"Binder_1". 關於service 和 binder的內部機制,請參考文章http://www.cnblogs.com/samchen2009/p/3316001.html

 
5. init2: 至此,system server的native初始化工作完成,又重新回到了Java端,在這裏,很多非常重要的系統服務將被啓動。 這些工作將在一個新的線程內開始,線程名"android.server.ServerThread", 見下圖的綠色條塊。在ServerThread裏,SystemServer 首先創建了兩個線程,UI thread 和 WindowManager thread, 見圖中的橙色和桃色條塊,這兩個thread的handle將被傳給某些Service的構造函數,部分的啓動工作會分發到這兩個Thread內進行。

    每個Thread都最終進入等待循環,這裏用到了Android的Looper機制,Looper,Handler是Android的進程內的消息傳遞和處理機制,我們將會在文章 http://www.cnblogs.com/samchen2009/p/3316004.html 裏詳細介紹,這裏,我們只需要知道,Looper在某個線程裏睡眠等待消息隊列裏的消息,然後在某個特定的Handler裏來處理這個消息。換句話說,指定某件事情在某個線程裏進行處理。

6. 接下來,System Server會啓動一系列的Service, 其中最重要的就是Acitivity Manager 和Window Manager.

從圖中可以看出,Activity Manager 有一個Looper Thread, AThread。這裏請注意Binder Thread和 Looper的區別,我們在後面會有專門的文章介紹它們。Android裏大量用到了Binder 與 Looper的組合,其中很重要的一個原因是爲了解決多線程中複雜的同步問題,通過一個Looper和對應的Message 隊列,可以將來着不同進程的Binder 調用序列化,而不需要維護複雜的且容易出問題的鎖。

WindowManager 類似,他的Handler Thread 是我們剛纔提到的System server 啓動初期創建的兩個Handler線程之一,WMThread. 他的Binder線程會由Kernel的Binder Driver來指定。

除了ActivityManager Service 和 WindowManager Service, 還有很多其他的服務相繼啓動,這裏不再詳述,只需要知道一個Service啓動需要的幾個步驟:

       1. 初始化Service 對象,獲得IBinder對象。

       2. 啓動後臺線程,並進入Loop等待。

       3. 將自己註冊到Service Manager, 讓其他進程通過名字可以獲得遠程調用必須的IBinder的對象。

7. 毫無疑問,這麼多服務之間是有依賴關係的,比如說,ActivityManager Service 在WindowManager Service 初始化完成之前是不能啓動應用的。那如何控制這些先後順序的?這裏由System server的啓動線程(下圖中的綠色條快)通過SystemReady()接口來完成。每個系統服務必須實現一個SystemReady() 接口,當被調用,表明系統已經OK, 該服務可以訪問(直接或間接)其他服務的資源。最後一個被調到的服務就是AcitivyManager Service. AM的SystemReady() 是通過Runnable 在另外一個線程裏完成,參加下圖中註釋8下方的那個箭頭。在這個Runnable裏面要做的事情,就是將當前排在最頂層的一個應用程序啓動 - resumeTopActivityLocked(),通常來講,這就是我們常說的‘HOME’, 當然,這裏可以指定其他的應用程序作爲Startup應用,比如說GoogleTV 裏面可以將電視應用作爲啓動程序,這樣用戶啓動後直接可以看到節目,類似現在家裏的機頂盒。此外,ActivityManager Service 還會廣播 BOOT_COMPLETED 事件給整個系統,一般來說,很多應用的後臺Service可以通過註冊這個Event的 Receiver 來監聽並啓動。啓動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應用的啓動比較複雜,我們會在專門的章節裏面去研究ActivityManager的工作細節,此處,我們只需要知道ActivityStack 是存在當前運行Activity的棧,resumeTopActivityLocked() 從其中找到要啓動的那一個(在最開始,該棧是空的,因爲需要通過moveTaskFromFrontLocked() 將‘Home' 推到該棧中),如果該應用從來沒有啓動過,我們需要通過AcitivyManagerService 爲其創建一個進程。注意!進程 並不是由ActivityManager創建的,別忘了,我們前面提到Zygote是所有Android 應用的孵化器,對,ActivityManager 只是通知Zygote創建而已。這個通信是通過Process.java裏面實現的,具體代碼如下:

複製代碼
static LocalSocket sZygoteSocket;
private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
            throws ZygoteStartFailedEx {
        openZygoteSocketIfNeeded();
        try {
            ...
            sZygoteWriter.write(arg);
          }
          ...
          sZygoteWriter.flush(); //發送後等待...
          ... 
          result.pid = sZygoteInputStream.readInt();
          ...
          return result;
        } 
        sZygoteSocket = null;
    }
}
複製代碼

到此爲止,System Server的啓動已經完成,Zygote的啓動也已經完成,接下來我們介紹Zygote進程生命裏做的唯一一件事,克隆自己。

5. Fork

 在Process.java 發送fork 請求之前,Zygote已經準備好了服務器端,這個我們已經在前面的Zygote Init 章節裏介紹過了。此處我們簡要分析一下Zygote Server端收到請求的處理。代碼在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 子進程之前做把GC而不是在每個子進程裏自己做,可以提高效率,但也不能每次都做因爲GC還是很耗時的。*/
            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);
         }

try {
            parsedArgs = new Arguments(args);
            applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
            ...

            pid = Zygote.forkAndSpecialize(parsedArgs.uid,parsedArgs.gid, parsedArgs.gids,parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,parsedArgs.niceName);
        } catch (IOException ex) {
            ...
        }

        try {
            if (pid == 0) {
                // 子進程,將serverFd釋放
                serverPipeFd = null;
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
            } else {
                // 父進程,將不用的子進程的PipeFd釋放
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            IoUtils.closeQuietly(childPipeFd);
            IoUtils.closeQuietly(serverPipeFd);
        }
    }
複製代碼

Android 應用的啓動在handleChildProc裏完成:

複製代碼
    private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws ZygoteInit.MethodAndArgsCaller {

        closeSocket(); // 不需要服務端的socket
        ZygoteInit.closeServerSocket();
        ...
        if (parsedArgs.runtimeInit) { //從Process.java 來的都爲true
            if (parsedArgs.invokeWith != null) {
                WrapperInit.execApplication(parsedArgs.invokeWith,
                        parsedArgs.niceName, parsedArgs.targetSdkVersion,
                        pipeFd, parsedArgs.remainingArgs); // 啓動命令行程序
            } else {
                RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
                        parsedArgs.remainingArgs); // 幾乎所有的應用啓動都走這條路
            }
        } 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() 函數實現是

    static void invokeStaticMain(ClassLoader loader,String className, String[] argv)     throws zygoteInit.MethodAndArgsCaller {
        ...
        throw new ZygoteInit.MethodAndArgsCaller(m, argv);
    }

 

細心的讀者可能會問這麼幾個問題:

1. 爲什麼不直接Call 相應的Java函數,而是通過一個exception?  MethodAndArgsCaller. 這裏Android 巧妙的運用到了Java Exception的一些設計特性。Execption一大特性就是當發生或拋出異常的時候,可以從發生錯誤的地方順着調用棧回溯直到找到捕捉該異常的代碼段。捕捉該異常的代碼如下

複製代碼
    public static void main(String argv[]) {
        ...
        try {
            runSelectLoop();
            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run(); //真正的入口在這裏。
        } catch (RuntimeException ex) {
            ...
        }
    }
複製代碼

這下你明白爲什麼總在dumpstate 文件裏看到以下的調用棧了吧

   ...
   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. 爲什麼所有的應用都從“android.app.ActivityThread")開始? 在這裏留個伏筆,我們會在http://www.cnblogs.com/samchen2009/p/3315993.html 系統的介紹Android Activity 從啓動到顯示的整個過程。

應用程序啓動完畢,Zygote有重新睡去,等待新的應用程序啓動請求。

 

6. 善後工作

      是不是到此之後,Zygote的工作變得很輕鬆了,可以宜養天年了?可惜現代社會,哪個父母把孩子養大就可以撒手不管了?尤其是像Sytem Server 這樣肩負社會重任的大兒子,出問題了父母還是要幫一把的。這裏,Zygote會默默的在後臺凝視這自己的大兒子,一旦發現System Server 掛掉了,將其回收,然後將自己殺掉,重新開始新的一生, 可憐天下父母心啊。這段實現在代碼 :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 會讓waitpid 立即返回,這裏只是爲了預防上面的賦值語句沒有完成之前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 在這裏註冊
    ...
    pid = fork();
    ...
    RETURN_INT(pid);
}
複製代碼

    在Unix-like系統,父進程必須用 waitpid 等待子進程的退出,否則子進程將變成"Zombie" (殭屍)進程,不僅系統資源泄漏,而且系統將崩潰(沒有system server,所有Android應用程序都無法運行)。但是waitpid() 是一個阻塞函數(WNOHANG參數除外),所以通常做法是在signal 處理函數裏進行無阻塞的處理,因爲每個子進程退出的時候,系統會發出 SIGCHID 信號。Zygote會把自己殺掉, 那父親死了,所有的應用程序不就成爲孤兒了? 不會,因爲父進程被殺掉後系統會自動給所有的子進程發生SIGHUP信號,該信號的默認處理就是將殺掉自己退出當前進程。但是一些後臺進程(Daemon)可以通過設置SIG_IGN參數來忽略這個信號,從而得以在後臺繼續運行。

      

 

總結

Zygote和System Server的啓動過程終於介紹完了,讓我們對着上面這張完整的類圖再來重溫一下這個過程吧。

1.  init 根據init.rc 運行 app_process, 並攜帶‘--zygote' 和 ’--startSystemServer' 參數。

2.  AndroidRuntime.cpp::start() 裏將啓動JavaVM,並且註冊所有framework相關的系統JNI接口。

3.  第一次進入Java世界,運行ZygoteInit.java::main() 函數初始化Zygote. Zygote 並創建Socket的server 端。

4.  然後fork一個新的進程並在新進程裏初始化SystemServer. Fork之前,Zygote是preload常用的Java類庫,以及系統的resources,同時GC()清理內存空間,爲子進程省去重複的工作。

5.  SystemServer 裏將所有的系統Service初始化,包括ActivityManager 和 WindowManager, 他們是應用程序運行起來的前提。

6.  依次同時,Zygote監聽服務端Socket,等待新的應用啓動請求。

7.  ActivityManager ready 之後尋找系統的“Startup” Application, 將請求發給Zygote。

8.  Zygote收到請求後,fork出一個新的進程。

9.  Zygote監聽並處理SystemServer 的 SIGCHID 信號,一旦System Server崩潰,立即將自己殺死。init會重啓Zygote.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章