Android深水區(qū):Android系統(tǒng)啟動

Android深水區(qū):Android系統(tǒng)啟動

開篇

對于Android系統(tǒng),有一張大家都見過的系統(tǒng)架構(gòu)圖

Android系統(tǒng).png

我們平時接觸的Android應(yīng)用開發(fā)及開源代碼都位于最上層(Application層),對Android FrameWork層接觸不多,但Android系統(tǒng)很多的精妙設(shè)計都處于FrameWork層及以下,要想理解Android系統(tǒng)則必須學(xué)習(xí)FrameWork層。本系列我將和大家一起開始FrameWork層的學(xué)習(xí),我們將依次學(xué)習(xí)Android啟動、Android跨進程Binder機制,Android四大組件啟動過程。在學(xué)習(xí)過程中不僅會接觸大量的Java層源碼,由于Android系統(tǒng)底層是linux,因此學(xué)習(xí)過程中還會涉及一些linux知識及C++代碼,為了不讓大家陷入代碼、糾于細節(jié),本系列主要會從架構(gòu)層面解釋具體原理,對應(yīng)節(jié)點會列出對應(yīng)源碼位置,有興趣的同學(xué)可以去進一步閱讀源碼。要想學(xué)好Android,只有那句程序猿至理名言RTFSC(Read The Fucking Source Code)。
關(guān)于Android源碼閱讀,推薦一個非常好的在線閱讀源碼閱讀網(wǎng)址:Android源碼

Android系統(tǒng)啟動流程

本文主要介紹Android系統(tǒng)的啟動過程,主要目的一是讓大家大致了解Android手機啟動后都在做什么,二是介紹幾個核心的系統(tǒng)服務(wù)及進程,為后續(xù)文章做一個鋪墊。本文以Android 9.0.0_r8系統(tǒng)源碼為例,Android系統(tǒng)啟動大致可以分為四步:

  • 系統(tǒng)環(huán)境準備
  • 啟動init進程
  • 啟動Zygote進程
  • 啟動SystemServer進程
Android系統(tǒng)啟動.png

下面我們依次來分析每一步都在做什么

系統(tǒng)環(huán)境準備

該步驟主要是用戶按下開機鍵后的一些硬件初始化、系統(tǒng)加載過程,簡單介紹不作過多說明

BootLoader

Bootloader是嵌入式系統(tǒng)在加電后執(zhí)行的第一段代碼,進行硬件初始化,獲取內(nèi)存大小信息等,調(diào)整手機到適配狀態(tài)。在它完成CPU和相關(guān)硬件的初始化之后,再將操作系統(tǒng)映像或固化的嵌入式應(yīng)用程序加載到內(nèi)存中然后跳轉(zhuǎn)到操作系統(tǒng)所在的空間,最終目標是拉起操作系統(tǒng)。當用戶按下開機鍵后,芯片就會開始將BootLoader加載到內(nèi)存中。

系統(tǒng)加載

BootLoader加載成功后,手機會通過BootLoader加載系統(tǒng),啟動系統(tǒng)內(nèi)核(Kernel)并做相應(yīng)的環(huán)境初始化設(shè)置,開始init進程啟動

init進程

init進程簡介

  • 我們知道,Android系統(tǒng)也有很多自己的系統(tǒng)級的服務(wù)進程,Android系統(tǒng)可以正常運行都依賴于這些進程,而init進程是這些所有的進程的根進程,這些進程都是由init進程孵化而來。
  • init進程是Android系統(tǒng)的第一個進程,我們可以通過adb shell -p命令 看到,init進程的pid為1。

init啟動流程分析

init是處于linux系統(tǒng)的用戶空間,在第一步系統(tǒng)環(huán)境準備后,linux內(nèi)核啟動成功便會調(diào)用/system/core/init/Init.cpp 中的main()開始init進程的啟動。init.cpp中main()函數(shù)較長,做相應(yīng)截取說明

int main(int argc, char** argv) {
     ...
    // 1、創(chuàng)建、掛載相應(yīng)文件
    // Get the basic filesystem setup we need put together in the initramdisk
    // on / and then we'll let the rc file figure out the rest.
    mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
    mkdir("/dev/pts", 0755);
     ...
    // 2.初始化log服務(wù)、屬性服務(wù)
    InitKernelLogging(argv);
    ....
    property_init();
    ...
    // 3、解析init.rc
    LoadBootScripts(am, sm);
    ...
    // 相關(guān)邏輯執(zhí)行完后,會進入一個while true循環(huán)等待任務(wù)執(zhí)行
}

代碼很長,我們關(guān)心的主要包含3步

