system和vendor分割槽掛載解析(Android O)
首先我們知道init程序在執行時會呼叫自身,所以init程序分為stage1和stage2兩個階段,而分割槽掛載操作也分為兩個階段:
stage1掛載操作是利用device tree中的配置項來讀取配置掛載的;stage2掛載操作則是我們常見的利用fstab配置檔案來掛載的。
在Android O之後的版本中,我們知道很多ko被從kernel中提取出來,移動到system分割槽和vendor分割槽中儲存。那麼系統啟動在服務載入之前首先需要把核心驅動模組全部載入起來才可以,所以我們的system分割槽和vendor分割槽必須要先掛載起來。
A/B system
我們知道使能了A/B system的系統,它的rootfs是整合到system.img中的,而kernel的執行必須要依賴rootfs,所以我們需要在很早就要把rootfs掛載起來,實際上UEFI在啟動kernel的時候會通過cmdline傳入引數告知rootfs所在分割槽,這樣kernel就能夠在一啟動就可以掛載rootfs,也就是我們的system分割槽。熟悉嵌入式的應該知道cmdline中有root引數,比如CONFIG_CMDLINE=”root=/dev/mtdblock2…”
而對於vendor分割槽,由於其中包含很多廠商自己的ko,所以需要在init的stage1進行掛載,那麼就需要在devicetree中進行掛載配置,init程序會去解析dtb中的相關資訊並掛載對應的分割槽。
rootfs在system.img中,實際上system會被掛載到/目錄上
system分割槽掛載資訊有uefi通過cmdline傳遞給kernel,由kernel掛載
vendor分割槽掛載資訊在dts中配置,並且有init stage1解析並掛載
Non A/B system
對於非A/B system的系統來說,rootfs是在boot.img中的,而決定rootfs在哪個分割槽,在android編譯系統中有如下巨集來決定的
BOARD_BUILD_SYSTEM_ROOT_IMAGE=false
如上所示,這樣配置的系統,將會吧ramdisk編譯到boot.img中。這樣uefi啟動時只需要傳入boot.img中的ramdisk作為rootfs即可啟動kernel。而對於其他非root分割槽的掛載則有init程序來完成。既然是init來完成,那麼就涉及到stage1和stage2兩個階段了。
對於system/vendor這兩個分割槽來說,由於其中包含有很多ko以及selinux配置,所以必須要在stage1完成掛載,然後才能進行後續的服務啟動。所以system/vendor的掛載配置需要在devicetree中進行配置。
rootfs在boot.img中
system分割槽掛載資訊在dts中配置,並且有init stage1解析並掛載
vendor分割槽掛載資訊在dts中配置,並且有init stage1解析並掛載
devicetree分割槽配置
一般來說,我們理解的devicetree中的配置都是給kernel使用的,但是這裡需要我們特別注意的是,devicetree中的分割槽配置並不是給kernel使用的,而是後續由init程序讀取掛載分割槽的。
fstab中的問題
device/qcom/sdm660/fstab_AB_variant.qcom:
#<src> <mnt_point> <type> <mnt_flags and options> <fs_mgr_flags>
/dev/block/bootdevice/by-name/system / ext4 ro,barrier=1,discard wait,slotselect,avb
由前文我們知道,在A/B system中,system掛載到根分割槽,是由UEFI傳入分割槽配置來掛載的,在non A/B system中,system掛載在/system是由devicetree來配置完成的,無論是否採用A/B system,都不可能在fstab中掛載system分割槽。那麼如上的配置專案為什麼還存在與fstab中呢?實際上,在init/fs_mgr的實現中,它會檢測並且過濾/目錄的掛載,所以上述配置中的第一行實際上是沒有起作用的。
備註:使能了A/B system的系統,rootfs都必須要放到system.img中,不管是哪個android版本。