Android AB分区OTA升级说明

1. 概述

OTA升级即Over-the-Air upgrade,本文会大致介绍Android标准的OTA包包括整包(full OTA)和差分包(incremental OTA)的制作方法以及本地验证OTA升级的方法。

2. OTA包的制作

2.1 编译配置

在编译OTA包时,BoardConfig.mk中的$(AB_OTA_PARTITIONS)设定来决定要对哪些分区做OTA升级。一般需要将AOSP的所有分区都填入到该变量中。

2.2 编译dist

不论是制作整包还是差分包,都需要先将制作OTA包所需的镜像文件先编译出来:

source build/envsetup.sh
lunch <device name>
make dist DIST_DIR=dist_output

在AOSP执行上述命令后,会得到一个目录dist_output,接下制作OTA包会需要基于该目录。

2.3 制作整包

执行命令:

ota_from_target_files \
    dist_output/<device name>_target_files.zip \
    ota_update.zip

会得到ota_update.zip。

2.4 制作差分包

制作差分包和制作整包类似,差异在要多喂一个'基础包'给ota_from_target_files以用于和新的target_files差分得到差分包,形如:

ota_from_target_files \
    -i last_target_files.zip \
    dist_output/<device name>_target_files.zip \
    incremental_ota_update.zip

会得到incremental_ota_update.zip。

3. 无缝升级验证

无缝升级即在系统运行的状态下将OTA包烧录到另一个slot。需要通过update_engine来完成OTA升级,主要有两种方式呼叫到update_engine:

  • 在shell通过调用update_engine_clinet完成从升级
  • APP通过UpdateEngine的applyPayload方法完成升级

3.1 使用update_engine_clinet验证

a> 编译出整包ota_update.zip

b> 解压ota_update.zip获得payload.binpayload_properties.txt

xxxxxx:~/workspace/AOSP$ unzip ota_update.zip -d ota_update_decompress
Archive:  ota_update.zip
signed by SignApk
 extracting: ota_update_decompress/META-INF/com/android/metadata
 extracting: ota_update_decompress/META-INF/com/android/metadata.pb
 extracting: ota_update_decompress/apex_info.pb
 extracting: ota_update_decompress/payload.bin
 extracting: ota_update_decompress/payload_properties.txt
  inflating: ota_update_decompress/META-INF/com/android/otacert

c> 检查当前设备所在的slot

PS C:\xxx> adb shell getprop ro.boot.slot_suffix
_a

d> 将payload.bin文件push到data分区

PS C:\xxx> adb root
restarting adbd as root
PS C:\xxx> adb shell mkdir /data/temp
PS C:\xxx> adb push .\ota_update_decompress\payload.bin /data/temp
.\ota_update_decompress\payload.bin: 1 file pushed, 0 skipped. 6.1 MB/s (422765615 bytes in 66.130s)

e> 从payload_properties.txt取参数,调用update_engine_clinet完成OTA升级 在调用update_engine_clinet之前可以再开一个命令行窗口执行adb logcat -s update_engine观察update_engine的升级进度。

PS C:\xxx>> adb shell
pioneer5_sdp:/ # update_engine_client --payload=file:///data/temp/payload.bin \
> --update \
> --headers="\
> FILE_HASH=k1VYZqDgsB0DJUw5hG2Rj9vg96bzE9DtY/CiYYpCuYI=
> FILE_SIZE=422765615
> METADATA_HASH=IfvrrWCRjbzJMI5za1VHgsaGqg12UnyTvf4usdTBdWA=
> METADATA_SIZE=44468"
pioneer5_sdp:/ #

注:对于开启seLinux的板子可能需要先执行setenforce 0将seLinux切到permissive模式。 在另一个窗口中可以看到update_engine会打印形如下log展示进度:

02-09 01:25:22.737   350   350 I update_engine: [INFO:delta_performer.cc(115)] Completed 123/789 operations (15%), 109920256/422765615 bytes downloaded (26%), overall progress 20%
02-09 01:25:43.724   350   350 I update_engine: [INFO:delta_performer.cc(115)] Completed 176/789 operations (22%), 160661504/422765615 bytes downloaded (38%), overall progress 30%
02-09 01:26:07.740   350   350 I update_engine: [INFO:delta_performer.cc(115)] Completed 248/789 operations (31%), 211386368/422765615 bytes downloaded (50%), overall progress 40%
02-09 01:26:31.479   350   350 I update_engine: [INFO:delta_performer.cc(115)] Completed 313/789 operations (39%), 262127616/422765615 bytes downloaded (62%), overall progress 50%
02-09 01:26:55.912   350   350 I update_engine: [INFO:delta_performer.cc(115)] Completed 379/789 operations (48%), 312213504/422765615 bytes downloaded (73%), overall progress 60%
02-09 01:27:09.672   350   350 I update_engine: [INFO:delta_performer.cc(115)] Completed 490/789 operations (62%), 332742656/422765615 bytes downloaded (78%), overall progress 70%
02-09 01:27:16.097   350   350 I update_engine: [INFO:delta_performer.cc(115)] Completed 647/789 operations (82%), 332759040/422765615 bytes downloaded (78%), overall progress 80%

