圖解 | Android系統(tǒng)的啟動

5張圖搞懂Android系統(tǒng)啟動的核心流程~

大綱:

  • Zygote啟動
  • SystemServer啟動
  • Launcher啟動
  • 總結
  • 細節(jié)補充
  • 參考資料

本文約1.9k字,閱讀大約8分鐘庐镐。

Android源碼基于8.0莫湘。

init進程是Linux內核啟動完成后在用戶空間啟動的第一個進程,主要負責初始化工作粗合、啟動屬性服務萍嬉、解析init.rc文件并啟動Zygote進程

Zygote進程是一個進程孵化器隙疚,負責創(chuàng)建虛擬機實例壤追、應用程序進程系統(tǒng)服務進程SystemServer供屉。他通過fork(復制進程)的方式創(chuàng)建子進程行冰,子進程能繼承父進程的系統(tǒng)資源如常用類溺蕉、注冊的JNI函數、主題資源悼做、共享庫等疯特。

由于Zygote進程啟動時會創(chuàng)建虛擬機實例,由Zygote fork出的應用程序進程和SystemServer進程則可以在內部獲取到一個虛擬機實例副本肛走。

Zygote啟動

init進程會解析配置文件init.rc漓雅,來啟動一些需要在開機時就啟動的系統(tǒng)進程,如Zygote進程朽色、ServiceManager進程等邻吞。

init.rc是由Android初始化語言編寫的腳本配置。由于Android 5.0開始支持了64bit程序葫男,在init.rc里改成了通過${ro.zygote}的值來引入Zygote相關的配置抱冷,

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

${ro.zygote}的取值有4種,在init.rc的同級目錄/system/core/rootdir下梢褐,可以看到4個Zygote相關的配置文件旺遮,表示系統(tǒng)所支持程序的bit位數,

  1. init.zygote32.rc利职,Zygote進程的執(zhí)行程序路徑為/system/bin/app_process
  2. init.zygote64.rc趣效,Zygote進程的執(zhí)行程序路徑為/system/bin/app_process64
  3. init.zygote32_64.rc,會啟動兩個Zygote進程猪贪,有兩個執(zhí)行程序跷敬,32為主模式
  4. init.zygote64_32.rc,會啟動兩個Zygote進程热押,有兩個執(zhí)行程序西傀,64為主模式

我們看到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
    ...

第一行中桶癣,service表示Zygote進程以服務的形式來啟動拥褂,zygote則是進程的名字,/system/bin/app_process是執(zhí)行程序的路徑牙寞,后面幾項則是傳給執(zhí)行程序的參數扫步,其中--start-system-server表示在Zygote進程啟動后需要啟動SystemServer進程。

然后是最后一行幸缕,Zygote進程是使用socket來進行跨進程通信的涵亏,所以會創(chuàng)建一個名為zygote的socket,660表示訪問權限rw-rw----惹挟,表示文件擁有者和同一群組用戶具有讀寫權限茄螃。

init進程啟動后,通過fork和execve來啟動Zygote進程连锯,

//system/core/init/service.cpp
bool Service::Start() {
    //fork出子進程
    pid = fork();
    if (pid == 0) {//子進程會返回0归苍,父進程會返回子進程的pid
        //strs[0]是執(zhí)行程序的路徑用狱,即execve會運行app_process
        if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
        }
    }
}

運行執(zhí)行程序app_process的入口函數main,

//frameworks/base/cmds/app_process/app_main.cpp
int main(int argc, char* const argv[]){
    if (zygote) {
        //啟動Zygote拼弃,進入ZygoteInit.main函數
        runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    }
}

至此Zygote就正式啟動了夏伊。

image

綜上,init進程讀取配置文件init.rc后肴敛,fork出Zygote進程署海,通過execve函數執(zhí)行Zygote的執(zhí)行程序app_process,進入ZygoteInit類的main函數医男。

下面詳細分析app_main和ZygoteInit砸狞。

native層app_main

前邊可知app_main.cpp的main函數會調用runtime.start(),

