Android Framework系列1 Zygote

前言

俗話說的好肩榕,好記憶不如爛筆頭刚陡;從業(yè)Android開發(fā)已多年,東西是越學越多株汉,越學越忘筐乳,此系列文章是對過去的所學總結(jié)。


Zygote的理解

1).Zygote的作用

1.啟動SystemServer
2.孵化應用進程

關(guān)于第二點孵化應用進程可能是大家比較熟悉的點乔妈,其實SystemServer也是通過Zygote啟動的蝙云,因為SystemServer需要用到Zygote里面準備的一些系統(tǒng)資源:比如常用的一些類,注冊的JNI函數(shù)褒翰,主題資源贮懈,共享庫等等,具體看之后的源碼介紹



2).Zygote的啟動流程

Android里面進程常用套路:進程啟動->準備工作->Loop循環(huán)

進程啟動.png

Loop循環(huán)
就是不停的接收消息處理消息优训,這個消息是從哪來的呢朵你?他可能是通過這個Socket發(fā)過來的,也可能是Message揣非,也可能呢抡医,是Binder驅(qū)動發(fā)過來的消息

Zygote進程如何啟動
Zygote進程它是如何被啟動的呢?這個我們得感謝init進程早敬,它是Linux啟動之后用戶空間的第一個進程忌傻,Init進程啟動之后首先會去加載一個啟用配置文件(init.rc)。里面定義了哪些系統(tǒng)服務需要這時候啟動的搞监。Zygote就是要啟動的服務之一(我們很熟悉的ServiceManager進程也在其中)水孩。那這個進程是怎么啟動的呢?就是通過fork加execve系統(tǒng)調(diào)用琐驴。

Zygote進程啟動.png

service zygote /system/bin/app_process64 -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 media
    onrestart restart netd
    writepid /dev/cpuset/foreground/tasks

init.rc語法就不擴展了俘种,其中有service名稱(zygote)秤标,有fork加execve系統(tǒng)調(diào)用所需的可執(zhí)行程序路徑(/system/bin/app_process64)以及后面所需的參數(shù)



Zygote進程啟動之后做了什么

1.Native世界

Zygote通過fork+ execve系統(tǒng)調(diào)用啟動進程,它執(zhí)行的是一個二進制的可執(zhí)行程序宙刘,用C++寫的里面有main函數(shù)作為入口苍姜。所以Zygote天生就是native的。做了如下三件事

Zygote的native世界.png

簡單的邏輯代碼可參考如下:

int main(int argc, char *argv[]) {    
        JavaVM *jvm;    
        JNIEnv *env;    
        JNI_CreateJavaVM(&jvm, (void **) &env, &vm_args);    
        jclass clazz = env->FindClass("ZygoteInit");    
        jmethodID method = env->GetStaticMethodID(clazz, "Main", "([Ljava/lang/String;)V");    
        env->CallStaticVoidMethod(clazz, method, args);    
        jvm->DestroyJavaVM();
    }

1.里邊首先通過 JNI_CreateJavaVM去創(chuàng)建一個虛擬機悬包。然后 再去找到一個叫ZygoteInit的Java類衙猪, 再去這個類里面找一個叫Main的靜態(tài)函數(shù),再通過這個CallStaticVoidMethod去調(diào)用這個函數(shù),最后呢布近,再去destroy這個java虛擬機 垫释。

2.JNI_CreateJavaVM去創(chuàng)建虛擬機。我們回想一下我們自己的應用撑瞧,里邊好像直接就可以JNI調(diào)用了啊饶号。沒有這么一句得先創(chuàng)建Java虛擬機的,那是為什么呢季蚂?因為這個Java虛擬機其實在Zygote進程里面就已經(jīng)創(chuàng)建好了茫船。咱們應用進程的是Zygote孵化出來的,就繼承了他的這個虛擬機扭屁,我們就不用再創(chuàng)建一遍了算谈,我們唯一要做的就是這個在進程啟動的時候重置一下這個虛擬機的狀態(tài) ,再重啟一下這個虛擬機料滥,里面的一些守護線程就可以了



2.Java世界
終于到了java世界了然眼,在java世界中做了哪些事情呢?主要有三件事

