Android框架簡(jiǎn)介--啟動(dòng)過(guò)程--Zygote

Zygote是做什么的

Zygote簡(jiǎn)單地說(shuō)主要作用是兩方面:

  • 啟動(dòng)SystemServer
  • 孵化應(yīng)用進(jìn)程

Android中大多數(shù)應(yīng)用進(jìn)程和系統(tǒng)進(jìn)程都是通過(guò)Zygote進(jìn)程來(lái)生成。Zygote為孵化的應(yīng)用程序提供了幾個(gè)基礎(chǔ)資源:

  • 常用類(lèi) :Android的Java 類(lèi)庫(kù), 大部分來(lái)自于 Apache Hamony, 開(kāi)源的Java API 實(shí)現(xiàn),如 java.lang, java.util, java.net
  • JNI函數(shù)
  • 主題資源 : 比如theme圖片, 占用10M+的內(nèi)存空間,這些內(nèi)存是系統(tǒng)共享的
  • 共享庫(kù):

Zygote進(jìn)程啟動(dòng)

Zygote由init進(jìn)程解析init.rc腳本啟動(dòng)的?,F(xiàn)在機(jī)器分為32位和64位,Zygote的啟動(dòng)也要區(qū)分對(duì)待:

/system/core/rootdir/init.rc
import /init.${ro.zygote}.rc

根據(jù)系統(tǒng)屬性ro.zygote的具體值,加載不同的描述Zygote的rc腳本。譬如firely rk3399包含的文件:
init.zygote32.rc
init.zygote32_64.rc
init.zygote64.rc
init.zygote64_32.rc
其中zygote32和zygote64分別對(duì)應(yīng)32位和64位機(jī)器。zygote32_64和zygote64_32則Primary Arch 和 Secondary Arch的組合,以init.zygote64.rc為例,相關(guān)腳本如下:

service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
    class main
    priority -20
    user root
    group root readproc
    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

從路徑來(lái)看,Zygote所在的應(yīng)用程序名稱叫"app_process64",

  • zygote 就是service的名稱
  • /system/bin/app_process64 應(yīng)用程序路徑,即Zygote所在的應(yīng)用進(jìn)程
  • -Xzygote /system/bin --zygote --start-system-server 為傳遞給app_process的參數(shù),后面的分析會(huì)看到參數(shù)--zygote被用來(lái) app_process 啟動(dòng)Zygote的選項(xiàng), --start-system-server 會(huì)被作為參數(shù)傳遞給Zygote的ZygoteInit.

可以簡(jiǎn)單地用下面這副圖描述Zygote的啟動(dòng)


zygote創(chuàng)建.png

Zygote啟動(dòng)時(shí)都做了什么

Zygote啟動(dòng)主要經(jīng)歷了兩部分:

  • native世界
  • java世界

native世界

從Zygote的rc腳本我們知道, Zygote是通過(guò)app_process啟動(dòng),入口就是app_process的main函數(shù)
frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));

    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    String8 niceName;
    String8 className;
   
    ++i;  // Skip unused "parent dir" argument.
    while (i < argc) {
        const char* arg = argv[i++];
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = ZYGOTE_NICE_NAME;
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName.setTo(arg + 12);
        } else if (strncmp(arg, "--", 2) != 0) {
            className.setTo(arg);
            break;
        } else {
            --i;
            break;
        }
    }

    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        
    }
    

這里有3點(diǎn),

  1. 創(chuàng)建了AndroidRuntime對(duì)象, 這里面主要的動(dòng)作就是啟動(dòng)虛擬機(jī)
  2. 解析傳進(jìn)來(lái)的參數(shù) . 這個(gè)場(chǎng)景中--zygote 指定了app_process接下來(lái)將啟動(dòng)"ZygoteInit", 并傳入-start-system-server
  3. 在虛擬機(jī)中運(yùn)行ZygoteInit , ZygoteInit是java寫(xiě)的,即這一步Zygote就從native世界進(jìn)入到了java世界

簡(jiǎn)單來(lái)說(shuō),Zygote在native世界做的主要是以下幾步:

  • 啟動(dòng)Android虛擬機(jī)
  • 注冊(cè)Android的JNI函數(shù)
  • 進(jìn)入java世界

java世界

