Android中的无缝A / B更新:它们的工作方式

图片



你好。在SberDevices,我们的团队致力于基于AOSP为其开发各种硬件和固件。



从Android 8(某些供应商从7.1开始)开始,该系统具有一种用于滚动OTA更新的新机制,即所谓的。无缝的A / B OTA更新-无缝更新。在这篇文章中,我将描述其操作的一般原理,从开发人员的角度考虑该机制,并将其与应用更新的旧方法(我们称之为基于恢复的方法)进行比较。以下所有内容仅对纯AOSP才适用,因为特定的实现取决于供应商。



基于恢复的OTA



Android的更新以zip存档的形式提供,其中包含基于块的更新。在KitKat时代,这只是由随附脚本复制到设备上的一组文件。我不会详细介绍该模式,我将简要描述其操作的基本原理:



  • zip存档由系统下载到设备;
  • 系统重启进入恢复模式;
  • 检查更新与设备的兼容性及其签名;
  • 如果一切正常,则执行zip存档中updater-script
  • 在更新过程中,设备可能会重启几次(例如,更新设备树);
  • 如果一切顺利,请启动新固件。


此方案有哪些缺点?



  • 需要为OTA存档保留足够的内部内存。/ cache部分用于此目的一些供应商使用/数据,但这很少见。结果,给用户留下了更少的空间(是的,应用程序仍然可以使用/缓存分区中的空间,但是有一些限制)。
  • 重新启动和应用更新需要时间,这对于某些类型的设备(例如,智能电视)可能至关重要。
  • 中断更新过程可能会导致启动循环
  • 无法回滚到旧固件版本。


这种不便之处使您可以绕过无缝升级方法。让我们看看它是如何工作的。



无缝A / B OTA



实现无缝A / B更新所需的关键组件和机制



  • 闪存的插槽标记; 
  • 与加载程序交互,管理插槽状态
  • 系统守护程序update_engine ;
  • 生成包含更新的zip存档。本文将不考虑这一方面。


插槽



A / B OTA的基本原理是 投放。所有需要更新的分区(可以是任何分区,而不仅仅是系统分区)必须位于两个副本中,否则必须位于插槽中。在Android实现支持2个时隙,这被命名为B,分别。系统从当前插槽启动并运行,第二个仅在更新时使用。具有插槽名称的后缀将添加到节名称中。



下表是比较在设备上组织分区的两个选项的表。 所有插槽分区均标有slotselect挂载选项, 以便系统可以选择正确的插槽。根据描述它们的位置,可能是fstab

图片



dts



更改分区表



  • B /缓存不再需要。现在,可以将更新保存在/ data中,或立即将其刷新到不活动的插槽中(更多内容在下面)。 
  • 恢复部分也不再使用。但是, 恢复模式  仍然存在,例如,有必要将设备重置为出厂设置(这可能会导致 救援人员)。还是所谓的。通过adb手动更新(sideload。 恢复ramdisk 现在位于 启动分区中,内核已共享。
  • (android/recovery) cmdline ‑ skip_initramfs.


乍一看,这样的方案似乎不是最佳的,因为有必要为系统分配两倍的空间。但是我们摆脱了 / cache,这意味着我们已经节省了很多内存。因此,系统将比恢复选项花费更多



A / B更新的主要优点是能够 流式传输固件。正是它确保了用户的无缝透明更新:要更新设备,只需重新引导到新插槽即可。在这种模式下,无需预先下载zip存档,而占用/ data中的空间。相反,系统会立即从专门准备的文件(有效负载)中写入数据块。,请参见下文)插入无效插槽的每个部分。从实现的角度来看,我们是预先下载更新还是立即将更新流传输到插槽,这没有什么区别。



插槽具有以下状态:



  • active-活动插槽,系统将在下次重新引导时从中加载;
  • 可引导-更新已成功刷新到插槽中,已验证,哈希总和匹配等;
  • 成功-系统能够成功引导到新插槽;
  • 无法启动-插槽已损坏。在开始升级过程之前,系统始终将插槽标记为不可引导


这两个插槽均可 启动 并 成功,但只有一个处于活动状态



引导加载程序在选择插槽时的算法:

图片

  • 引导加载程序检测到有一个或多个 可引导插槽
  • 从中选择活动插槽(或优先级最高的插槽)。
  • 如果系统成功启动,则该插槽将标记为 Success  and  active
  • 否则,该插槽将标记为不可引导,并且系统将重新引导。




在更新期间更改插槽状态:

图片



与Seamless A / B配合使用所需的组件。



