实施虚拟 A/B - 补丁

Cherry-pick 以下补丁可解决以下已知问题。

侧载时正确检查可分配空间

在具有小于 *2 * sum(更新组大小)* 的超级分区的虚拟 A/B 设备上旁加载完整的 OTA 包可能会失败,并在恢复日志/tmp/recovery.log中显示以下内容:

The maximum size of all groups with suffix _b (...) has exceeded half of allocatable space for dynamic partitions ...

以下是日志示例:

[INFO:dynamic_partition_control_android.cc(1020)] Will overwrite existing partitions. Slot A may be unbootable until update finishes!
[...]
[ERROR:dynamic_partition_control_android.cc(803)] The maximum size of all groups with suffix _b (2147483648) has exceeded half of allocatable space for dynamic partitions 1073741824.

如果您遇到此问题,请选择CL 1399393 ,如果设备不使用恢复作为引导,则重建并刷新引导分区或恢复分区。

修复合并期间的分段错误

应用 OTA 更新后,在 VAB 合并过程中,调用update_engine_client --cancel会导致CleanupPreviousUpdateAction崩溃。当markSlotSuccessful迟到时,也存在潜在的野指针错误。

这已通过添加StopActionInternal函数得到解决。 CleanupPreviousUpdateAction在销毁时取消挂起的任务。它维护一个变量,用于跟踪消息循环中待处理任务的任务 ID。在销毁时,挂起的任务被取消以避免段错误。

确保在您的 Android 11 源代码树中进行以下更改,以修复合并期间update_engine中的SIGSEGV崩溃:

  • CL 1439792 (CL 1439372 的先决条件)
  • CL 1439372CleanupPreviousUpdateAction :在销毁时取消挂起的任务)
  • CL 1663460 (修复markSlotSuccessful来晚时可能出现的野指针错误)

修复 VAB 不正确的插槽切换,发布 OTA 更新

在 Android 11 及更高版本中,无法在 OTA 更新后同步设备中的插槽开关可能会使设备进入不可用状态。如果您的IBootControl HAL 的插槽切换实现执行写入,您必须立即刷新这些写入。如果写入未刷新,并且设备在合并开始后重新启动,但在硬件可以刷新插槽开关写入之前,设备可能会恢复到前一个插槽并且无法启动。

有关示例代码解决方案,请查看此 CL: CL 1535570

防止 update_engine 过早合并

当设备启动(Android 11 及更高版本)并完成启动时, update_engine调用ScheduleWaitMarkBootSuccessful()WaitForMergeOrSchedule() 。这将启动合并过程。但是,设备将重新启动到旧插槽。由于合并已经开始,因此设备无法启动并无法运行。

将以下更改添加到您的源代码树。请注意,CL 1664859 是可选的。

  • CL 1439792 (CL 1439372 的先决条件)。
  • CL 1439372CleanupPreviousUpdateAction :在销毁时取消挂起的任务)
  • CL 1663460 (修复markSlotSuccessful来晚时可能出现的野指针错误)
  • CL 1664859 (可选 - 为unittest添加CleanupPreviousUpdateAction

防止因跳过元数据而导致数据丢失或损坏

在 Android 11 及更高版本中,如果存储设备具有易失性回写缓存,则在某些情况下,已完成合并的元数据会被跳过,从而导致数据丢失或损坏。

状况:

  1. 在完成一组异常的合并操作后,调用了merge_callback()
  2. 元数据已在跟踪合并完成的 COW 设备中更新。 (此对 COW 设备的更新已彻底刷新。)

结果:由于最近合并的存储设备的缓存没有被刷新,系统崩溃了。

请参阅以下内容以实施解决方案:

确保正确的 dm-verity 配置

在 Android 11 及更高版本中,可能会无意中为设备配置以下 dm-verity 选项:

  • CONFIG_DM_VERITY_AVB=y在内核中
  • 引导加载程序配置为使用任何验证模式(例如AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE ),但没有AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO

使用此设备配置,任何验证错误都会导致 vbmeta 分区损坏,并导致非 A/B 设备无法运行。同样,如果合并已开始,A/B 设备也可能无法运行。仅使用AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO验证模式。

  1. 在内核中设置CONFIG_DM_VERITY_AVB=n
  2. 将设备配置为使用AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO模式。

有关更多信息,并且作为实践问题,请参考 verity 文档:处理 dm-verity 错误

在紧急系统关闭期间跳过验证工作以响应 I/O 错误

在 Android 11 及更高版本中,如果调用了紧急系统关机(如热关机的情况),则 dm 设备可以处于活动状态,而块设备无法再处理 I/O 请求。在这种状态下,由新的 dm I/O 请求或已经在进行中的请求处理的 I/O 错误可能导致验证错误状态,这是一种误判。

要在系统关闭时跳过验证工作以响应 I/O 错误,请使用以下命令:

CL 1847875 (在关机期间跳过验证工作以响应 I/O 错误)

确保 DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED 关闭

运行 4.19 或更早版本内核的 Android Go 设备可能在其内核配置中包含DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED=y 。此设置与虚拟 A/B 不兼容,并且已知当两者同时启用时会导致罕见的页面损坏问题。

对于内核 4.19 及更早版本,通过在内核配置中设置CONFIG_DM_ANDROID_VERITY_AT_MOST_ONCE_DEFAULT_ENABLED=n来禁用它。

对于内核 5.4 及更高版本,代码已被删除并且配置选项不可用。