Android OTA的两种方式:Non-A/B(recovery)和A/B系统升级
一、Recovery系统升级
Recovery升级也就是传统的非A/B升级(Non-A/B System Updates)
工作流程:
- 下载更新包:用户接收到更新通知后,下载OTA(Over-The-Air)更新包。
- 准备更新:下载完成后,系统会将更新包解压并准备进行安装。
- 安装更新:设备进入恢复模式(recovery mode),系统停止正常运行,安装更新包。
- 重启设备:更新完成后,设备重新启动并应用更新。
优点:
实现相对简单,因为不需要额外的分区或复杂的管理逻辑。
缺点:
安装过程中设备无法使用,更新过程可能需要较长时间。
如果更新过程中发生故障,可能导致设备无法正常启动,必须通过手动进恢复模式修复。
官网文档如下:
https://source.android.com/docs/core/ota/nonab?hl=zh-cn
以RK3588 Android12平台为例,Recovery升级指令如下:
adb push ota-eng.root.zip /cache/recovery_update.zip adb shell "echo \"--update_package=/cache/recovery_update.zip\" >> /cache/recovery/command" adb reboot recovery
二、A/B系统升级(A/B (Seamless) System Updates)
由于传统Recovery升级的局限性,因此Android从7.0开始引入新的OTA升级方式A/B升级(也称为无缝更新),A/B系统升级通过创建两个系统分区(A和B),当一个分区正在使用时,另一个分区可以用来进行更新,从而减少更新过程中的设备不可用时间,实现无缝更新。
工作流程:
- 下载更新包:用户接收到更新通知后,下载OTA更新包。
- 更新备用分区:系统在后台将更新包安装到未使用的分区(例如,当前使用分区为a,更新包安装到分区b)。
- 切换分区:更新完成后,系统会将引导加载程序配置为从更新的分区启动(例如,从slot_a切换到slot_b)。
- 重启设备:设备重新启动,从更新的分区启动。
优点:
无缝更新:更新在后台进行,用户可以继续使用设备,减少了更新过程中的不便。
更安全:如果更新过程中出现问题,可以回滚到之前的分区,确保设备的可用性。
缺点:
需要更多存储空间,因为需要两个系统分区(slot_a / slot_b)。
官方文档如下:
https://source.android.com/docs/core/ota/ab?hl=zh-cn
以RK3588 Android12平台为例,默认是Recovery升级方式,修改为AB系统升级需要打开对应的编译配置:
@@ -17,7 +17,7 @@ include device/rockchip/rk3588/BoardConfig.mk BUILD_WITH_GO_OPT := false # AB image definition -BOARD_USES_AB_IMAGE := false +BOARD_USES_AB_IMAGE := true BOARD_ROCKCHIP_VIRTUAL_AB_ENABLE := false --------------------------------------------------------------------------------------- diff --git a/u-boot/configs/rk3588_defconfig b/u-boot/configs/rk3588_defconfig index badc0b7..e24d241 100755 --- a/u-boot/configs/rk3588_defconfig +++ b/u-boot/configs/rk3588_defconfig @@ -236,3 +236,4 @@ CONFIG_OPTEE_V2=y CONFIG_OPTEE_ALWAYS_USE_SECURITY_PARTITION=y CONFIG_CMD_DTEN=y CONFIG_DTEN_GPIO=y +CONFIG_ANDROID_AB=y
build.sh脚本的参数修改:
- . ./build.sh -AUCKuo
+ . ./build.sh -ABUCKuo
如果userdata分区用的ext4格式,也需要同步修改过来(默认是f2fs):
+++ b/device/rockchip/rk3588/RadxaRock5C/recovery.fstab_AB ...... /dev/block/by-name/userdata /data ext4 defaults defaults -------------------------------------------------------------------------------- --- a/device/rockchip/rk3588/device.mk +++ b/device/rockchip/rk3588/device.mk @@ -32,8 +32,7 @@ PRODUCT_PACKAGES += \ #$(call inherit-product-if-exists, vendor/rockchip/common/npu/npu.mk) #BOARD_SEPOLICY_DIRS += device/rockchip/rk3588/sepolicy_vendor -# enable this for support f2fs with data partion -BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE := f2fs +BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE := ext4
AB系统升级指令如下:
1.将AB升级的OTA包下载到本地解压:
adb push ota-eng.root.zip /sdcard/ab_update.zip adb shell "unzip /sdcard/ab_update.zip -d /cache/"
2.通过AB系统编译时生成的update_engine_client升级程序进行安装: adb shell进入系统执行升级程序,参数如下: update_engine_client \ --update \ --follow \ --payload=file:///cache/payload.bin \ --headers=" FILE_HASH=RU3Yind4kMb4JN56cdWxIsV3QN2albGbIilsNty10s= FILE_SIZE=649244766 METADATA_HASH=VbWk+eWZJTO73B0mM6s/0THjoLMJ19Ncvz9MbYe8UaY= METADATA_SIZE=47623"
注:
--payload=后指定的payload.bin是解压OTA压缩包获得。
--headers=后的参数是解压OTA压缩包获得的payload_properties.txt所包含的内容。注:--headers=后要接回车(\n)
执行update_engine_client开始空闲分区的更新,成功后会有如下打印,会在下次系统重启后切换到更新分区:
... [INFO:update_engine_client_android.cc(92)] onStatusUpdate(UPDATE_STATUS_UPDATED_NEED_REBOOT (6), 0) [INFO:update_engine_client_android.cc(100)] onPayloadApplicationComplete(ErrorCode::kSuccess (0))
查看当前系统分区信息:
console:/ # lpdump (/system/etc/init/lpdumpd.rc:31) Slot 0: Metadata version: 10.0 Metadata size: 1452 bytes Metadata max size: 65536 bytes Metadata slot count: 3 Header flags: none Partition table: ------------------------ Name: system_a Group: rockchip_dynamic_partitions_a Attributes: readonly Extents: 0 .. 1823311 linear super 2048 ------------------------ Name: system_b Group: rockchip_dynamic_partitions_b Attributes: readonly Extents: ------------------------ Name: system_ext_a Group: rockchip_dynamic_partitions_a Attributes: readonly Extents: 0 .. 299999 linear super 1826816 ------------------------ Name: system_ext_b Group: rockchip_dynamic_partitions_b Attributes: readonly Extents: ------------------------ Name: vendor_a Group: rockchip_dynamic_partitions_a Attributes: readonly Extents: 0 .. 1006719 linear super 2127872 ------------------------ Name: vendor_b Group: rockchip_dynamic_partitions_b Attributes: readonly Extents: ------------------------ Name: vendor_dlkm_a Group: rockchip_dynamic_partitions_a Attributes: readonly Extents: 0 .. 9471 linear super 3135488 ------------------------ Name: vendor_dlkm_b Group: rockchip_dynamic_partitions_b Attributes: readonly Extents: ------------------------ Name: odm_a Group: rockchip_dynamic_partitions_a Attributes: readonly Extents: 0 .. 1359 linear super 3145728 ------------------------ Name: odm_b Group: rockchip_dynamic_partitions_b Attributes: readonly Extents: ------------------------ Name: odm_dlkm_a Group: rockchip_dynamic_partitions_a Attributes: readonly Extents: 0 .. 511 linear super 3147776 ------------------------ Name: odm_dlkm_b Group: rockchip_dynamic_partitions_b Attributes: readonly Extents: ------------------------ Name: product_a Group: rockchip_dynamic_partitions_a Attributes: readonly Extents: 0 .. 63375 linear super 3149824 ------------------------ Name: product_b Group: rockchip_dynamic_partitions_b Attributes: readonly Extents: ------------------------ Name: scratch Group: default Attributes: none Extents: 0 .. 1455 linear super 1825360 1456 .. 2511 linear super 2126816 2512 .. 3407 linear super 3134592 3408 .. 4175 linear super 3144960 4176 .. 4863 linear super 3147088 4864 .. 6399 linear super 3148288 6400 .. 3643575 linear super 3213200 ------------------------ Super partition layout: ------------------------ super: 2048 .. 1825360: system_a (1823312 sectors) super: 1825360 .. 1826816: scratch (1456 sectors) super: 1826816 .. 2126816: system_ext_a (300000 sectors) super: 2126816 .. 2127872: scratch (1056 sectors) super: 2127872 .. 3134592: vendor_a (1006720 sectors) super: 3134592 .. 3135488: scratch (896 sectors) super: 3135488 .. 3144960: vendor_dlkm_a (9472 sectors) super: 3144960 .. 3145728: scratch (768 sectors) super: 3145728 .. 3147088: odm_a (1360 sectors) super: 3147088 .. 3147776: scratch (688 sectors) super: 3147776 .. 3148288: odm_dlkm_a (512 sectors) super: 3148288 .. 3149824: scratch (1536 sectors) super: 3149824 .. 3213200: product_a (63376 sectors) super: 3213200 .. 6850376: scratch (3637176 sectors) ------------------------ Block device table: ------------------------ Partition name: super First sector: 2048 Size: 5372903424 bytes Flags: none ------------------------ Group table: ------------------------ Name: default Maximum size: 0 bytes Flags: none ------------------------ Name: rockchip_dynamic_partitions_a Maximum size: 2682257408 bytes Flags: none ------------------------ Name: rockchip_dynamic_partitions_b Maximum size: 2682257408 bytes Flags: none ------------------------
查看当前系统运行的哪个分区:
console:/ # getprop ro.boot.slot_suffix
_a
另外,简单介绍一下虚拟A/B升级(Virtual A/B Overview)方式:
由于A/B升级也有缺点(占用额外的存储空间),因此又引入了虚拟A/B升级,RK官方文档描述:
注意:如果要开启虚拟AB功能(不建议),则需要同时配置BOARD_USES_AB_IMAGE 和 BOARD_ROCKCHIP_VIRTUAL_AB_ENABLE为true,即: -BOARD_USES_AB_IMAGE := false -BOARD_ROCKCHIP_VIRTUAL_AB_ENABLE := false +BOARD_USES_AB_IMAGE := true +BOARD_ROCKCHIP_VIRTUAL_AB_ENABLE := true
概述:
虚拟A/B升级结合了A/B和非A/B升级的优点,通过逻辑分区和动态分区达到减少存储空间目的。
在Android 10及更高版本中引入,通过使用动态分区来实现无缝更新,而不需要实际的物理A/B分区。
工作流程:
- 下载更新包:用户接收到更新通知后,下载OTA更新包。
- 创建和更新动态分区:系统在后台创建或更新动态分区(使用逻辑分区),这些分区通过内核支持并在内存中映射。
- 切换分区映射:更新完成后,系统会更新内存中的分区映射,从而指向更新后的逻辑分区。
- 重启设备:设备重新启动,加载更新后的分区。
优点:
无缝更新:用户可以在后台进行更新,无需停止设备操作。
更高效的存储利用率:使用动态分区减少了A/B分区所需的存储空间。
缺点:
实现复杂度更高,需要内核和系统的支持。
官方文档如下:
https://source.android.com/docs/core/ota/virtual_ab?hl=zh-cn
posted on 2025-04-08 11:46 sheldon_blogs 阅读(1870) 评论(0) 收藏 举报
浙公网安备 33010602011771号