//frameworks/base/core/jni/AndroidRuntime.cpp
void AndroidRuntime::start(...){
    //1. 啟動java虛擬機
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
    //2. 為java虛擬機注冊JNI方法
    if (startReg(env) < 0) {
        return;
    }
    //根據傳入的參數找到ZygoteInit類和他的main函數
    //3. 通過JNI調用ZygoteInit的main函數
    env->CallStaticVoidMethod(startClass, startMeth, strArray);
}

Java層ZygoteInit

來到ZygoteInit的main函數镀梭,

//ZygoteInit.java
public static void main(String argv[]) {
    //是否要創(chuàng)建SystemServer
    boolean startSystemServer = false;
    //默認的socket名字
    String socketName = "zygote";
    //是否要延遲資源的預加載
    boolean enableLazyPreload = false;

    for (int i = 1; i < argv.length; i++) {
        if ("start-system-server".equals(argv[i])) {
            //在init.rc文件中刀森,有--start-system-server參數,表示要創(chuàng)建SystemServer
            startSystemServer = true;
        } else if ("--enable-lazy-preload".equals(argv[i])) {
            //init.rc沒有這個參數报账,資源的預加載不會被延遲
            enableLazyPreload = true;
        } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
            //init.rc可以通過--socket-name=指定socket名字來覆蓋默認值
            socketName = argv[i].substring(SOCKET_NAME_ARG.length());
        }
    }

    //1. 創(chuàng)建服務端socket研底,名字為socketName即zygote
    zygoteServer.registerServerSocket(socketName);

    if (!enableLazyPreload) {
        //2. 沒有被延遲,就預加載資源
        preload(bootTimingsTraceLog);
    }

    if (startSystemServer) {
        //3. fork并啟動SystemServer進程
        startSystemServer(abiList, socketName, zygoteServer);
    }

    //4. 等待AMS請求(AMS會通過socket請求Zygote來創(chuàng)建應用程序進程)
    zygoteServer.runSelectLoop(abiList);
}

總結一下native層的3個環(huán)節(jié)和Java層的4個環(huán)節(jié):

image

SystemServer啟動

SystemServer進程主要負責創(chuàng)建啟動系統(tǒng)服務如AMS透罢、WMS和PMS等榜晦。

從前邊可知SystemServer進程由Zygote進程fork出來并啟動,在ZygoteInit類中羽圃,

//ZygoteInit.java
private static boolean startSystemServer(...){
    String args[] = {
        //...
        //啟動的類名:
        "com.android.server.SystemServer",
    };
    //fork進程乾胶,由native層實現(xiàn)
    pid = Zygote.forkSystemServer();
    //處理SystemServer進程
    handleSystemServerProcess(parsedArgs);
}

private static void handleSystemServerProcess(...){
    ZygoteInit.zygoteInit(...);
}

public static final void zygoteInit(...){
    //啟動binder線程池
    ZygoteInit.nativeZygoteInit();
    //內部經過層層調用,找到"com.android.server.SystemServer"類和他的main函數朽寞,然后執(zhí)行
    RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}

這里啟動了binder線程池识窿,SystemServer進程就可以用binder機制來跨進程通信了(Zygote進程是用socket來通信的),接著進入了SystemServer的main函數脑融,

//SystemServer.java
public static void main(String[] args) {
    new SystemServer().run();
}

private void run() {
    //創(chuàng)建looper
    Looper.prepareMainLooper();
    //加載動態(tài)庫libandroid_servers.so
    System.loadLibrary("android_servers");
    //創(chuàng)建系統(tǒng)上下文
    createSystemContext();

    //創(chuàng)建SSM喻频,用于服務的創(chuàng)建、啟動和生命周期管理
    mSystemServiceManager = new SystemServiceManager(mSystemContext);
    
    //服務根據優(yōu)先級被分成3批來啟動:
    //啟動引導服務肘迎,如AMS甥温、PMS等
    startBootstrapServices();
    //啟動核心服務
    startCoreServices();
    //啟動其他服務
    startOtherServices();

    //開啟looper循環(huán)
    Looper.loop();
}

看下AMS的啟動,

//SystemServer.java
private void startBootstrapServices() {
    //由SSM創(chuàng)建啟動
    mActivityManagerService = mSystemServiceManager.startService(
        ActivityManagerService.Lifecycle.class).getService();
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
}

