征服Android面試官路漫漫(四):5 張圖帶你搞懂Android系統啟動的核心流程

南方吳彥祖_藍斯發表於2020-11-06

5張圖帶你搞懂Android系統啟動的核心流程~

大綱:

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

Android原始碼基於8.0。

init程式是Linux核心啟動完成後在使用者空間啟動的 第一個程式,主要負責 初始化工作啟動屬性 服務解析init.rc檔案並啟動Zygote程式

Zygote程式是一個 程式孵化器,負責 建立虛擬機器例項應用程式程式系統服務程式SystemServer。他透過fork(複製程式)的方式建立子程式,子程式能 繼承父程式的系統資源如常用類、註冊的JNI函式、主題資源、共享庫等。

由於Zygote程式啟動時會建立虛擬機器例項,由Zygote fork出的應用程式程式和SystemServer程式則可以在內部獲取到一個虛擬機器例項副本。

Zygote啟動

init程式會解析配置檔案init.rc,來啟動一些需要在開機時就啟動的系統程式,如Zygote程式、ServiceManager程式等。

init.rc是由Android初始化語言編寫的指令碼配置。由於Android 5.0開始支援了64bit程式,在init.rc裡改成了透過 ${ro.zygote}的值來引入Zygote相關的配置,

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

${ro.zygote}的取值有4種,在init.rc的同級目錄/system/core/rootdir下,可以看到4個Zygote相關的配置檔案,表示系統所支援程式的bit位數,

  1. init.zygote32.rc,Zygote程式的執行程式路徑為/system/bin/app_process
  2. init.zygote64.rc,Zygote程式的執行程式路徑為/system/bin/app_process64
  3. init.zygote32_64.rc,會啟動兩個Zygote程式,有兩個執行程式,32為主模式
  4. init.zygote64_32.rc,會啟動兩個Zygote程式,有兩個執行程式,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是執行程式的路徑,後面幾項則是傳給執行程式的引數,其中 --start-system-server表示在Zygote程式啟動後需要啟動SystemServer程式。

然後是最後一行, Zygote程式是使用socket來進行跨程式通訊的,所以會建立一個名為zygote的socket,660表示訪問許可權 rw-rw----,表示檔案擁有者和同一群組使用者具有讀寫許可權。

init程式啟動後,透過 fork和execve來啟動Zygote程式,

//system/core/init/service.cppbool Service::Start() {
    //fork出子程式
    pid = fork();
    if (pid == 0) {//子程式會返回0,父程式會返回子程式的pid
        //strs[0]是執行程式的路徑,即execve會執行app_process
        if (execve(strs[0], (char**) &strs[0], (char**) ENV) < 0) {
        }
    }}

執行執行程式app_process的入口函式main,

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

至此Zygote就正式啟動了。

征服Android面試官路漫漫(四):5 張圖帶你搞懂Android系統啟動的核心流程

綜上, init程式讀取配置檔案init.rc後,fork出Zygote程式,透過execve函式執行Zygote的執行程式app_process,進入ZygoteInit類的main函式

下面詳細分析app_main和ZygoteInit。

native層app_main

前邊可知app_main.cpp的main函式會呼叫runtime.start(),

//frameworks/base/core/jni/AndroidRuntime.cppvoid 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.javapublic static void main(String argv[]) {
    //是否要建立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引數,表示要建立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\. 建立服務端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來建立應用程式程式)
    zygoteServer.runSelectLoop(abiList);}

總結一下native層的3個環節和Java層的4個環節:

征服Android面試官路漫漫(四):5 張圖帶你搞懂Android系統啟動的核心流程

SystemServer啟動

SystemServer程式主要負責 建立啟動系統服務如AMS、WMS和PMS等

從前邊可知SystemServer程式由Zygote程式fork出來並啟動,在ZygoteInit類中,

//ZygoteInit.javaprivate static boolean startSystemServer(...){
    String args[] = {
        //...
        //啟動的類名:
        "com.android.server.SystemServer",
    };
    //fork程式,由native層實現
    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函式,然後執行
    RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);}

這裡啟動了binder執行緒池, SystemServer程式就可以用binder機制來跨程式通訊了(Zygote程式是用socket來通訊的),接著進入了SystemServer的main函式,

//SystemServer.javapublic static void main(String[] args) {
    new SystemServer().run();}private void run() {
    //建立looper
    Looper.prepareMainLooper();
    //載入動態庫libandroid_servers.so
    System.loadLibrary("android_servers");
    //建立系統上下文
    createSystemContext();
    //建立SSM,用於服務的建立、啟動和生命週期管理
    mSystemServiceManager = new SystemServiceManager(mSystemContext);
    //服務根據優先順序被分成3批來啟動:
    //啟動引導服務,如AMS、PMS等
    startBootstrapServices();
    //啟動核心服務
    startCoreServices();
    //啟動其他服務
    startOtherServices();
    //開啟looper迴圈
    Looper.loop();}

看下AMS的啟動,

//SystemServer.javaprivate void startBootstrapServices() {
    //由SSM建立啟動
    mActivityManagerService = mSystemServiceManager.startService(
        ActivityManagerService.Lifecycle.class).getService();
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);}private void startOtherServices() {
    //AMS準備就緒
    mActivityManagerService.systemReady(...);}

