實施 A/B 更新

想要實施 A/B 系統更新的 OEM 和 SoC 供應商必須確保其引導加載程序實施 boot_control HAL 並將正確的參數傳遞給內核。

實現引導控制 HAL

支持 A/B 的引導加載程序必須在hardware/libhardware/include/hardware/boot_control.h實現boot_control HAL。您可以使用system/extras/bootctl實用程序和system/extras/tests/bootloader/來測試實現。

您還必須實現如下所示的狀態機:

圖 1.引導加載程序狀態機

設置內核

實施 A/B 系統更新:

  1. Cherrypick 以下內核補丁系列(如果需要):
  2. 確保內核命令行參數包含以下額外參數:
    skip_initramfs rootwait ro init=/init root="/dev/dm-0 dm=system none ro,0 1 android-verity <public-key-id> <path-to-system-partition>"
    ... 其中<public-key-id>值是用於驗證驗證表簽名的公鑰的 ID(有關詳細信息,請參閱dm-verity ) .
  3. 將包含公鑰的 .X509 證書添加到系統密鑰環:
    1. .der格式的 .X509 證書複製到kernel目錄的根目錄下。如果 .X509 證書被格式化為.pem文件,請使用以下openssl命令將.pem轉換為.der格式:
      openssl x509 -in <x509-pem-certificate> -outform der -out <x509-der-certificate>
    2. 構建zImage以將證書包含在系統密鑰環中。要驗證,請檢查procfs條目(需要啟用KEYS_CONFIG_DEBUG_PROC_KEYS ):
      angler:/# cat /proc/keys
      
      1c8a217e I------     1 perm 1f010000     0     0 asymmetri
      Android: 7e4333f9bba00adfe0ede979e28ed1920492b40f: X509.RSA 0492b40f []
      2d454e3e I------     1 perm 1f030000     0     0 keyring
      .system_keyring: 1/4
      成功包含 .X509 證書表示系統密鑰環中存在公鑰(突出顯示表示公鑰 ID)。
    3. 將空格替換為#並將其作為<public-key-id>在內核命令行中傳遞。例如,通過Android:#7e4333f9bba00adfe0ede979e28ed1920492b40f代替<public-key-id>

設置構建變量

支持 A/B 的引導加載程序必須滿足以下構建變量標準:

必須為 A/B 目標定義
  • AB_OTA_UPDATER := true
  • AB_OTA_PARTITIONS := \
    boot \
    system \
    vendor
    以及通過update_engine更新的其他分區(收音機、引導加載程序等)
  • PRODUCT_PACKAGES += \
    update_engine \
    update_verifier
例如,請參閱/device/google/marlin/+/android-7.1.0_r1/device-common.mk 。您可以選擇執行編譯中描述的安裝後(但重啟前)dex2oat 步驟。
強烈推薦用於 A/B 目標
  • 定義TARGET_NO_RECOVERY := true
  • 定義BOARD_USES_RECOVERY_AS_BOOT := true
  • 不要定義BOARD_RECOVERYIMAGE_PARTITION_SIZE
無法為 A/B 目標定義
  • BOARD_CACHEIMAGE_PARTITION_SIZE
  • BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE
調試版本可選PRODUCT_PACKAGES_DEBUG += update_engine_client

設置分區(槽)

A/B 設備不需要恢復分區或緩存分區,因為 Android 不再使用這些分區。數據分區現在用於下載的 OTA 包,恢復映像代碼在引導分區上。所有經過 A/B 處理的分區都應命名如下(插槽始終命名為ab等): boot_aboot_bsystem_asystem_bvendor_avendor_b

緩存

對於非 A/B 更新,緩存分區用於存儲下載的 OTA 包並在應用更新時臨時存儲塊。從來沒有一個很好的方法來調整緩存分區的大小:它需要多大取決於您想要應用的更新。最壞的情況是緩存分區與系統映像一樣大。使用 A/B 更新,無需存儲塊(因為您總是在寫入當前未使用的分區),使用流式 A/B 無需在應用之前下載整個 OTA 包。

恢復

恢復 RAM 磁盤現在包含在boot.img文件中。進入恢復時,引導加載程序無法skip_initramfs選項放在內核命令行上。

