一、问题处理思路
1.1 dm-verity问题处理流程
(1)回读整个system分区并与正确的分区进行比较。确认system.img中的数据是否已损坏?若是,则执行步骤2或步骤3。若不是,则执行步骤4。
(2)将mmc / ufs寄给供应商,以检查物理块是否损坏。
(3)擦除分区并下载软件。
(4)做更多的压力测试以验证system.img。如将数据从system复制到userdata分区以加快复制速度。若可以复现该问题,则删除损坏的物理块,请转到步骤3。若不能复现问题,则重复步骤4,或继续观察设备。如果复现问题并重复执行步骤3和步骤4超过 3次,且物理块始终相同,请返回到步骤2。如果物理块并不总是相同,则转到步骤5。
(5)检查dmesg日志,看是否有任何mmc驱动程序/UFS驱动程序故障。如果有,则向mmc/ufs team提交case协助分析。否则执行步骤6。
(6)mmc/ufs硬件/驱动程序基本被排除嫌疑,此时可以从DDR角度进行检查。在此设备上进行Qblizzard压力测试。如果测试结果良好,则执行步骤7。如果测试fail,则向DDR team提交case协助分析。
(7)观察损坏时,在第一次使设备崩溃后收集ramdump信息。添加以下debug信息:
1 | static int verity_handle_err() |
通过ramdump,可以从稳定性的角度进行一些完整性检查,例如任务列表遍历,与vmlinux进行只读区域比较,cache/ ddr比较,vma列表和rbtree比较等等。如果发现有问题,则在完成步骤6的情况下,转到步骤9。如果没有发现任何错误,转到步骤8。
(8)与硬件团队进行交换测试。
(9)尝试禁用CPR,提高APC电压,提高vdd-mx,以确保AP缓存稳定运行。
(10)如果烧录GSI时出现下方开机异常,则需要烧录禁用avb的vbmeta。
1 | avb_slot_verify.c:432: DEBUG: Loading vbmeta struct from partition 'system'. |
参考指令如下:
1 | fastboot --disable-verification flash vbmeta[_a/b] vbmeta.img |
1.2 处理dm-verity错误
通过设计,哈希树验证错误是由HLOS而非引导程序检测到的。AVB提供了一种方法,该方法通过avb_slot_verify()函数中的hashtree_error_mode参数指定应如何处理错误。可能的值包括:
AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE表示HLOS将使当前插槽无效并重新启动。在具有A / B的设备上,这将导致尝试引导另一个插槽(如果标记为可引导),或者导致无法引导任何操作系统的模式(例如某种形式的修复模式)。在Linux中,这需要使用CONFIG_DM_VERITY_AVB构建的内核。
AVB_HASHTREE_ERROR_MODE_RESTART表示操作系统将在不使当前插槽无效的情况下重新启动。请谨慎使用此模式,因为如果每次启动都遇到相同的哈希树验证错误,则可能会导致启动循环。
AVB_HASHTREE_ERROR_MODE_EIO表示将向应用程序返回EIO错误。
AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO表示使用RESTART或EIO模式,具体取决于状态。此模式实现状态机,默认情况下使用RESTART,并且将AVB_SLOT_VERIFY_FLAGS_RESTART_CAUSED_BY_HASHTREE_CORRUPTION传递给avb_slot_verify()时,该模式会转换为EIO。当检测到新的操作系统时,设备将转换回重新启动模式。
为此,需要持久存储-特别是这意味着传递的AvbOps将需要实现read_persistent_value()和write_persistent_value()操作。使用的持久值的名称为avb.managed_verity_mode,并且需要32个字节的存储空间。
AVB_HASHTREE_ERROR_MODE_LOGGING意味着将记录错误,并且损坏的数据可能返回给应用程序。此模式仅应用于诊断和调试。除非允许验证错误,否则不能使用它。
在hashtree_error_mode中传递的值实际上是通过androidboot.veritymode,androidboot.veritymode.managed和androidboot.vbmeta.invalidate_on_error内核命令行参数通过以下方式传递给HLOS的:
- | androidboot.veritymode | androidboot.veritymode.managed | androidboot.vbmeta.invalidate_on_error |
---|---|---|---|
AVB_HASHTREE_ERROR_MODE_RESTART_AND_INVALIDATE | enforcing | (unset) | yes |
AVB_HASHTREE_ERROR_MODE_RESTART | enforcing | (unset) | (unset) |
AVB_HASHTREE_ERROR_MODE_EIO | eio | (unset) | (unset) |
AVB_HASHTREE_ERROR_MODE_MANAGED_RESTART_AND_EIO | eio or enforcing | yes | (unset) |
AVB_HASHTREE_ERROR_MODE_LOGGING | ignore_corruption | (unset) | (unset) |
该表的唯一例外是,如果在顶级vbmeta中设置了AVB_VBMETA_IMAGE_FLAGS_HASHTREE_DISABLED标志,则将androidboot.veritymode设置为disable,并取消设置androidboot.veritymode.managed和androidboot.vbmeta.invalidate_on_error。
二、一些问题
2.1 分区位置读取错乱导致 Verified Error
(1)异常uart日志:
1 | [3830] read from system_a, 0x40 bytes at Offset 0x12b7fffc0, partition size 1696096256 |
partition.xml内容如下:
1 | <configuration> |
(2)解决方案:
验证分区前从分区表中获取分区位置,重新设置index。
kernel/lk/platform/msm_shared/avb/libavb/avb_ops.c
2.2 32位系统中system分区过大导致越界
(1)uart异常日志:
1 | [ 6.561417] device-mapper: uevent: version 1.0.3 |
(2)解决方案:
修改vbmeta_offset的类型(size_t -> uint64_t)
external/avb/libavb/avb_slot_verify.c
2.3 未打开FEC宏导致dm-verity找不到参数
(1)uart异常日志:
1 | [ 0.000000] device-mapper: init: will configure 1 devices |
(2)解决方案:
在kernel config中打开CONFIG_DM_VERITY_FEC宏
kernel/msm-4.4/arch/arm64/configs/project_defconfig
2.4 boot分区超过heap size加载失败
(1)uart异常日志:
1 | [partition_get_index]find boot_b index 38 |
(2)解决方案:
修改boot分区大小时同步修改AVB_HEAP_SZ
bootable/bootloader/lk/platform/common/boot/avb20/load_vfy_boot_ab.c
2.5 分区slot后缀未过滤导致无法加载
(1)uart异常日志:
1 | [3590] Loading image system_a |
(2)解决方案:
验证分区时移除slot后缀,兼容a/b和non-a/b系统。
kernel/lk/platform/msm_shared/avb/libavb/avb_slot_verify.c