總結一下,SystemServer程式被建立後,主要做了3件事情: 啟動binder執行緒池、建立SystemServiceManager(SSM)、用SSM啟動各種服務

征服Android面試官路漫漫(四):5 張圖帶你搞懂Android系統啟動的核心流程

Launcher的啟動

Launcher作為Android的桌面,用於 管理應用圖示和桌面元件

前邊可知SystemServer程式會啟動各種服務,其中PackageManagerService啟動後會將系統中的應用程式安裝完成,然後由AMS來啟動Launcher。

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

跟進ActivityManagerService,

//ActivityManagerService.javapublic void systemReady(...) {
    //經過層層呼叫來到startHomeActivityLocked}boolean startHomeActivityLocked(...) {
    //最終會啟動Launcher應用的Activity
    mActivityStarter.startHomeActivityLocked(...);}

Activity類是Launcher.java,剩下的流程就是載入已安裝的應用程式資訊,然後展示,就不具體分析了。

征服Android面試官路漫漫(四):5 張圖帶你搞懂Android系統啟動的核心流程

總結

Android系統啟動的核心流程如下:

  1. Linux核心啟動
  2. init程式啟動
  3. init程式fork出Zygote程式
  4. Zygote程式fork出SystemServer程式
  5. SystemServer程式啟動各項服務(PMS、AMS等)
  6. AMS服務啟動Launcher桌面
征服Android面試官路漫漫(四):5 張圖帶你搞懂Android系統啟動的核心流程

Zygote程式啟動好服務端socket後,便會等待AMS的socket請求,來建立應用程式程式。

細節補充

  • Zygote的跨程式通訊沒有使用binder,而是socket,所以應用程式程式的binder機制不是繼承而來,而是程式建立後自己啟動的。
  • Zygote跨程式通訊之所以用socket而不是binder,是因為binder通訊是多執行緒的,而Zygote需要在單執行緒狀態下fork子程式來避免死鎖問題。
  • PMS、AMS等系統服務啟動後會呼叫ServiceManager.addService()註冊,然後執行在自己的工作執行緒。

如何進階Android?

有些東西你不僅要懂,而且要能夠很好地表達出來,能夠讓面試官認可你的理解,例如Handler機制,這個是面試必問之題。有些晦澀的點,或許它只活在面試當中,實際工作當中你壓根不會用到它,但是你要知道它是什麼東西。

對於程式設計師來說,要學習的知識內容、技術有太多太多,要想不被環境淘汰就只有不斷提升自己, 從來都是我們去適應環境,而不是環境來適應我們!

最後我在這裡分享一下這段時間從朋友,大佬那裡收集到的一些 2019-2020BAT 面試真題解析,裡面內容很多也很系統,包含了很多內容: Android 基礎、Java 基礎、Android 原始碼相關分析、常見的一些原理性問題等等,可以很好地幫助我們深刻理解Android相關知識點的原理以及面試相關知識。

1、確定好方向,梳理成長路線圖

不用多說,相信大家都有一個共識:無論什麼行業,最牛逼的人肯定是站在金字塔端的人。所以,想做一個牛逼的程式設計師,那麼就要讓自己站的更高,成為技術大牛並不是一朝一夕的事情,需要時間的沉澱和技術的積累。

關於這一點,在我當時確立好Android方向時,就已經開始梳理自己的成長路線了,包括技術要怎麼系統地去學習,都列得非常詳細。

征服Android面試官路漫漫(四):5 張圖帶你搞懂Android系統啟動的核心流程

知識梳理完之後,就需要進行查漏補缺,所以針對這些知識點,我手頭上也準備了不少的電子書和筆記,這些筆記將各個知識點進行了完美的總結。

2、透過原始碼來系統性地學習

只要是程式設計師,不管是Java還是Android,如果不去閱讀原始碼,只看API文件,那就只是停留於皮毛,這對我們知識體系的建立和完備以及實戰技術的提升都是不利的。

真正最能鍛鍊能力的便是直接去閱讀原始碼,不僅限於閱讀各大系統原始碼,還包括各種優秀的開源庫。

征服Android面試官路漫漫(四):5 張圖帶你搞懂Android系統啟動的核心流程
《486頁超全面Android開發相關原始碼精編解析》

3、閱讀前輩的一些技術筆記

征服Android面試官路漫漫(四):5 張圖帶你搞懂Android系統啟動的核心流程
《960全網最全Android開發筆記》

4、刷題備戰,直通大廠

歷時半年,我們整理了這份市面上最全面的安卓面試題解析大全
包含了騰訊、百度、小米、阿里、樂視、美團、58、360、新浪、搜狐等一線網際網路公司面試被問到的題目。熟悉本文中列出的知識點會大大增加透過前兩輪技術面試的機率。

如何使用它?

1.可以透過目錄索引直接翻看需要的知識點,查漏補缺。
2.五角星數表示面試問到的頻率,代表重要推薦指數

征服Android面試官路漫漫(四):5 張圖帶你搞懂Android系統啟動的核心流程
《379頁Android開發面試寶典》

以上內容均放在了開源專案: github  中已收錄,大家可以自行獲取。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69983917/viewspace-2732717/,如需轉載,請註明出處,否則將追究法律責任。

相關文章