最近在網上找到了一個學習 Android framework
源碼的地址,着實開心。因爲在虛擬機ubuntu
下載源碼實在是太難等了,而且自己也不是要移植系統開發學習,只是爲了學習裏面的代碼。所以這個地址真是太適合了。下來來介紹下Android
系統的啓動過程
Android ROM
想了解Android
系統的啓動過程,就不得不瞭解下ROM
包的組成,現在國內市場上很多ROM
包,小米,魅族,一加等等。那麼ROM
包都是由什麼構成的呢。這裏以紅米2A的某個版本解壓來看看,可以看到images
目錄如下圖
其中這裏麪包含了Android
很多的分區
- boot.img
boot分區,包括內核文件和虛擬內存盤Ramdisk
,負責手機開機,可在recovery
模式進行擦除,重新安裝帶有boot
分區的新系統
- system.img
system分區,包含Android
系統的用戶界面以及設置上的一些預裝系統應用
- recovery.img
recovery分區,替代啓動分區,執行恢復和維護系統的一些操作
- userdata.img
data分區,用於保存用戶的數據,例如聯繫人,短信,設置偏好和應用程序存放的地方
- cache.img
cache分區,用於放置系統頻繁訪問的數據和應用程序組件的分區
- misc
misc分區存放一些系統設置,包括USB
配置和某些硬件設置,如果損壞,一些設備功能將無法啓動
- persist.img
persist分區包含了設備的傳感器和信號部分的驅動程序,例如wifi,藍牙連接都有關係
- splash.img
開機畫面文件
- NON-HLOS.bin
是負責處理通訊協議相關的基帶鏡像
- 8916_msimage.mbn
平臺鏡像,包含一些必要的啓動分區和分區表,例如裏面的sbl1.mbn、tz.mbn、rpm.mbn
等等
- sbl1.mbn
硬件的初始化,並且保存加載其他模塊信息的順序
- tz.mbn
它和其他模塊代碼運行在相互隔離的區域,主要實現底層很多安全性特性
- rpm.mbn
負責資源電源管理
- emmc_appsboot.mbn
bootloader
文件,進入fastboot
模式相關文件
- gpt_backup0.bin
備份gpt
頭和分區表
- gpt_both0.bin
對應EMMC
的分區表
- gpt_main0.bin
GPT頭和分區表
- patch0.xml
服務端返回的具體磁盤大小打上最後一個分區的補丁、完成分區表頭校驗的配置文
- 其他都是一些燒錄程序的文件,如prog_emmc_firehose_8916.mbn 、rawprogram0.xml 、sec.bat
Android BootLoader
在Linux
軟件系統中,有一個叫引導加載程序的部分,它主要是由固化代碼程序和BootLoader
程序組成,其中固化程序已經燒入到了生產的芯片中,而BootLoader
程序通過它的啓動模式去引導系統CPU
和部分外設的初始化。爲把Linux
內核加載到RAM
內存中做準備。例如,在上文的ROM
中,系統首先運行的就是emmc_appsboot.mbn
文件中的bootloader
程序。詳細程序根據不同廠商芯片而不同,如要完全搞懂,得深入ARM
開發相關知識。
Linux kernel
待BootLoader
程序執行完後,標誌着CPU
和部分外設初始化完成,接下來要做的就是把Linux
內核加載到內存中,主要流程如下
說到Linux
內核,先來了解下Linux
內核的結構
SCI
供用戶空間調用的一些API
函數,API
函數的具體表現依賴於底部的體系結構PM
進程管理,接收SCI
創建的進程,然後實現進程之間的通信和同步管理MM
內存管理,通過內存頁的方式進行管理,主要管理緩存區的內存的分配VFS
虛擬文件系統,在內核所支持的文件系統和SCI
之間提供了一個交換層NS
網絡堆棧,主要是一些TCP/IP
和Socket
相關的網絡協議DD
設備驅動,驅動程序,驅動一些硬件設備的功能Arch
依賴體系結構的代碼
上文說的bootloader
程序執行完成之後,就會啓動Linux
內核,Linux
內核啓動調用的第一個函數就是start_kernel
,start_kernel
主要會執行
1. 調用setup_arch
初始化化一些硬件相關的體系結構依賴代碼
2. 調用paging_init()
初始化內核頁表
3. 調用mem_init()
函數初始化頁描述符
4. 調用trap_init()
和init_IRQ
初始化中斷向量表IDT
5. 調用kmem_cache_init()
和kmem_cache_sizes_init()
函數初始化slab
分配器
6. 調用time_init()
函數初始化系統日期和時間
7. 調用kernel_thread()
函數爲進程1創建內核線,同時執行init
程序
8. 調用fork_init()
函數初始化進程創建機制
9. 調用vfs_caches_init()
初始化虛擬文件系統
start_kernel
執行完後,接下來會進入rest_init
函數的執行
它會生成兩個線程kernel_init
和kthreadd
。其中kernel_init
也叫init
進程,主要是初始化和執行進程,kthreadd
是用來管理調度其他應用進程。rest_init
主要會去調用cpu_idle
函數,該函數有一個死循環,當有命令過來的時候則啓動執行,反之進入空閒狀態。
Android init
上文kernel_init
初始化之後,則會進入Android init
進程,執行init.c
裏面的main
函數。流程如下:
其中Android
的Main()
函數位於<Android源代碼本目錄>/system/core/init/
,在init.rc
它會去讀取init.rc
配置文件
// android-7.1.2_r36/init/init.cpp
//....
Parser& parser = Parser::GetInstance();
parser.AddSectionParser("service",std::make_unique<ServiceParser>());
parser.AddSectionParser("on", std::make_unique<ActionParser>());
parser.AddSectionParser("import", std::make_unique<ImportParser>());
parser.ParseConfig("/init.rc");
//....
init.rc
使用的是AIL
語言,代碼位於/system/core/rootdir/
,在init.rc
裏面會創建一個Zygote
進程
// android-7.1.2_r36/rootdir/init.rc
//....
on nonencrypted
# A/B update verifier that marks a successful boot.
exec - root cache -- /system/bin/update_verifier nonencrypted
class_start main
class_start late_start
//....
上面的class main
即爲創建Zygote
進程,創建具體代碼在rootdir/
目錄下的init.zygote64.rc
// android-7.1.2_r36/rootdir/init.zygote64.rc
service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
//...
service
AIL
語言語法,啓動一個系統程序zygote
啓動程序名稱,這裏指的是Zygote
進程/system/bin/app_process64
需要操作對象的路徑pathname
,這裏指的是/base/cmds/app_process/app_main.cpp
-Xzygote /system/bin
指定參數傳到/base/cmds/app_process/app_main.cpp
裏面--zygote --start-system-server
傳的具體參數值。這裏指的參數爲--zygote
和--start-system-server
Android app_main.cpp
上面傳的參數可以在main
函數裏面得到
// android-7.1.2_r36/cmds/app_process/app_main.cpp
//....
while (i < argc) {
const char* arg = argv[i++];
if (strcmp(arg, "--zygote") == 0) {
zygote = true;
niceName = ZYGOTE_NICE_NAME;
} else if (strcmp(arg, "--start-system-server") == 0) {
startSystemServer = true;
}
//....
}
//....
然後繼續往下
// android-7.1.2_r36/cmds/app_process/app_main.cpp
//....
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
}
//....
如果傳了--zygote
參數,則通過runtime
啓動ZygoteInit
,同時傳入相關的參數,反之啓動RuntimeInit
ZygoteInit
源碼位於framework/base/core/java/com/android/internal/os/ZygoteInit.java
RuntimeInit
源碼位於framework/base/core/java/com/android/internal/os/RuntimeInit.java
在上面的代碼中runtime
指的是在同文件定義的AppRuntime
,AppRuntime
繼承於AppRuntime
,Android
的虛擬機ART
,源代碼位於frameworks/base/core/jni/AndroidRuntime.cpp