分區版面配置

在 Android 10 中,根目錄檔案系統不再包含在 ramdisk.img 中,而是併入 system.img (也就是說,如果已設定 BOARD_BUILD_SYSTEM_ROOT_IMAGE,系統一律會建立 system.img)。推出時搭載 Android 10 的裝置:

  • 使用系統做為根分區的版面配置 (由版本自動強制執行,且沒有變更行為的選項)。
  • 必須使用 dm-linear 所需的 RAM 磁碟。
  • 必須將 BOARD_BUILD_SYSTEM_ROOT_IMAGE 設為 false。這項設定只用於區分使用 RAM 磁碟機的裝置,以及不使用 RAM 磁碟機 (而是直接掛載 system.img) 的裝置。

在 Android 9 和 Android 10 之間,系統做為根目錄的設定含義有所不同。在 Android 9 系統做為根目錄的設定中,BOARD_BUILD_SYSTEM_ROOT_IMAGE 會設為 true,這會強制建構作業將根檔案系統合併至 system.img,然後將 system.img 掛載為根檔案系統 (rootfs)。對於搭載 Android 9 的裝置,這項設定是必要的,但對於升級至 Android 9 的裝置和搭載較舊 Android 版本的裝置,則是選用的。在 Android 10 系統做為根目錄的設定中,建構作業一律會將 $TARGET_SYSTEM_OUT$TARGET_ROOT_OUT 合併為 system.img;對於所有搭載 Android 10 的裝置,這項設定是預設行為。

Android 10 會進一步變更,以支援動態分區,這是一種使用者空間分區系統,可讓無線 (OTA) 更新建立、調整大小或刪除分區。在這個變更中,Linux 核心無法再在執行 Android 10 的裝置上掛載邏輯系統分區,因此這個作業會由第一階段初始化處理。

以下各節將說明系統專用 OTA 的系統做為根目錄要求,並提供更新裝置以使用系統做為根目錄的操作說明 (包括分割區版面配置變更和 dm-verity 核心要求)。如要進一步瞭解 RAMDISK 的異動,請參閱「RAMDISK 分區」一文。

關於系統專用 OTA

系統專用 OTA 需要系統做為根磁碟分區的版面配置,才能讓 Android 版本更新 system.imgproduct.img,而不變更其他分區。所有搭載 Android 10 的裝置都必須使用系統為根目錄的分割區版面配置,才能啟用僅限系統的 OTA。

  • A/B 裝置會將 system 分區掛載為 rootfs,因此已使用系統做為 root,且無需變更即可支援系統 OTA。
  • 非 A/B 裝置會在 /system 上掛載 system 分區,因此必須更新為使用系統做為根分區的版面配置,才能支援系統 OTA。

如需 A/B 裝置和非 A/B 裝置的詳細資訊,請參閱「A/B (無縫) 系統更新」。

使用供應商疊加層 (AOSP 14 以下)

供應商疊加可讓您在裝置啟動時疊加 vendor 分區的變更。供應商疊加層是 product 分區中的一組供應商模組,會在裝置啟動時疊加至 vendor 分區,取代並新增至現有模組。

裝置啟動時,init 程序會完成第一個階段的掛載作業,並讀取預設屬性。接著,如果符合下列條件,系統會搜尋 /product/vendor_overlay/<target_vendor_version>,並將每個子目錄掛載至對應的 vendor 分割區目錄:

  • /vendor/<overlay_dir> 已存在。
  • /product/vendor_overlay/<target_vendor_version>/<overlay_dir>/vendor/<overlay_dir> 具有相同的檔案內容。
  • init 可在 /vendor/<overlay_dir> 的檔案內容中掛載。

實作供應商重疊

/product/vendor_overlay/<target_vendor_version> 中安裝供應商疊加檔案。這些檔案會在裝置啟動時覆蓋 vendor 分割區,取代同名檔案並新增任何新檔案。供應商疊加層無法從 vendor 分割區移除檔案。

