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 1439372 (
CleanupPreviousUpdateAction
:在销毁时取消挂起的任务) - 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 1439372 (
CleanupPreviousUpdateAction
:在销毁时取消挂起的任务) - CL 1663460 (修复
markSlotSuccessful
来晚时可能出现的野指针错误) - CL 1664859 (可选 - 为
unittest
添加CleanupPreviousUpdateAction
)
防止因跳过元数据而导致数据丢失或损坏
在 Android 11 及更高版本中,如果存储设备具有易失性回写缓存,则在某些情况下,已完成合并的元数据会被跳过,从而导致数据丢失或损坏。
状况:
- 在完成一组异常的合并操作后,调用了
merge_callback()
。 - 元数据已在跟踪合并完成的 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
验证模式。
- 在内核中设置
CONFIG_DM_VERITY_AVB=n
- 将设备配置为使用
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 及更高版本,代码已被删除并且配置选项不可用。