Android 系統的啓動過程

最近在網上找到了一個學習 Android framework 源碼的地址,着實開心。因爲在虛擬機ubuntu下載源碼實在是太難等了,而且自己也不是要移植系統開發學習,只是爲了學習裏面的代碼。所以這個地址真是太適合了。下來來介紹下Android系統的啓動過程

Android ROM

想了解Android系統的啓動過程,就不得不瞭解下ROM包的組成,現在國內市場上很多ROM包,小米,魅族,一加等等。那麼ROM包都是由什麼構成的呢。這裏以紅米2A的某個版本解壓來看看,可以看到images目錄如下圖

images.png

misc.png

其中這裏麪包含了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內核.png

說到Linux內核,先來了解下Linux內核的結構

Linux內核.png

  • SCI供用戶空間調用的一些API函數,API函數的具體表現依賴於底部的體系結構
  • PM 進程管理,接收SCI創建的進程,然後實現進程之間的通信和同步管理
  • MM 內存管理,通過內存頁的方式進行管理,主要管理緩存區的內存的分配
  • VFS 虛擬文件系統,在內核所支持的文件系統和SCI之間提供了一個交換層
  • NS 網絡堆棧,主要是一些TCP/IPSocket相關的網絡協議
  • 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_initkthreadd。其中kernel_init也叫init進程,主要是初始化和執行進程,kthreadd是用來管理調度其他應用進程。rest_init主要會去調用cpu_idle函數,該函數有一個死循環,當有命令過來的時候則啓動執行,反之進入空閒狀態。

Android init

上文kernel_init初始化之後,則會進入Android init進程,執行init.c裏面的main函數。流程如下:
流程.png

其中AndroidMain()函數位於<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指的是在同文件定義的AppRuntimeAppRuntime繼承於AppRuntimeAndroid的虛擬機ART,源代碼位於frameworks/base/core/jni/AndroidRuntime.cpp

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章