boot_control



为了支持A / B更新,供应商必须实现特殊的HAL接口-boot_control它允许您更改插槽的状态并获取有关它们的信息。对于外部工作(例如,通过adb shell进行),使用了实用程序-bootctl该接口用作OS与引导加载程序之间的通信方式。



update_engine



整个A / B电路 的主要组成部分。处理下载,流更新,验证签名等。通过boot_control更改插槽状态。允许您控制设备更新过程:暂停,继续,取消。

该组件是从ChromeOS转到Android的,已经使用了一段时间。 AOSP将update_engine维护为静态侧载程序集。这就是恢复中使用的方式,因为此模式不支持动态链接。



此组件的过程可以分为以下步骤:



  • 将更新加载到插槽中。您可以从以前下载的更新包中下载它,也可以直接通过Internet通过http / https下载它。在下载过程中,将检查签名,公钥已在设备上(/system/etc/update_engine/update-payload-key.pub.pem);
  • 验证下载的更新并比较哈希值;
  • 执行安装后脚本。 


Service Pack结构:



2009-01-01 00:00:00 .....          360          360  META-INF/com/android/metadata
2009-01-01 00:00:00 .....          107          107  care_map.txt
2009-01-01 00:00:00 .....    384690699    384690699  payload.bin
2009-01-01 00:00:00 .....          154          154  payload_properties.txt
2009-01-01 00:00:00 .....         1675          943  META-INF/com/android/otacert


  • care_map.txt-由update_verifier使用(请参见下文);
  • payload_properties.txt-在有效载荷内部包含哈希和数据大小
  • payload.bin-更新包,包含所有节的块,元数据,签名。


update_engine_client



用于管理update_engine守护程序的客户端可以由供应商直接调用以应用更新。



update_verifier



实用程序,用于在首次启动时检查系统的完整性(带有活动标记的插槽 ,但尚未 成功)。完整性控制是使用dm-verity内核模块实现的如果检查成功,该实用程序会将当前插槽标记为 成功否则,系统将重新启动到旧插槽中。验证care_map.txt文件中指定的块



UpdateEngineApi



有一个用于实现供应商更新服务的Java API还有一个这样的服务实现例子



让我们看一下AOSP中的A / B更新构建示例。为此,请编辑目标平台的Makefile:



#  A/B
AB_OTA_UPDATER := true
#    :
AB_OTA_PARTITIONS := boot system vendor
#  
PRODUCT_PACKAGES := update_engine update_engine_client update_verifier
#  recovery
TARGET_NO_RECOVERY := true
#,       cache:
#BOARD_CACHEIMAGE_PARTITION_SIZE := ...
#BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ...


调用make otapackage之后,我们将获得包含更新的zip存档。以这种形式,它已经适用于侧载模式。我们可以重启进入恢复状态,并调用adb sideload ota.zip此方法便于调试。



在生产系统中应用更新通常是特定于供应商的。最简单的方法是上传payload.bin到一个HTTP服务器和呼叫update_engine_client直接



通话示例:



update_engine_client \
--payload=http://path/to/payload.bin \
--update \
--headers=" \
FILE_HASH=ozGgyQEddkI5Zax+Wbjo6I/PCR8PEZka9gGd0nWa+oY= \
FILE_SIZE=282344983 \
METADATA_HASH=GLIKfE6KRwylWMHsNadG/Q8iy5f786WTatvMdBlpOPg= \
METADATA_SIZE=26723"


payload_properties.txt文件内容传递到headers参数logcat中,您可以查看更新进度。如果通过--follow开关,则进度将在stdout中复制



结论



新的更新机制的优势显而易见:



  • 系统更新在后台进行,而不会中断用户的工作。是的,您仍然需要重新引导(到新插槽),但是它  比在恢复中重新引导来应用更新快得多;
  • 引导循环的可能性降到最低(没有人无法避免实现中的错误)。更新过程可以中断,不会以任何方式影响活动插槽;
  • 可以回滚到以前的固件版本。即使由于某种原因更新失败,系统也会简单地返回到旧版本。
  • 多亏了流媒体,设备更新速度更快;
  • 根据实现的不同,您可以将用户完全排除在更新过程之外。


在缺点中,我要指出两点:



  • A / B OTA取决于当前磁盘布局,因为更新是在系统运行时进行的。也就是说,无法使用已更改的分区来滚动更新。
  • 实现的相对复杂性。


但是,在我看来,专业人士胜过一切。顺便说一句,在我们最近发布的设备中,我们正在使用A / B OTA更新。



All Articles