Android系統啟動過程學習
使用 android 手機已經長時間了,同時,從大學學習 android 開發開始,也進行過多款 android app 專案的開發,但是對 android 內部的啟動過程,即當我們從按下電源鍵開機開始, android 系統內部是如何執行的,由於android 系統的核心使用的是 linux 核心,那麼在啟動過程中,android 系統和桌面Linux系統的啟動過程是否是一樣的?我們在之前的一篇部落格中,曾學習過Linux核心的啟動過程,在這裡,我們學習一下android系統的啟動過程,並從大體程式碼上講解其啟動過程。
啟動步驟
在android系統的啟動過程中,大體可以分為以下幾個步驟:
android啟動過程分析
第一步 啟動電源以及啟動系統
當電源按下的時候,會引導固化在晶片中的程式碼從預定義的位置開始啟動,並載入載入程式到記憶體,即RAM中,然後執行。
第二步 載入程式執行
載入程式,英文名稱為Boot Loader,顧名思義,其為啟動載入器,其主要作用是引導android系統核心的啟動。載入程式是執行的第一個程式。其主要作用是在引導核心啟動之前,檢測相關硬體以及外部的RAM,設定網路,記憶體等,並根據相關引數或輸入資料設定核心。
Boot Loader載入程式可以在\bootable\bootloader\legacy\usbloader
中找到,一般的載入器包含著兩個重要的檔案:
- init.S初始化堆疊,清空BBS棧,呼叫main.c的_main()函式
- main.c初始化硬體(鬧鐘,主機板,鍵盤,控制檯),建立Linux標籤
第三步 核心執行
當載入程式引導核心啟動之後,android的核心執行和linux的核心執行相似。核心啟動的時候,設定快取,被保護的儲存器,計劃列表,載入驅動。當核心完成系統設定之後,便找到系統檔案中”init”檔案,然後啟動系統的第一個程序。
第四步 init執行
init程序是android系統執行的第一個程序,也就是說所有的android程序都是直接或間接的被init程序建立的。在init程序執行過程中,主要負責兩個事情,一個是掛載系統目錄,像/dev
/proc
,/sys
等,另外一件事情是執行init.rc
檔案。
init
位於/system/core/init
目錄中。init.rc
位於/system/core/rootdir
目錄中。- 在
/system/core/init/readme.txt
檔案中可以學習.rc
檔案的相關語法,我們將在下面的部落格中學習該語法。
總體來說,在init.rc
檔案中,主要是啟動相關程序和服務,同時設定相關引數和掛載相關目錄。
我們先來看一下init
中的相關程式碼:
int main(int argc, char **argv)
{
//.....
#ifndef NO_DEVFS_SETUP
mkdir("/dev", 0755);
mkdir("/proc", 0755);
mkdir("/sys", 0755);
mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
mkdir("/dev/pts", 0755);
mkdir("/dev/socket", 0755);
mount("devpts", "/dev/pts", "devpts", 0, NULL);
mount("proc", "/proc", "proc", 0, NULL);
mount("sysfs", "/sys", "sysfs", 0, NULL);
close(open("/dev/.booting", O_WRONLY | O_CREAT, 0000));
open_devnull_stdio();
klog_init();
#endif
property_init();
//.......
is_charger = !strcmp(bootmode, "charger");
INFO("property init\n");
if (!is_charger)
property_load_boot_defaults();
INFO("reading config file\n");
if (!charging_mode_booting())
init_parse_config_file("/init.rc");
else
init_parse_config_file("/lpm.rc");
/* Check for an emmc initialisation file and read if present */
if (emmc_boot && access("/init.emmc.rc", R_OK) == 0) {
INFO("Reading emmc config file");
init_parse_config_file("/init.emmc.rc");
}
/* Check for a target specific initialisation file and read if present */
if (access("/init.target.rc", R_OK) == 0) {
INFO("Reading target specific config file");
init_parse_config_file("/init.target.rc");
}
//.......
在這些事情處理完成之後,在init.rc
中便會啟動zygote程序。
service zygote /system/bin/app_process -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
第五步 zygote程序
在java中不同的虛擬機器例項會為不同的應用分配不同的記憶體。假如android應用應該儘可能快的啟動,但如果android系統為每一個應用啟動不同的Dalvik虛擬機器例項,就會消耗大量的記憶體以及時間。因此為了解決這個問題,Android系統創造了Zygote。Zygote讓Dalvik虛擬機器共享程式碼,低記憶體佔用以及最小的啟動時間成為可能。Zygote是一個虛擬機器程序,正如我們在前一個步驟所說的在系統引導的時候啟動。Zygote預載入以及初始化核心庫類。
Zygote載入程序:
public static void main(String argv[]) {
try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
registerZygoteSocket();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean up after startup
gcAndFinalize();
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
Trace.setTracingEnabled(false);
// If requested, start system server directly from Zygote
if (argv.length != 2) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
if (argv[1].equals("start-system-server")) {
startSystemServer(); //啟動系統服務
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
Log.i(TAG, "Accepting command socket connections");
runSelectLoop();
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
- 載入
ZygoteInit
類,程式碼位於/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
中。 registerZygoteSocket()
為zygote命令連線註冊一個伺服器套接字。preload()
預載入類,資原始檔以及OpenGL。
第六步 系統服務或服務
在Zygote完成相應的初始化之後,開始申請啟動系統服務,系統服務是android系統中供上層執行的基礎。系統服務同時使用native以及java編寫,系統服務可以認為是一個程序。同一個系統服務在Android SDK可以讓System Services形式獲得。
核心服務:
- 啟動電源管理器;
- 建立Activity管理器;
- 啟動電話註冊;
- 啟動包管理器;
- 設定Activity管理服務為系統程序;
- 啟動上下文管理器;
- 啟動系統Context Providers;
- 啟動電池服務;
- 啟動定時管理器;
- 啟動感測服務;
- 啟動視窗管理器;
- 啟動藍芽服務;
- 啟動掛載服務。
其他服務:
- 啟動狀態列服務;
- 啟動硬體服務;
- 啟動網路狀態服務;
- 啟動網路連線服務;
- 啟動通知管理器;
- 啟動裝置儲存監視服務;
- 啟動定位管理器;
- 啟動搜尋服務;
- 啟動剪下板服務;
- 啟動登記服務;
- 啟動桌布服務;
- 啟動音訊服務;
- 啟動耳機監聽;
- 啟動AdbSettingsObserver(處理adb命令)。
第七步 引導完成
一單系統服務啟動,android系統的引導過程就完成了。此時,”ACTION_BOOT_COMPLETE”開機啟動廣播就發出去了。