供應商疊加檔案必須與 vendor 分割區中所取代的目標檔案具有相同的檔案內容。根據預設,/product/vendor_overlay/<target_vendor_version> 目錄中的檔案具有 vendor_file 結構定義。如果供應商覆蓋檔案與其取代的檔案之間的檔案內容不相符,請在裝置專屬的 sepolicy 中指定這項內容。檔案內容是在目錄層級設定。如果供應商覆蓋目錄的檔案內容不符,且裝置專屬的 sepolicy 中未指定正確的檔案內容,則該供應商覆蓋目錄不會覆蓋至目標目錄。

如要使用供應商重疊顯示功能,核心必須透過設定 CONFIG_OVERLAY_FS=y 啟用 OverlayFS。此外,核心必須從常見的 4.4 以上核心合併,或使用 "overlayfs: override_creds=off option bypass creator_cred" 進行修補。

供應商疊加層實作範例

本程序說明如何實作供應商疊加層,疊加 /vendor/lib/*/vendor/etc/*/vendor/app/* 目錄。

  1. device/<vendor>/<target>/vendor_overlay/<target_vendor_version>/ 中新增預先建構的供應商檔案:

    device/google/device/vendor_overlay/28/lib/libfoo.so
    device/google/device/vendor_overlay/28/lib/libbar.so
    device/google/device/vendor_overlay/28/etc/baz.xml
    device/google/device/vendor_overlay/28/app/qux.apk
  2. 將預先建構的供應商檔案安裝至 device/google/device/device.mk 中的 product/vendor_overlay

    PRODUCT_COPY_FILES += \
        $(call find-copy-subdir-files,*,device/google/device/vendor_overlay,$(TARGET_COPY_OUT_PRODUCT)/vendor_overlay)
  3. 如果目標 vendor 分割區檔案的內容不是 vendor_file,請定義檔案內容。由於 /vendor/lib/* 使用 vendor_file 情境,因此這個範例不會納入該目錄。

    device/google/device-sepolicy/private/file_contexts 中新增以下內容:

    /(product|system/product)/vendor_overlay/[0-9]+/etc(/.*)?   u:object_r:vendor_configs_file:s0
    /(product|system/product)/vendor_overlay/[0-9]+/app(/.*)?   u:object_r:vendor_app_file:s0
  4. 允許 init 程序在 vendor_file 以外的檔案情境中掛接供應商疊加層。由於 init 程序已具備掛載 vendor_file 內容的權限,因此本例不會定義 vendor_file 的政策。

    device/google/device-sepolicy/public/init.te 中新增以下內容:

    allow init vendor_configs_file:dir mounton;
    allow init vendor_app_file:dir mounton;

驗證供應商重疊圖層

如要驗證供應商疊加設定,請在 /product/vendor_overlay/<target_vendor_version>/<overlay_dir> 中新增檔案,然後檢查這些檔案是否疊加在 /vendor/<overlay_dir> 中的檔案上。

對於 userdebug 版本,Atest 有測試模組:

$ atest -v fs_mgr_vendor_overlay_test

更新為系統-as-root

如要更新非 A/B 裝置以使用系統做為根目錄,您必須更新 boot.imgsystem.img 的分割區配置方案、設定 dm-verity,並移除裝置專屬根目錄的所有啟動依附元件。

更新分區

與 A/B 裝置將 /boot 重新用於復原分區不同,非 A/B 裝置必須保留 /recovery 分區,因為它們沒有備用插槽分區 (例如從 boot_aboot_b)。如果在非 A/B 裝置上移除 /recovery,並將其設為類似 A/B 配置,則在更新 /boot 分區時可能會中斷復原模式。因此,對於非 A/B 裝置,/recovery 區隔 必須/boot 區隔開來,這表示復原映像檔會繼續以延遲方式更新 (也就是與搭載 Android 8.1.0 以下版本的裝置相同)。

下表列出 Android 9 之前和之後,非 A/B 裝置的映像檔區隔差異。

圖片 Ramdisk (9 之前) 以系統為根 (9 之後)
boot.img 包含核心和 ramdisk.img
ramdisk.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/ (mount point)
    - vendor/ (mount point)
    - odm/ (mount point)
    ...
只包含一般啟動核心。
recovery.img 包含復原核心和復原 ramdisk.img
system.img 包含下列項目:
system.img
  -/
    - bin/
    - etc
    - vendor -> /vendor
    - ...
包含原始 system.imgramdisk.img 的合併內容:
system.img
  -/
    - init.rc
    - init
    - etc -> /system/etc
    - system/
      - bin/
      - etc/
      - vendor -> /vendor
      - ...
    - vendor/ (mount point)
    - odm/ (mount point)
    ...

分割區本身不會變更;ramdisk 和系統-as-root 都會使用下列分割區配置:

  • /boot
  • /system
  • /system
  • /recovery
  • /vendor

設定 dm-verity

在以系統為根目錄的情況下,核心必須使用 dm-verity/ (掛載點) 下掛載 system.img。Android 開放原始碼計畫支援 system.img 的下列 dm-verity 實作項目。

vboot 1.0

對於 vboot 1.0,核心必須在 /system 上剖析 Android 專屬的中繼資料,然後轉換為 dm-verity 參數來設定 dm-verity (需要這些核心修補程式)。以下範例顯示在核心指令列中,以系統為根目錄的 dm-verity 相關設定:

ro root=/dev/dm-0 rootwait skip_initramfs init=/init
dm="system none ro,0 1 android-verity /dev/sda34"
veritykeyid=id:7e4333f9bba00adfe0ede979e28ed1920492b40f

vboot 2.0

針對 vboot 2.0 (AVB),引導程式必須整合 external/avb/libavb,然後剖析 /system hashtree 描述元,將其轉換為 dm-verity 參數,最後透過核心指令列將參數傳遞至核心。(/system 的 Hashtree 描述符可能位於 /vbmeta/system 本身)。

vboot 2.0 需要下列核心修補程式:

以下範例顯示在核心指令列中,以系統為根目錄的 dm-verity 相關設定:

ro root=/dev/dm-0 rootwait  skip_initramfs init=/init

dm="1 vroot none ro 1,0 5159992 verity 1
PARTUUID=00000016-0000-0000-0000-000000000000
PARTUUID=00000016-0000-0000-0000-000000000000 4096 4096 644999 644999
sha1 d80b4a8be3b58a8ab86fad1b498640892d4843a2
8d08feed2f55c418fb63447fec0d32b1b107e42c 10 restart_on_corruption
ignore_zero_blocks use_fec_from_device
PARTUUID=00000016-0000-0000-0000-000000000000 fec_roots 2 fec_blocks
650080 fec_start 650080"

使用裝置專屬的根目錄

在系統做為根目錄的情況下,在裝置上刷新通用系統映像檔 (GSI) (並在執行供應商測試套件測試之前) 後,使用 BOARD_ROOT_EXTRA_FOLDERS 新增的任何裝置專屬根目錄資料夾都會消失,因為整個根目錄內容已由系統做為根目錄 GSI 取代。如果裝置有特定根資料夾的依附元件 (例如,用作掛載點),移除這些資料夾可能會導致裝置無法啟動。

為避免這個問題,請勿使用 BOARD_ROOT_EXTRA_FOLDERS 新增裝置專屬的根目錄。如果您需要指定裝置專屬的掛載點,請使用 /mnt/vendor/<mount point> (已新增至這些變更清單)。這些供應商專屬的掛載點可直接在 fstab 裝置樹狀結構 (用於第一階段掛載) 和 /vendor/etc/fstab.{ro.hardware} 檔案中指定,無須額外設定 (因為 fs_mgr 會自動在 /mnt/vendor/* 下建立這些掛載點)。