private void startOtherServices() {
    //AMS準備就緒
    mActivityManagerService.systemReady(...);
}

總結一下妓布,SystemServer進程被創(chuàng)建后窿侈,主要做了3件事情:啟動binder線程池、創(chuàng)建SystemServiceManager(SSM)秋茫、用SSM啟動各種服務

image

Launcher的啟動

Launcher作為Android的桌面乃秀,用于管理應用圖標和桌面組件肛著。

前邊可知SystemServer進程會啟動各種服務圆兵,其中PackageManagerService啟動后會將系統(tǒng)中的應用程序安裝完成,然后由AMS來啟動Launcher枢贿。

//SystemServer.java
private void startOtherServices() {
    //AMS準備就緒
    mActivityManagerService.systemReady(...);
}

跟進ActivityManagerService殉农,

//ActivityManagerService.java
public void systemReady(...) {
    //經過層層調用來到startHomeActivityLocked
}

boolean startHomeActivityLocked(...) {
    //最終會啟動Launcher應用的Activity
    mActivityStarter.startHomeActivityLocked(...);
}

Activity類是Launcher.java,剩下的流程就是加載已安裝的應用程序信息局荚,然后展示超凳,就不具體分析了。

image

總結

Android系統(tǒng)啟動的核心流程如下:

  1. Linux內核啟動
  2. init進程啟動
  3. init進程fork出Zygote進程
  4. Zygote進程fork出SystemServer進程
  5. SystemServer進程啟動各項服務(PMS耀态、AMS等)
  6. AMS服務啟動Launcher桌面
image

Zygote進程啟動好服務端socket后轮傍,便會等待AMS的socket請求,來創(chuàng)建應用程序進程首装。

細節(jié)補充

  • Zygote的跨進程通信沒有使用binder创夜,而是socket,所以應用程序進程的binder機制不是繼承而來仙逻,而是進程創(chuàng)建后自己啟動的驰吓。
  • Zygote跨進程通信之所以用socket而不是binder,是因為binder通信是多線程的系奉,而Zygote需要在單線程狀態(tài)下fork子進程來避免死鎖問題檬贰。
  • PMS、AMS等系統(tǒng)服務啟動后會調用ServiceManager.addService()注冊缺亮,然后運行在自己的工作線程翁涤。

參考資料


更多性感文章,關注原創(chuàng)技術公眾號:哈利迪ei

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末瞬内,一起剝皮案震驚了整個濱河市迷雪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌虫蝶,老刑警劉巖章咧,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異能真,居然都是意外死亡赁严,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門粉铐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來疼约,“玉大人,你說我怎么就攤上這事蝙泼〕贪” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵汤踏,是天一觀的道長织鲸。 經常有香客問我舔腾,道長,這世上最難降的妖魔是什么搂擦? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任稳诚,我火速辦了婚禮,結果婚禮上瀑踢,老公的妹妹穿的比我還像新娘扳还。我一直安慰自己,他們只是感情好橱夭,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布氨距。 她就那樣靜靜地躺著,像睡著了一般徘钥。 火紅的嫁衣襯著肌膚如雪衔蹲。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天呈础,我揣著相機與錄音舆驶,去河邊找鬼。 笑死而钞,一個胖子當著我的面吹牛沙廉,可吹牛的內容都是我干的。 我是一名探鬼主播臼节,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼撬陵,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了网缝?” 一聲冷哼從身側響起巨税,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎粉臊,沒想到半個月后草添,有當地人在樹林里發(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡扼仲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年远寸,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屠凶。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡驰后,死狀恐怖,靈堂內的尸體忽然破棺而出矗愧,到底是詐尸還是另有隱情灶芝,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站监署,受9級特大地震影響颤专,放射性物質發(fā)生泄漏。R本人自食惡果不足惜钠乏,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望春塌。 院中可真熱鬧晓避,春花似錦、人聲如沸只壳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吼句。三九已至锅必,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間惕艳,已是汗流浹背搞隐。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留远搪,地道東北人劣纲。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像谁鳍,于是被迫代替她去往敵國和親癞季。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348