1. 程式人生 > >Android N 的開機啟動流程概述

Android N 的開機啟動流程概述

前言

做android開發已經好些年頭,一直對android系統的開機啟動流程一知半解。前前後後看了不少文章和原始碼,在這裡把自己的一些總結記錄下來,也算是加深自己的理解。

Android N 開機啟動流程概述

相信只要接觸過Android的人,都會看過下面這張圖:



Android層次架構圖

圖片展示了Android的五層架構,從上到下依次是:應用層,應用框架層,庫層,執行時層以及Linux核心層。而Android的啟動流程是自下而上的,大體上分為三個階段:1. BootLoader引導;2. 啟動Kernel;3. 啟動Android。如果再細化一點,則如下圖所示:


這裡寫圖片描述

Android的啟動流程圖

 Android的啟動過程可以分為兩個階段,第一階段是Linux的啟動,第二階段才是Android的啟動。上圖中1、2、3是linux啟動的過程,從4開始就是android啟動的過程。
 下面我詳細描述一下過程:

Step 1. Boot Rom
 當按開機鍵的時候,引導晶片開始從固化在ROM的預設程式碼開始執行,然後載入載入程式到RAM。

Step 2. Bootloader
 BootLoader,又稱為載入程式。它是在作業系統執行之前執行的一段程式,是執行的第一個程式。主要有檢查RAM,初始化硬體引數等功能,當然它的最終目的是把作業系統給拉起來。

 檔案路徑/bootable/bootloader/legacy/

 BootLoader的主要功能分析,我摘抄過來,一起看看:

其實Bootloader主要的必須的作用只有一個:就是把作業系統映像檔案拷貝到RAM中去,然後跳轉到它的入口處去執行,我們稱之為啟動載入模式,該過程沒有使用者的介入,是它正常工作的模式。它的步驟如下:

Stage1:

硬體裝置初始化。為stage2的執行及隨後核心的執行準備好基本的硬體環境

為載入stage2 準備ram空間。為了獲得更好的執行速度,通常吧stage2載入到ram中執行

複製stage2的程式碼到ram中

設定好堆疊

跳轉到stage2的c程式入口

Stage2:

初始化本階段要使用的硬體裝置

檢測系統記憶體對映

將核心映像和根檔案系統映像從flash讀到ram中

為核心設定啟動引數

呼叫核心

 簡單的說,Bootloader負責初始化軟體執行所需要的最小硬體環境,最後載入核心到記憶體。

Step 3. 初始化Kernel
 接著就進入C語言編寫的結構無關的程式碼了。這個入口的函式是start_kernel函式。start_kernel 函式完成了核心的大部分初始化工作。實際上,可以將start_kernel 函式看做核心的main函式。start_kernel函式執行到最後呼叫了reset_init函式進行後續的初始化。 reset_init函式最主要的任務就是啟動核心執行緒kernel_init。kernel_init函式將完成裝置驅動程式的初始化,並呼叫init_post函式啟動使用者空間的init程序。到init_post函式為止,核心的初始化已經基本完成。

檔案路徑:/kernel_imx/init/main.c

簡單的說,核心載入進記憶體後,將首先進入核心引導階段,在核心引導階段的最後,呼叫start_kernel進入核心啟動階段,主要是完成核心的大部分初始化工作。start_kernel會最終啟動使用者空間的init程序。

Step 4. init程序
 當初始化核心之後,就會啟動一個相當重要的祖先程序,也就是init程序,在Linux中所有的程序都是由init程序直接或間接fork出來的。init程序負責建立系統中最關鍵的幾個核心daemon(守護)程序,尤其是zygote和servicemanager。前者是android啟動的第一個dalvik 虛擬機器,它將負責啟動Java世界的程序;後者是BInder通訊的基礎。另外,它還提供了property service(屬性服務),類似於windows系統的登錄檔服務。

 在Android系統中,會有個init.rc指令碼。init程序一啟動就會讀取並解析這個指令碼檔案,把其中的元素整理成自己的資料結構(連結串列)。

 換句話說, init程序負責解析init.rc配置檔案,開啟系統守護程序。兩個最重要的守護程序是zygote程序和servicemanager,zygote是Android啟動的第一個Dalvik虛擬機器,servicemanager是Binder通訊的基礎。

檔案路徑: /system/core/init/init.c
/system/core/rootdir/init.rc
/system/core/init/readme.txt

