大廠Android開發高頻面試問題:說說你對Zygote的理解

前言

Zygote可以說是Android開發面試很高頻的一道問題,

但總有小夥伴在回答這道問題總不能讓面試滿意,

在這你就要搞清楚面試問你對Zygote的理解時,他最想聽到的和其實想問的應該是哪些?

下面我們透過以下幾點來剖析這道問題!

瞭解Zygote的作用

熟悉Zygote的啟動流程

深刻理解Zygote的工作原理

下面來我們來深入剖析

一、 Zygote的作用

Zygote的作用分為兩點:

啟動SystemServer

孵化應用程序

關於這個問題答出了這兩點那就是OK了。可能大部分小夥伴可能能答出第二點,第一點就不是很清楚。SystemServer也是Zygote啟動的,因為SystemServer需要用到Zygote準備好的系統資源包括:

大廠Android開發高頻面試問題:說說你對Zygote的理解

直接從Zygote繼承過來就不需要重新載入過來,那麼對效能將會有很大的提升。

二、Zygote的啟動流程

2。1 啟動三段式

在說Zygote啟動流程之前,

先明確一個概念:啟動三段式,

這個可以理解為Android中程序啟動的常用套路,

分為三步驟:

大廠Android開發高頻面試問題:說說你對Zygote的理解

這裡要了解LOOP迴圈是什麼,其實LOOP作用是不停地

接受訊息

處理訊息

,訊息的來源可以是

Soket

MessageQueue

Binder

驅動發過來的訊息,但無論訊息從哪裡來,它整個流程都是去接受訊息,處理訊息。這個啟動三段式,它不光是Zygote程序是這樣的,只要是有獨立程序的,比如說系統服務程序,自己的應用程序都是如此。

2。2 Zygote程序是怎麼啟動的?

Zygote程序的啟動取決於init程序,init程序是它是linux啟動之後使用者空間的第一個程序,下面看一下

啟動流程

linux啟動init程序

init程序啟動之後載入init。rc配置檔案

大廠Android開發高頻面試問題:說說你對Zygote的理解

3。啟動配置檔案中定義的系統服務,其中Zygote服務就是定義在配置中的

大廠Android開發高頻面試問題:說說你對Zygote的理解

4。同時啟動的服務除了Zygote之外還有一些別的系統服務也是會啟動的,比如說ServiceManager程序,它是透過fork+execve系統呼叫啟動的

大廠Android開發高頻面試問題:說說你對Zygote的理解

2。2。1載入Zygote的啟動配置

在init。rc 檔案中會import /init。${ro。zygote}。rc,init。zygoteXX,XX指的是32或者64,對我們沒差我們直接看init。zygote32。rc即可。配置檔案比較長,這裡做了擷取保留了Zygot相關的部分。

service zygote /system/bin/app_process -Xzygote /system/bin ——zygote ——start-system-server class main socket zygote stream 660 root system onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart audioserver writepid /dev/cpuset/foreground/tasks

service zygote:是程序名稱,

/system/bin/app_process:可執行程式的路徑,用於init程序fork,execve呼叫

-Xzygote /system/bin ——zygote ——start-system-server 為它的引數

2。2。2啟動程序

說完了啟動配置呢,這裡來聊一下啟動程序,

啟動程序有兩種方式:

第一種:fork+handle

pid_t pid = fork();if (pid == 0){ // child process} else { // parent process}

第二種:fork+execve

pid_t pid = fork();if (pid == 0) { // child process execve(path, argv, env);} else { // parent process}

兩者看起來差不多,首先首先都會呼叫fork函式建立子程序,這個函式比較奇特會返回兩次,子程序返回一次,父程序返回一次。

區別在於:

子程序一次,返回的pid是0 但是父程序返回的pid是子程序的pid,因此可以根據判斷pid來區分目前是子程序還是父程序

對於handle預設的情況,子程序會繼承父程序的所有資源,但當透過execve去載入二進位制程式時,那父程序的資源則會被清除

2。2。3訊號處理-SIGCHLD

當父程序fork子程序後,父程序需要關注這個訊號。當子程序掛了,父程序就會收到SIGCHLD,這時候父程序就可以做一些處理。例如Zygote程序如果掛了,那父程序init程序就會收到訊號將Zygote程序重啟。

大廠Android開發高頻面試問題:說說你對Zygote的理解

三、Zygote程序啟動原理

主要分為兩部分Native層處理和Java層處理,Zygote程序啟動之後,它執行了execve系統呼叫,它執行的是用C++寫的二進位制的可執行程式裡的main函式作為入口,然後在Java層執行!

先來看一下Native層的處理流程

大廠Android開發高頻面試問題:說說你對Zygote的理解

在app_main。cpp檔案,AndroidRuntime。cpp檔案。我們可以找到幾個主要函式名

int main(int argc,char *argv[]){ JavaVM *jvm; JNIEnv *env; JNI_CreateJavaVM(&jvm,(void**)&env,&vm_args); //建立Java虛擬機器 jclass clazz = env->FindClass(“ZygoteInit”); //找到叫ZygoteInit的Java類 jmethodID method = env->GetStaticMethodID(clazz,“Main”,“[Ljava/lang/String;)V”); //找到ZygoteInit類中的Main的靜態函式 env->CallStaticVoidMethod(clazz,method,args); //呼叫main函式 jvm->DestroyJavaVM();}

根據上述程式碼,你會發現在我們的應用裡直接就可以 JNI 呼叫了,並不需要建立虛擬機器。因為應用程序是Zygote程序孵化出來的,繼承了父程序的擁有虛擬機器,只需要重置資料即可。

接著看一下Java層的處理,具體可參考ZygoteInit檔案的main方法

1。預載入資源,比如常用類庫、主題資源及一些共享庫等

大廠Android開發高頻面試問題:說說你對Zygote的理解

2。啟動SystemServer程序

大廠Android開發高頻面試問題:說說你對Zygote的理解

3。進入Socket 的Loop迴圈 會看到的ZygoteServer。runSelectLoop(…)呼叫

boolean runOnce() { String[] args = readArgumentList(); //讀取引數列表 int pid = Zygote。forkAndSpecialize(); //根據讀取到的引數啟動子程序 if(pid == 0) { //in child //執行ActivityThread的入口函式(main) handleChildProc(args,。。。); return true; }}

大廠Android開發高頻面試問題:說說你對Zygote的理解

四、總結

Zygote啟動流程中需要主要以下2點問題

Zygote fork要保證是單執行緒

Zygote的IPC是採用socket

最後

如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:

​點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力。