第一步 創(chuàng)建、掛載相應(yīng)文件

  • 創(chuàng)建并掛載系統(tǒng)運行時所需的目錄,主要包括tmpfs、devpts、proc、sysfs和selinuxfs五種文件系統(tǒng)。

第二步 初始化log服務(wù)、屬性服務(wù)

  • 調(diào)用InitKernelLogging(argv)初始化日志系統(tǒng),之后會執(zhí)行LOG(INFO) << "init first stage started!",出內(nèi)核中第一句log。
  • 在Android系統(tǒng)中,所有的進程共享系統(tǒng)初始值,這些值存在于系統(tǒng)的共享內(nèi)存區(qū)域,通過調(diào)用property_init()對相關(guān)值進行初始化。

第三步 解析init.rc配置文件

  • LoadBootScripts函數(shù)主要工作就是解析init.rc文件,關(guān)鍵代碼parser.ParseConfig("/init.rc")
  • init.rc文件是一個非常重要的配置文件,它由AIL語言(Android Init Language)編寫,源碼位于/system/core/rootdir/init.rc,核心代碼如下。
    # Now we can start zygote for devices with file based encryption
    trigger zygote-start
  • trigger zygote-start從源碼注釋可以看出,這步開始初始化Zygote進程。

Zygote進程

Zygote進程簡介

Zygote是受精卵的意思,它是Android中的一個非常重要的守護進程服務(wù)(Daem Service),所有的其他Dalvik虛擬機(進程)都是通過zygote孵化(fork)出來的。Android應(yīng)用程序是由Java語言編寫的,運行在各自獨立的Dalvik虛擬機(進程)中。如果每個應(yīng)用程序在啟動之時都需要單獨運行和初始化一個虛擬機(進程),會大大降低系統(tǒng)性能,因此Android首先創(chuàng)建一個zygote虛擬機(進程),然后通過它孵化出其他的虛擬機(進程),進而共享虛擬機內(nèi)存和框架層資源,這樣大幅度提高應(yīng)用程序的啟動和運行速度。
Zygote是Android中最重要的一個進程,和Init進程,SystemServer進程是支撐Android世界的三極。Android8.0后對zygote.rc文件進行了拆分,存在以下四種:

  • init.zygote32.rc
  • init.zygote32_64.rc
  • init.zygote64.rc
  • init.zygote64_32.rc

我們以init.zygote32.rc為例來簡單分析下

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc reserved_disk
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    onrestart restart wificond
    writepid /dev/cpuset/foreground/tasks

代碼不多,共15行,也是Android Init Language語法,執(zhí)行邏輯就是啟動進程,名稱為zygote,執(zhí)行程序為/system/bin/app_process,類名為main,當Zygote進程重啟時,重啟audioserver、cameraserver、media等進程。下面我們通過frameworks/base/cmds/app_process/app_main.cpp具體分析Zygote進程初始化流程。

Zygote啟動流程分析

Zygote進程初始化過程會進入Java層,因此我們分為C++層跟Java層分別分析。

C++層

同樣,我們看下app_main.cpp中的main方法,代碼較長,我們截取分析。

int main(int argc, char* const argv[])
{
    ...
   // 1、創(chuàng)建AppRuntime變量
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));     // 1
    // Process command line arguments
    // ignore argv[0]
    argc--;
    argv++;

    ...
    // 2、創(chuàng)建Zygote進程
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            // Zygote進程自己
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {     
            // SystemServer進程
            startSystemServer = true; 
        } else if (strcmp(arg, "--application") == 0) {
           // 普通應(yīng)用進程
            application = true;
        } 
        
        ...
    }

    ...

    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);      
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
    }
}
第一步 創(chuàng)建AppRuntime變量
  • 定義了一個名為runtime的變量,其類型是AppRuntime,該類繼承自AndroidRuntime,也定義在app_main.cpp中
第二步 創(chuàng)建Zygote進程,進入Java層
  • 定義了一個名為runtime的變量,其類型是AppRuntime,該類繼承自AndroidRuntime,也定義在app_main.cpp中
  • Zygote進程都是通過fork自身來創(chuàng)建子進程的,這樣Zygote進程以及它的子進程都可以進入app_main.cpp的main()函數(shù),因此main()函數(shù)中為了區(qū)分當前運行在哪個進程,會判斷參數(shù)argv中是否包含--zygote,若包含則說明main()函數(shù)是運行在Zygote進程中的并將變量zygote設(shè)置為true;判斷參數(shù)argv是否包含--start-system-server,若包含則說明main()函數(shù)是運行在SystemServer進程中的并在將變量startSystemServer設(shè)置為true;判斷參數(shù)argv是否包含--application,若包含則說明main()函數(shù)是運行在普通進程。
  • 若zygote屬性為true,則通過AppRuntime的start()函數(shù),通過jni調(diào)用,執(zhí)行com.android.internal.os.ZygoteInit中的main()方法,經(jīng)過此步,Android初始化首次進入Java層。下面我們開始研究ZygoteInit,該類位于/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

