Android N 的開機啟動流程概述
前言
做android開發已經好些年頭,一直對android系統的開機啟動流程一知半解。前前後後看了不少文章和原始碼,在這裡把自己的一些總結記錄下來,也算是加深自己的理解。
Android N 開機啟動流程概述
相信只要接觸過Android的人,都會看過下面這張圖:
圖片展示了Android的五層架構,從上到下依次是:應用層,應用框架層,庫層,執行時層以及Linux核心層。而Android的啟動流程是自下而上的,大體上分為三個階段:1. BootLoader引導;2. 啟動Kernel;3. 啟動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。