Android之Zygote介紹

lvxiangan發表於2019-01-11

在Android系統中,應用程式程式都是由Zygote程式孵化出來的,而Zygote程式是由Init程式啟動的。Zygote程式在啟動時會建立一個Dalvik虛擬機器例項,每當它孵化一個新的應用程式程式時,都會將這個Dalvik虛擬機器例項複製到新的應用程式程式裡面去,從而使得每一個應用程式程式都有一個獨立的Dalvik虛擬機器例項。
 

 

  1. Zygote(受精卵),Android中最重要的一個程式,它和Init程式、SystemServer程式是Android最重要的三大程式。
  2. 其他所有的Dalvik虛擬機器程式都是通過Zygote 孵化(fork)出來的。
  3. Android應用程式執行在各自獨立的Dalvik虛擬機器中。如果每個應用程式在啟動之時都需要單獨執行和初始化一個虛擬機器,會大大降低系統效能,因此Android首先建立一個zygote虛擬機器,然後通過它孵化出其他的虛擬機器程式,進而共享虛擬機器記憶體和框架層資源,這樣大幅度提高應用程式的啟動和執行速度
  4. Zygote程式在Init程式中通過解析init.zygote.rc檔案配置,以service的方式啟動建立的,它是android系統第一個java程式,是所有java程式的父程式,zygote最初名字叫“app_process”,這個名字是在Android.mk檔案中指定的,但是在執行過程中Linux下的pctrl系統呼叫將名字換成了“zygote”,因此通過ps命令檢視到程式名稱為”zygote”,對應的原始檔是App_main.cpp,zygote孵化的第一個程式是System Server程式。

Zygote程式在啟動的過程中,除了會建立一個Dalvik虛擬機器例項之外,還會將Java執行時庫載入到程式中來,以及註冊一些Android核心類的JNI方法來前面建立的Dalvik虛擬機器例項中去。注意,apk應用程式程式被Zygote程式孵化出來的時候,不僅會獲得Zygote程式中的Dalvik虛擬機器例項拷貝,還會與Zygote一起共享Java執行時庫
 


由 init 啟動的程式在“system\core\rootdir\root.rc”指令碼中都有描述:

再來看 zygote.rc (以 init.zygote32.rc 為例):

服務名稱為:zygote
啟動該服務執行的命令: /system/bin/app_process
命令的引數: -Xzygote /system/bin –zygote –start-system-server
socket zygote stream 660建立一個名為:/dev/socket/zygote 的 socket,
型別為:stream,許可權為:660
onrestart:當服務重啟時,執行該關鍵字後面指定的command

總結:zygote要執行的程式便是system/bin/app_process,它的原始碼在frameworks/base/cmds/app_process/app_main.cpp


這段指令碼要求 init 程式建立一個名為 zygote 的程式,該程式要執行的程式是“/system/bin/app_process”。並且為 zygote 程式建立一個 socket 資源 (用於程式間通訊,ActivityManagerService 就是通過該 socket 請求 zygote 程式 fork 一個應用程式程式)。

後面的“--zygote”是傳給 app_process 的引數,表示啟動的是 zygote 程式。在 app_process 的 main 函式中會依據該引數決定執行 ZygoteInit 還是 Java 類。

zygote 程式在初始化時會啟動虛擬機器,並載入一些系統資源。這樣 zygote fork 出子程式後,子程式也繼承了能正常工作的虛擬機器和各種系統資源,接下來只需裝載 apk 檔案的位元組碼就可以執行應用程式了,可以大大縮短應用的啟動時間,這就是 zygote 程式的主要作用。

Java 應用程式不能直接以本地程式的形態執行,必須在一個獨立的虛擬機器中執行。如果每次都重新啟動虛擬機器,將嚴重拖慢應用程式的啟動速度。

Linux 的程式都是 fork 出來的,fork 出的子程式與父程式共享記憶體映像。只有當子程式改寫記憶體時,作業系統才會為其分配一個新頁面,並將老頁面上的資料複製一份到新頁面,這就是“寫時拷貝(Copy On Write)”。


 

初始化Zygote涉及到的函式呼叫

App_main.main
  AndroidRuntime.start
    startVm
    startReg
    ZygoteInit.main
        registerZygoteSocket
        preload
        startSystemServer
        runSelectLoop

原始碼出處:
/frameworks/base/cmds/app_process/App_main.cpp (內含AppRuntime類)
/frameworks/base/core/jni/AndroidRuntime.cpp
/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
/frameworks/base/core/java/com/android/internal/os/Zygote.java
/frameworks/base/core/java/android/net/LocalServerSocket.java

 

 

從AndroidRuntime到ZygoteInit,主要分為2大過程

1、建立虛擬機器——startVm:呼叫JNI虛擬機器建立函式
2、註冊JNI函式——startReg:前面已經建立虛擬機器,這裡給這個虛擬機器註冊一些JNI函式(後續java世界用到的函式是native實現,這裡需要提前註冊註冊這些函式)

此時就要執行CallStaticViodMethod,通過這個函式將進入android精心打造的java世界,這個函式將呼叫com.android.internal.os.ZygoteInit的main函式

在 ZygoteInit.main函式中進入java世界,主要有4個關鍵步驟
1、建立IPC通訊服務——registerZygoteSocket
zygote及系統中其他程式的通訊並沒有使用Binder,而是採用基於AF_UNIX型別的Socket,registerZygoteSocket函式的作用正是建立這個Socket

2、預載入類和資源
主要是preloadClasses和preloadResources,其中preloadClasses一般是載入時間超過1250ms的類,因而需要在zygote預載入

3、啟動system_server——startSystemServer
這個函式會建立Java世界中系統Service所駐留的程式system_server,該程式是framework的核心,也是zygote孵化出的第一個程式。如果它死了,就會導致zygote自殺。

4、等待請求——runSelectLoppMode
zygote從startSystemServer返回後,將進入第四個關鍵函式runSelectLoppMode,在第一個函式registerZygoteSocket中註冊了一個用於IPC的Socket將在這裡使用,這裡Zygote採用高效的I/O多路複用機制,保證在沒有客戶端請求時或者資料處理時休眠,否則響應客戶端的請求

此時zygote完成了java世界的初創工作,呼叫runSelectLoppMode便開始休眠了,當收到請求或者資料處理便會隨時醒來,繼續工作

zygote的分裂

zygote主要用來孵化system_server程式和應用程式程式。在孵化出第一個程式system_server後通過runSelectLoopMode等待並處理訊息,分裂應用程式程式仍由system_server控制,如app啟動時建立子程式

 

 

 

 

參考:
https://blog.csdn.net/XSF50717/article/details/51607176 
https://blog.csdn.net/sgzy001/article/details/44856643 
https://blog.csdn.net/fengluoye2012/article/details/80023051
https://blog.csdn.net/tfygg/article/details/52086621

相關文章