最终会看到形如下成功的log:

02-09 01:27:50.421   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(330)] Hashing partition 0 (boot) on device /dev/block/platform/soc/soc:emmc/by-name/boot_b
02-09 01:27:50.427   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(380)] Verity writes disabled on partition boot
02-09 01:27:50.734   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(436)] Hash of boot: qPqEV09LNCXxbgCuBZLiGRM8KFy+IGqvxqWGzJ/1mDk=
02-09 01:27:50.749   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(330)] Hashing partition 1 (dtbo) on device /dev/block/platform/soc/soc:emmc/by-name/dtbo_b
02-09 01:27:50.755   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(380)] Verity writes disabled on partition dtbo
02-09 01:27:50.762   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(436)] Hash of dtbo: AvTCoA5SNMaDcvFBEgLrlckITdd6yR5R9qFreokowI4=
02-09 01:27:50.768   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(330)] Hashing partition 2 (odm) on device /dev/block/platform/soc/soc:emmc/by-name/odm_b
02-09 01:27:50.774   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(380)] Verity writes disabled on partition odm
02-09 01:27:50.932   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(436)] Hash of odm: 9FZ3WRMTUcsn7iSWv/1FekiY65WvykZ89YeRZdRtMcQ=
02-09 01:27:50.942   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(330)] Hashing partition 3 (system) on device /dev/block/platform/soc/soc:emmc/by-name/system_b
02-09 01:27:50.948   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(380)] Verity writes disabled on partition system
02-09 01:28:14.876   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(436)] Hash of system: 5s+2+UIPmwSdJ9Nzm4197qkcqHlu6r6UX8cdAJQv544=
02-09 01:28:15.378   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(330)] Hashing partition 4 (vendor) on device /dev/block/platform/soc/soc:emmc/by-name/vendor_b
02-09 01:28:15.385   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(380)] Verity writes disabled on partition vendor
02-09 01:28:20.167   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(436)] Hash of vendor: O6/WFp4iXJDfGycYnAYUzyIfYWfxlPlpdAIGdl2K4Ao=
02-09 01:28:20.313   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(330)] Hashing partition 5 (vendor_boot) on device /dev/block/platform/soc/soc:emmc/by-name/vendor_boot_b
02-09 01:28:20.320   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(380)] Verity writes disabled on partition vendor_boot
02-09 01:28:20.569   350   350 I update_engine: [INFO:filesystem_verifier_action.cc(436)] Hash of vendor_boot: kLJ2SzMyS+Io/K+Vlo/+8WUOf8gIW17cwdINmc86sIk=
02-09 01:28:20.584   350   350 I update_engine: [INFO:action_processor.cc(116)] ActionProcessor: finished FilesystemVerifierAction with code ErrorCode::kSuccess
02-09 01:28:20.591   350   350 I update_engine: [INFO:action_processor.cc(143)] ActionProcessor: starting PostinstallRunnerAction
02-09 01:28:20.598   350   350 I update_engine: [INFO:dynamic_partition_control_android.cc(1057)] Skip FinishedSnapshotWrites() because /metadata is not mounted
02-09 01:28:20.619   350   350 I update_engine: [INFO:hardware_android.cc(291)] Device doesn't use avb, skipping setting vbmeta digest
02-09 01:28:20.628   350   350 E update_engine: UnmapAllSnapshots should never be called.
02-09 01:28:20.634   350   350 I update_engine: [INFO:postinstall_runner_action.cc(389)] Unmapped all partitions.
02-09 01:28:20.640   350   350 I update_engine: [INFO:postinstall_runner_action.cc(405)] All post-install commands succeeded
02-09 01:28:20.646   350   350 I update_engine: [INFO:action_processor.cc(116)] ActionProcessor: finished last action PostinstallRunnerAction with code ErrorCode::kSuccess
02-09 01:28:20.652   350   350 I update_engine: [INFO:update_attempter_android.cc(546)] Processing Done.
02-09 01:28:20.659   350   350 I update_engine: [INFO:update_attempter_android.cc(559)] Update successfully applied, waiting to reboot.
02-09 01:28:20.665   350   350 E update_engine: UnmapAllSnapshots should never be called.
02-09 01:28:20.674   350   350 I update_engine: [INFO:metrics_reporter_android.cc(159)] Current update attempt downloads 403 bytes data
02-09 01:28:20.685   350   350 I update_engine: [INFO:metrics_utils.cc(335)] Updated Marker = 1/1/1970 0:39:21 GMT

f> reboot重启,查看设备是否正常开机,和c步骤一样的方法查看设备当前是否处在另一个slot。