sheldon_blogs

Android OTA的两种方式:Non-A/B(recovery)和A/B系统升级

一、Recovery系统升级

Recovery升级也就是传统的非A/B升级(Non-A/B System Updates)

工作流程:

  1. 下载更新包:用户接收到更新通知后,下载OTA(Over-The-Air)更新包。
  2. 准备更新:下载完成后,系统会将更新包解压并准备进行安装。
  3. 安装更新:设备进入恢复模式(recovery mode),系统停止正常运行,安装更新包。
  4. 重启设备:更新完成后,设备重新启动并应用更新。

优点:
实现相对简单,因为不需要额外的分区或复杂的管理逻辑。

缺点:
安装过程中设备无法使用,更新过程可能需要较长时间。
如果更新过程中发生故障,可能导致设备无法正常启动,必须通过手动进恢复模式修复。

官网文档如下:
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),当一个分区正在使用时,另一个分区可以用来进行更新,从而减少更新过程中的设备不可用时间,实现无缝更新。

工作流程:

  1. 下载更新包:用户接收到更新通知后,下载OTA更新包。
  2. 更新备用分区:系统在后台将更新包安装到未使用的分区(例如,当前使用分区为a,更新包安装到分区b)。
  3. 切换分区:更新完成后,系统会将引导加载程序配置为从更新的分区启动(例如,从slot_a切换到slot_b)。
  4. 重启设备:设备重新启动,从更新的分区启动。

优点:
无缝更新:更新在后台进行,用户可以继续使用设备,减少了更新过程中的不便。
更安全:如果更新过程中出现问题,可以回滚到之前的分区,确保设备的可用性。

缺点:
需要更多存储空间,因为需要两个系统分区(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分区。
工作流程:

  1. 下载更新包:用户接收到更新通知后,下载OTA更新包。
  2. 创建和更新动态分区:系统在后台创建或更新动态分区(使用逻辑分区),这些分区通过内核支持并在内存中映射。
  3. 切换分区映射:更新完成后,系统会更新内存中的分区映射,从而指向更新后的逻辑分区。
  4. 重启设备:设备重新启动,加载更新后的分区。

优点:
无缝更新:用户可以在后台进行更新,无需停止设备操作。
更高效的存储利用率:使用动态分区减少了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)    收藏  举报

导航