Zygote的java世界.png

  • 預加載資源:為了將來繼承給子進程,包括主題資源葵腹,常用類等
// 代碼來自Android23中:ZygoteInit.java
static void preload() {
        Log.d(TAG, "begin preload");
        preloadClasses();
        preloadResources();
        preloadOpenGL();
        preloadSharedLibraries();
        preloadTextResources();
        // Ask the WebViewFactory to do any initialization that must run in the zygote process,
        // for memory sharing purposes.
        WebViewFactory.prepareWebViewInZygote();
        Log.d(TAG, "end preload");
  • 啟動SystemServer:SystemServer單獨跑在一個進程
          // 代碼來自Android23中:ZygoteInit.java
private static boolean startSystemServer(String abiList, String socketName)
            throws MethodAndArgsCaller, RuntimeException {
          ......
         /* Request to fork the system server process */
          pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
          ......
}
  • 進入Loop循環(huán):等待的是socket消息
// 代碼來自Android23中:ZygoteInit.java
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
        ...
        while (true) {
            for (int i = pollFds.length - 1; i >= 0; --i) {
                boolean done = peers.get(i).runOnce();
            }
        }
    }

到這進入Loop循環(huán)后高每,等待Socket消息,拿到消息后執(zhí)行的是runOnce()

runOnce()

// 代碼來自Android23中:ZygoteInit.java
boolean runOnce() {    
        String[] args = readArgumentList();    
        int pid = Zygote.forkAndSpecialize();    
        if (pid == 0) {        
            // in child       
            handleChildProc(args, ...);        
            return true;    
        }
    }

runOnce先會創(chuàng)建一個進程践宴,然后在子進程中最終會調(diào)用handleChildProc鲸匿,這個方法其實就是執(zhí)行了一個java類的main函數(shù),類名通過AMS跨進程傳過來阻肩,其實就是\color{red}{ActivityThread}

這就通過Zygote孵化了一個進程带欢,進程的入口函數(shù)就是我們熟悉的ActivityThread的main方法。

總結(jié)

Zygote啟動流程如下:

  • init進程fork出zygote進程
  • 啟動虛擬機烤惊,注冊jni函數(shù)
  • 預加載系統(tǒng)資源
  • 啟動SystemServer
  • 進入Socket Loop循環(huán)

思考點

1.Zygote的跨進程通信采用了Linux的Socket乔煞,而不是Binder,為什么不采用Binder呢柒室?(后面文章會解釋渡贾,不過理解了本篇文章的同學應該也能猜到的吧)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市雄右,隨后出現(xiàn)的幾起案子空骚,更是在濱河造成了極大的恐慌锦溪,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件府怯,死亡現(xiàn)場離奇詭異,居然都是意外死亡防楷,警方通過查閱死者的電腦和手機牺丙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來复局,“玉大人冲簿,你說我怎么就攤上這事∫诨瑁” “怎么了峦剔?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長角钩。 經(jīng)常有香客問我吝沫,道長,這世上最難降的妖魔是什么递礼? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任惨险,我火速辦了婚禮,結(jié)果婚禮上脊髓,老公的妹妹穿的比我還像新娘辫愉。我一直安慰自己,他們只是感情好将硝,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布恭朗。 她就那樣靜靜地躺著,像睡著了一般依疼。 火紅的嫁衣襯著肌膚如雪痰腮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天律罢,我揣著相機與錄音诽嘉,去河邊找鬼。 笑死弟翘,一個胖子當著我的面吹牛虫腋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播稀余,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼悦冀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了睛琳?” 一聲冷哼從身側(cè)響起盒蟆,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤踏烙,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后历等,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體讨惩,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年寒屯,在試婚紗的時候發(fā)現(xiàn)自己被綠了荐捻。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡寡夹,死狀恐怖处面,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情菩掏,我是刑警寧澤魂角,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站智绸,受9級特大地震影響野揪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瞧栗,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一囱挑、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沼溜,春花似錦平挑、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至找都,卻和暖如春唇辨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背能耻。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工赏枚, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人晓猛。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓饿幅,卻偏偏與公主長得像,于是被迫代替她去往敵國和親戒职。 傳聞我的和親對象是個殘疾皇子栗恩,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容