Zygote的java世界入口是ZygoteInit 的main函數(shù)
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

 public static void main(String argv[]) {
            zygoteServer.registerServerSocket(socketName);   
            // In some configurations, we avoid preloading resources and classes eagerly.
            // In such cases, we will preload things prior to our first fork.
            if (!enableLazyPreload) {
                preload(bootTimingsTraceLog);  //預(yù)加載各類(lèi)資源
            } else {
                Zygote.resetNicePriority();
            }

           if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {
                    r.run();
                    return;
                }
            }

            caller = zygoteServer.runSelectLoop(abiList);
}

ZygoteInit的主函數(shù)主要完成幾件事情:

  • 注冊(cè)一個(gè)socket
    Zygote 作為孵化器,跟其他進(jìn)程間的通訊不是通過(guò)binder而是通過(guò)socket。一旦有新進(jìn)程需要運(yùn)行,系統(tǒng)會(huì)通過(guò)這個(gè)Socket(完整的名稱為ANDROID_SOCKET_zygote)跟Zygote通訊,由zygote完成進(jìn)程孵化過(guò)程
  • 預(yù)加載各類(lèi)資源
    函數(shù)preload用于加載虛擬機(jī)運(yùn)行時(shí)所需的各類(lèi)資源
  • 啟動(dòng)System Server
  • 進(jìn)入Loop循環(huán)

其他問(wèn)題點(diǎn)

為何用socket而不是binder

Zygote是通過(guò)fork來(lái)創(chuàng)建新進(jìn)程的,而binder是多線程的,有可能造成死鎖。

在 POSIX 標(biāo)準(zhǔn)中,fork 的行為是這樣的:復(fù)制整個(gè)用戶空間的數(shù)據(jù)(通常使用 copy-on-write 的策略,所以可以實(shí)現(xiàn)的速度很快)以及所有系統(tǒng)對(duì)象, 然后僅復(fù)制當(dāng)前線程到子進(jìn)程。這里:所有父進(jìn)程中別的線程,到了子進(jìn)程中都是突然蒸發(fā)掉的。

假如父進(jìn)程在獲取到鎖的情況下,fork了一個(gè)子進(jìn)程。子進(jìn)程的內(nèi)存中,這個(gè)鎖的狀態(tài)是上鎖狀態(tài)。子進(jìn)程僅運(yùn)行了fork所在的這個(gè)線程,其它線程沒(méi)有運(yùn)行,當(dāng)它嘗試獲取鎖時(shí),就發(fā)生了死鎖

為何要通過(guò)Zygote來(lái)孵化程序,而不是由其他進(jìn)程直接創(chuàng)建

主要有兩個(gè)好處:

  • 縮短應(yīng)用的啟動(dòng)時(shí)間
    無(wú)論哪個(gè)app,所有的虛擬機(jī)都必須按照某種一樣的而且是確定的方式初始化。Zygote預(yù)加載了各種資源,創(chuàng)建了虛擬機(jī)。由Zygote創(chuàng)建的進(jìn)程能夠繼承這些資源,不用再重新創(chuàng)建。加載app的類(lèi)只是最后一步而已。
  • 優(yōu)化共享內(nèi)存
    所有虛擬機(jī)都是從Zygote fork出來(lái)的,所以特么能夠享受到由內(nèi)核實(shí)現(xiàn)的內(nèi)存共享的優(yōu)勢(shì)。比如Zygote預(yù)加載的各類(lèi)資源,比如theme主題圖片,所有的進(jìn)程都是共享的,在物理內(nèi)存中只需要保存一份。

Zygote這一設(shè)計(jì)有什么缺點(diǎn)

所有應(yīng)用進(jìn)程都是從同一個(gè)進(jìn)程fork出來(lái)的,這會(huì)有效地破壞地址空間布局隨機(jī)化,這一技術(shù)是對(duì)抗代碼注入攻擊的重要安全手段

參考
網(wǎng)絡(luò)課程 --剖析Framework面試 沖擊Android高級(jí)職位
最強(qiáng)Android書(shū)架構(gòu)大剖析
深入理解Android內(nèi)核設(shè)計(jì)思想
https://blog.csdn.net/boygrass/article/details/27103383

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

相關(guān)閱讀更多精彩內(nèi)容

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