想要實施 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/
來測試實現。
您還必須實現如下所示的狀態機:
![](https://source.android.com/static/devices/tech/ota/images/ab-updates-state-machine.png?authuser=4&hl=zh-tw)
設置內核
實施 A/B 系統更新:
- Cherrypick 以下內核補丁系列(如果需要):
- 如果在沒有 ramdisk 的情況下啟動並使用“啟動作為恢復”,cherrypick android-review.googlesource.com/#/c/158491/ 。
- 要在沒有 ramdisk 的情況下設置 dm-verity,請使用 cherrypick android-review.googlesource.com/#/q/status:merged+project:kernel/common+branch:android-3.18+topic:A_B_Changes_3.18 。
- 確保內核命令行參數包含以下額外參數:
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 ) . - 將包含公鑰的 .X509 證書添加到系統密鑰環:
- 將
.der
格式的 .X509 證書複製到kernel
目錄的根目錄下。如果 .X509 證書被格式化為.pem
文件,請使用以下openssl
命令將.pem
轉換為.der
格式:openssl x509 -in <x509-pem-certificate> -outform der -out <x509-der-certificate>
- 構建
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)。 - 將空格替換為
#
並將其作為<public-key-id>
在內核命令行中傳遞。例如,通過Android:#7e4333f9bba00adfe0ede979e28ed1920492b40f
代替<public-key-id>
。
- 將
設置構建變量
支持 A/B 的引導加載程序必須滿足以下構建變量標準:
必須為 A/B 目標定義 |
/device/google/marlin/+/android-7.1.0_r1/device-common.mk 。您可以選擇執行編譯中描述的安裝後(但重啟前)dex2oat 步驟。 |
---|---|
強烈推薦用於 A/B 目標 |
|
無法為 A/B 目標定義 |
|
調試版本可選 | PRODUCT_PACKAGES_DEBUG += update_engine_client |
設置分區(槽)
A/B 設備不需要恢復分區或緩存分區,因為 Android 不再使用這些分區。數據分區現在用於下載的 OTA 包,恢復映像代碼在引導分區上。所有經過 A/B 處理的分區都應命名如下(插槽始終命名為a
、 b
等): boot_a
、 boot_b
、 system_a
、 system_b
、 vendor_a
、 vendor_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_a
或vendor_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 分區。一對分區有一個共同的前綴(例如system
或boot
)和每個插槽的後綴(例如_a
)。有效負載生成器為其定義更新的分區列表由AB_OTA_PARTITIONS
make 變量配置。
例如,如果包含一對分區bootloader_a
和booloader_b
( _a
和_b
是插槽後綴),您可以通過在產品或板配置上指定以下內容來更新這些分區:
AB_OTA_PARTITIONS := \ boot \ system \ bootloader
由update_engine
更新的所有分區不得被系統的其餘部分修改。在增量或增量更新期間,來自當前槽的二進制數據用於生成新槽中的數據。任何修改都可能導致新槽位數據在更新過程中校驗失敗,從而導致更新失敗。
配置安裝後
您可以使用一組鍵值對為每個更新的分區配置不同的安裝後步驟。要在新映像中運行位於/system/usr/bin/postinst
的程序,請指定相對於系統分區中文件系統根目錄的路徑。
例如, usr/bin/postinst
是system/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 中):
- 在構建中包含本機組件,以確保編譯腳本和二進製文件被編譯並包含在系統映像中。
# A/B OTA dexopt package PRODUCT_PACKAGES += otapreopt_script
- 將編譯腳本連接到
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 文件的首次引導安裝。