實施 A/B 更新

OEM廠商和SoC廠商誰想要實現A / B系統更新必須確保他們的引導程序實現boot_control HAL並傳遞正確的參數傳遞給內核。

實現引導控制 HAL

A / B-能夠引導程序必須實現boot_control在HAL hardware/libhardware/include/hardware/boot_control.h 。您可以使用測試實現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-真理) .
  3. 將包含公鑰的 .X509 證書添加到系統密鑰環:
    1. 複製在格式化.X509證書.der格式的根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包,恢復鏡像代碼在boot分區。是A / B-ED應如下命名的所有分區(時隙總是被命名為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(否則設備將引導到恢復模式。恢復模式很小(並且其中大部分已經在引導分區上),因此引導分區不會增加在尺寸方面。

所述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 。獲取有關命令的詳細信息。

如果引導加載程序工具FASTBOOT,它應支持命令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設備的命令。所述target_files.zip必須通過定義為A / B目標的生成變量來生成文件。 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使變量。

例如,如果一對分區的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)編譯。這意味著你必須編譯提前時間ODEX文件system_server及其在最低限度的依賴;其他任何東西都是可選的。

要在後台編譯應用程序,您必須將以下內容添加到產品的設備配置中(在產品的 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
    

對於未使用的第二系統分區上安裝preopted文件幫助,請參閱的DEX_PREOPT文件首先啟動安裝