Step 5. Zygote程序
 當init程序建立之後,會fork出一個Zygote程序,這個程序是所有Java程序的父程序。我們知道,Linux是基於C的,而Android是基於Java的(當然底層也是C)。所以這裡就會fork出一個Zygote Java程序用來fork出其他的程序。在zygote開啟的時候,會呼叫ZygoteInit.main()進行初始化。下面我們看一段ZygoteInit.main()原始碼:

    public static void main(String argv[]) {
        // Mark zygote start. This ensures that thread creation will throw
        // an error.
        ZygoteHooks.startZygoteNoThreadCreation();

        try {
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
            RuntimeInit.enableDdms();
            // Start profiling the zygote initialization.
            SamplingProfilerIntegration.start();
// 載入zygote的時候,會傳入引數,startSystemServer變為true
            boolean startSystemServer = false;
            String socketName = "zygote";
            String abiList = null;
            for (int i = 1; i < argv.length; i++) {
                if ("start-system-server".equals(argv[i])) {
                    startSystemServer = true;
                } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                    abiList = argv[i].substring(ABI_LIST_ARG.length());
                } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                    socketName = argv[i].substring(SOCKET_NAME_ARG.length());
                } else {
                    throw new RuntimeException("Unknown command line argument: " + argv[i]);
                }
            }

            if (abiList == null) {
                throw new RuntimeException("No ABI list supplied.");
            }

            registerZygoteSocket(socketName);
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                SystemClock.uptimeMillis());
            preload();
            EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                SystemClock.uptimeMillis());
            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);

            // Finish profiling the zygote initialization.
            SamplingProfilerIntegration.writeZygoteSnapshot();

            // Do an initial gc to clean up after startup
            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");
            gcAndFinalize();
            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);

            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);

            // Disable tracing so that forked processes do not inherit stale tracing tags from
            // Zygote.
            Trace.setTracingEnabled(false);

            // Zygote process unmounts root storage spaces.
            Zygote.nativeUnmountStorageOnInit();

            ZygoteHooks.stopZygoteNoThreadCreation();
// 啟動SystemServer程序
            if (startSystemServer) {
                startSystemServer(abiList, socketName);
            }

            Log.i(TAG, "Accepting command socket connections");
            runSelectLoop(abiList);

            closeServerSocket();
        } catch (MethodAndArgsCaller caller) {
            caller.run();
        } catch (Throwable ex) {
            Log.e(TAG, "Zygote died with exception", ex);
            closeServerSocket();
            throw ex;
        }
    }

檔案路徑:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java

從程式碼中可以看出,zygote虛擬機器啟動子程序system_server,同時也可以看出zygote中定義了一個Socket,用於接收ActivityManagerService啟動應用程式的請求。

Step 6. SystemServer程序
 前面ZygoteInit.java裡面通過startSystemServer() fork出了SystemServer程序,這個程序在整個的Android中非常重要,它和Zygote程序一樣,是Android Framework層的兩大重要程序。系統裡面重要的服務都是在這個程序裡面開啟的,例如AMS, WindowsManager, PackageManagerService等等都是由這個SystemServer fork出來的。在下面SystemServer 的程式碼中可以看到,這些服務如何開啟和具體開啟了哪些服務。

檔案路徑:/frameworks/base/services/java/com/android/server/SystemServer.java

 從SystemServer.java檔案程式碼中可以看出,在SystemServer程序開啟的時候,就會初始化ActivityManagerService 。同時,會載入本地系統的服務庫,呼叫createSystemContext()建立系統上下文,建立ActivityThread及開啟各種服務等等。
 也就是說在system_server中開啟了核心系統服務,並將系統服務新增到ServiceManager中,然後系統進入SystemReady狀態。

Step 7. Home Activity

 上面ActivityManagerService 開啟之後,會呼叫finishBooting() ,完成引導過程,同時傳送開機廣播。

檔案路徑:/frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

 之後就會啟動Home程式,完成系統介面的載入與顯示。

其實這一步遠比上面所說的複雜,具體步驟是:

1、在systemReady狀態,ActivityManagerService會與zygote的Socket通訊,請求啟動Home。
2、zygote收到AMS的連線請求後,執行runSelectLoopMode處理請求。
3、zygote處理請求會通過forkAndSpecialize啟動新的應用程序,並最終啟動Home。

Android的開機啟動流程就完成了。

總結一下整個開機啟動流程:

Step1 系統加電,執行bootloader。Bootloader負責初始化軟體執行所需要的最小硬體環境,最後載入核心到記憶體。
Step2 核心載入進記憶體後,將首先進入核心引導階段,在核心引導階段的最後,呼叫start_kernel進入核心啟動階段。start_kernel最終啟動使用者空間的init程式。
Step3 init程式負責解析init.rc配置檔案,開啟系統守護程序。兩個最重要的守護程序是zygote程序和ServiceManager,zygote是Android啟動的第一個Dalvik虛擬機器,ServiceManager是Binder通訊的基礎。
Step4 zygote虛擬機器啟動子程序system_server,在system_server中開啟了核心系統服務,並將系統服務新增到ServiceManager中,然後系統進入SystemReady狀態。
Step5 在SystemReady狀態,ActivityManagerService與zygote中的socket通訊,通過zygote啟動home應用,進入系統桌面。

從Step3開始,init啟動後,上層的實現。

Step1 init啟動的核心Daemon服務包括Android的第一個Dalvik虛擬機器zygote。
Step2 zygote定義一個socket,用於接受ActivityManagerService啟動應用的請求。
Step3 zygote通過fork系統呼叫建立system_server程序
Step4 在system_server程序中,將會啟動系統核心服務以及其他服務。
Step5 系統服務啟動後會註冊到ServiceManager中,用於Binder通訊。
Step6 ActivityManagerService進入systemReady狀態。
Step7 在systemReady狀態,ActivityManagerService會與zygote的Socket通訊,請求啟動Home。
Step8 zygote收到AMS的連線請求後,執行runSelectLoopMode處理請求。
Step9 zygote處理請求會通過forkAndSpecialize啟動新的應用程序,並最終啟動Home。