實施 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. 精選以下內核補丁系列(如果需要):
  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(否則裝置將引導至復原模式。復原模式很小(並且其中大部分已經在引導分割區上),因此引導分割區不會增加在尺寸方面。

穩定表

slotselect參數必須位於 A/B 分區的行上。例如:

<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 裝置相同的指令。必須透過定義 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

編譯應用程式

應用程式可以在使用新系統映像重新啟動之前在背景編譯。若要在背景編譯應用程序,請將以下內容新增至產品的裝置配置中(在產品的 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 檔案的首次開機安裝