Java層

我們截取看下ZygoteInit中的main方法

         // 1、創(chuàng)建Socket
          ...
          String socketName = "zygote";
          ...
          zygoteServer.registerServerSocketFromEnv(socketName);
          ...
         // 2、預(yù)加載類、資源
         preload(bootTimingsTraceLog);
         ...
         // 3、fork SystemServer進程
         if (startSystemServer) {
             Runnable r = forkSystemServer(abiList, socketName, zygoteServer); 
             ...
             if (r != null) {
                 r.run();
                 return;
              }
         }
          ...
            
         // 4、等待AMS消息
         // The select loop returns early in the child process after a fork and
         // loops forever in the zygote.
          caller = zygoteServer.runSelectLoop(abiList); 

第一步 創(chuàng)建Socket
  • 調(diào)用registerServerSocketFromEnv()方法創(chuàng)建一個Server端名為“zygote”的Socket,這個Socket用于與AMS(ActivityManagerService)通信,后續(xù)程序運行時若要創(chuàng)建普通進程,則由AMS通過該Socket通知Zygote進程孵化。這里稍微了解Android跨進程通信的可能會問,此處為什么不使用Binder進行跨進程通信,原因在于Binder機制依賴于ServiceManger,而此時ServiceManger還未創(chuàng)建。
第二步 預(yù)加載類、資源
  • 調(diào)用preload(bootTimingsTraceLog)方法,預(yù)加載類和資源,應(yīng)用程序中以com.android.internal.R.xxx頭的資源,便是此時由Zygote加載到內(nèi)存的。
第三步 fork SystemServer進程
  • 在C++層第二步中判斷邏輯一致,當若傳入的參數(shù)中包含--start-system-server,則startSystemServer為true
  • 調(diào)用forkSystemServer()方法fork出SystemServer進程,調(diào)用run()方法啟動。
第四步
  • 調(diào)用ZygoteServer的runSelectLoop()方法,等待AMS請求創(chuàng)建新的應(yīng)用程序進程。

SystemServer進程

SystemServer進程簡介

  • SystemServer進程是Zygote創(chuàng)建的第一個Java進程,主要用于創(chuàng)建系統(tǒng)服務(wù),ActivityMangerService、PackageManagerService和WindowManagerService等這些重要的服務(wù)都是通過SystemServer進程啟動的。

SystemServer啟動流程分析

上文談到forkSystemServer()方法,該方法進行一系列調(diào)用后,最終啟動SystemServer進程會進入com.android.server.SystemServer.java,該類的main方法直接調(diào)用SystemServer的run()方法,我們直接看run方法。

private void run() {
     ...
     // 創(chuàng)建主線程
     Looper.prepareMainLooper();
     ...
     // 1、加載動態(tài)庫
     System.loadLibrary("android_servers");
     ...
     // 創(chuàng)建system Context
     createSystemContext();
     ...
     // 2、創(chuàng)建ServiceManager
     mSystemServiceManager = new SystemServiceManager(mSystemContext);
     ...
     // 3、啟動引導(dǎo)服務(wù)、啟動核心服務(wù)、啟動其他服務(wù)
     startBootstrapServices();    
     startCoreServices();         
     startOtherServices();
     ...
}

第一步 加載動態(tài)庫

  • 加載動態(tài)庫libandroid_servers.so,初始化native服務(wù)。

第二步 創(chuàng)建ServiceManager

  • 創(chuàng)建SystemServiceManager對象,Binder機制啟用。

第三步 啟動引導(dǎo)服務(wù)、啟動核心服務(wù)、啟動其他服務(wù)

  • 官方把系統(tǒng)服務(wù)分為了三種類型,分別是引導(dǎo)服務(wù)、核心服務(wù)和其他服務(wù)。
  • 引導(dǎo)服務(wù)主要包括ActivityManagerService、PowerManagerService、PackageManagerService。
  • 核心服務(wù)有DropBoxManagerService、BatteryService等。
  • 其他服務(wù)是一些不緊要和不需要立即啟動的服務(wù),不一一舉例。

總結(jié)

至此,Android系統(tǒng)啟動核心部分已經(jīng)分析結(jié)束。我們分析了Android系統(tǒng)啟動后硬件環(huán)境準備,init進程如何啟動Zygote進程,Zygote進程如何孵化SystemServer進程。本文分析主要是流程分析,源碼分析只是指出關(guān)鍵方法,很多代碼細節(jié)一筆帶過,有興趣的同學(xué)可以自己去源碼內(nèi)研究。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容