對於非 A/B 更新,恢復分區包含用於應用更新的代碼。 A/B 更新由在常規引導系統映像中運行的update_engine應用。還有一種恢復模式用於實現出廠數據重置和更新包的側載(這就是“恢復”名稱的來源)。恢復模式的代碼和數據存儲在 ramdisk 的常規引導分區中;為了引導到系統映像,引導加載程序告訴內核跳過 ramdisk(否則設備引導進入恢復模式。恢復模式很小(並且大部分已經在引導分區上),所以引導分區不會增加在尺寸方面。

Fstab

slotselect參數必須在 A/B-ed 分區的行上。例如:

<path-to-block-device>/vendor  /vendor  ext4  ro
wait,verify=<path-to-block-device>/metadata,slotselect

不應將分區命名為vendor 。相反,分區vendor_avendor_b將被選擇並安裝在/vendor安裝點上。

內核槽參數

當前插槽後綴應通過特定設備樹 (DT) 節點 ( /firmware/android/slot_suffix ) 或通過androidboot.slot_suffix內核命令行或 bootconfig 參數傳遞。

默認情況下,fastboot 會刷新 A/B 設備上的當前插槽。如果更新包還包含其他非當前插槽的映像,fastboot 也會刷新這些映像。可用選項包括:

  • --slot SLOT 。覆蓋默認行為並提​​示 fastboot 刷新作為參數傳入的插槽。
  • --set-active [ SLOT ] 。將插槽設置為活動。如果未指定可選參數,則當前插槽設置為活動。
  • fastboot --help 。獲取有關命令的詳細信息。

如果引導加載程序實現了快速引導,它應該支持命令set_active <slot>將當前活動槽設置為給定槽(這還必須清除該槽的不可引導標誌並將重試計數重置為默認值)。引導加載程序還應支持以下變量:

  • has-slot:<partition-base-name-without-suffix> 。如果給定的分區支持插槽,則返回“yes”,否則返回“no”。
  • current-slot 。返回將從下一個引導的插槽後綴。
  • slot-count 。返回一個表示可用槽數的整數。目前,支持兩個插槽,因此該值為2
  • slot-successful:<slot-suffix> 。如果給定的插槽已被標記為成功啟動,則返回“yes”,否則返回“no”。
  • slot-unbootable:<slot-suffix> 。如果給定的插槽被標記為不可引導,則返回“yes”,否則返回“no”。
  • slot-retry-count .嘗試引導給定插槽的剩餘重試次數。

要查看所有變量,請運行fastboot getvar all

生成OTA包

OTA 打包工具遵循與非 A/B 設備的命令相同的命令。必須通過為 A/B 目標定義構建變量來生成target_files.zip文件。 OTA 包工具會自動識別並生成 A/B 更新程序格式的包。

例子:

  • 生成完整的 OTA:
    ./build/make/tools/releasetools/ota_from_target_files \
        dist_output/tardis-target_files.zip \
        ota_update.zip
    
  • 生成增量 OTA:
    ./build/make/tools/releasetools/ota_from_target_files \
        -i PREVIOUS-tardis-target_files.zip \
        dist_output/tardis-target_files.zip \
        incremental_ota_update.zip
    

配置分區

update_engine可以更新同一磁盤中定義的任何一對 A/B 分區。一對分區有一個共同的前綴(例如systemboot )和每個插槽的後綴(例如_a )。有效負載生成器為其定義更新的分區列表由AB_OTA_PARTITIONS make 變量配置。

例如,如果包含一對分區bootloader_abooloader_b_a_b是插槽後綴),您可以通過在產品或板配置上指定以下內容來更新這些分區:

AB_OTA_PARTITIONS := \
  boot \
  system \
  bootloader

update_engine更新的所有分區不得被系統的其餘部分修改。在增量或增量更新期間,來自當前槽的二進制數據用於生成新槽中的數據。任何修改都可能導致新槽位數據在更新過程中校驗失敗,從而導致更新失敗。

配置安裝後

您可以使用一組鍵值對為每個更新的分區配置不同的安裝後步驟。要在新映像中運行位於/system/usr/bin/postinst的程序,請指定相對於系統分區中文件系統根目錄的路徑。

例如, usr/bin/postinstsystem/usr/bin/postinst (如果不使用 RAM 磁盤)。此外,指定要傳遞給mount(2)系統調用的文件系統類型。將以下內容添加到產品或設備.mk文件(如果適用):

AB_OTA_POSTINSTALL_CONFIG += \
  RUN_POSTINSTALL_system=true \
  POSTINSTALL_PATH_system=usr/bin/postinst \
  FILESYSTEM_TYPE_system=ext4

編譯

出於安全原因, system_server不能使用即時 (JIT)編譯。這意味著您必須至少為system_server及其依賴項提前編譯 odex 文件;其他任何事情都是可選的。

要在後台編譯應用程序,您必須將以下內容添加到產品的設備配置中(在產品的 device.mk 中):

  1. 在構建中包含本機組件,以確保編譯腳本和二進製文件被編譯並包含在系統映像中。
      # A/B OTA dexopt package
      PRODUCT_PACKAGES += otapreopt_script
    
  2. 將編譯腳本連接到update_engine以便作為安裝後步驟運行。
      # A/B OTA dexopt update_engine hookup
      AB_OTA_POSTINSTALL_CONFIG += \
        RUN_POSTINSTALL_system=true \
        POSTINSTALL_PATH_system=system/bin/otapreopt_script \
        FILESYSTEM_TYPE_system=ext4 \
        POSTINSTALL_OPTIONAL_system=true
    

有關在未使用的第二個系統分區中安裝預選文件的幫助,請參閱DEX_PREOPT 文件的首次引導安裝