14、升级状态机与日志:升级状态流转、last_install日志分析、升级失败原因排查
做OTA升级开发,最怕什么?
不是代码写不出来,而是升级失败了,你连怎么失败的都不知道。
我早期做这个模块时,就吃过这个亏。客户反馈说“升级到一半手机重启了”,我盯着logcat看了半天,发现关键的日志已经被重启冲掉了。后来我才意识到,last_install日志才是真正的“黑匣子”。
今天我们就来彻底搞懂升级状态机是怎么跑的,日志怎么看,失败原因怎么定位。
14.1 升级状态机:系统升级的“骨架”
升级状态机,说白了就是系统在升级过程中经历的各个阶段。每个阶段都有明确的入口和出口,状态之间通过事件驱动流转。
Android的Recovery模式里,核心状态机定义在install.cpp中。我把它简化成下面这张图,你一看就明白:
这张图里,我特意把失败状态画成了红色。为什么?因为实际项目中,80%的问题都出在从VERIFY到INSTALL这个阶段。
核心要点:状态机不是单向的。失败后可以重试,但重试次数有限。默认是3次,超过后进入永久失败状态,需要人工干预。
14.2 last_install日志:升级的“黑匣子”
每次升级结束后,Recovery会把关键信息写入/cache/recovery/last_install文件。这个文件不会因为重启而丢失,是排查问题的第一手资料。
我习惯在分析问题时,先看这个文件。它记录了:
- 升级结果:成功还是失败
- 失败原因:错误码和错误描述
- 升级包路径:从哪里读取的升级包
- 时间戳:每个阶段的时间点
一个典型的last_install日志长这样:
# 示例:last_install 日志
install_result: 0
install_path: /data/ota_package/update.zip
install_recovery: --update_package=/data/ota_package/update.zip
install_time: 2024-03-15 14:23:45
install_stage: 3
install_error: 0
这里install_result: 0表示成功。如果非0,那就是失败。常见的错误码我整理了一张表:
| 错误码 | 含义 | 常见原因 |
|---|---|---|
| 0 | 成功 | - |
| 1 | 校验失败 | 升级包损坏、签名不匹配 |
| 2 | 设备空间不足 | /cache分区满了 |
| 3 | 安装脚本错误 | updater-script语法问题 |
| 4 | 设备兼容性错误 | 升级包与设备型号不匹配 |
| 5 | 未知错误 | 需要进一步分析logcat |
我的小技巧:如果last_install里显示install_error: 1,别急着怀疑升级包。先检查一下设备时间是否正确。我遇到过好几次,设备时间被重置到1970年,导致签名校验失败。
14.3 升级失败原因排查:实战三板斧
升级失败了,别慌。按照我总结的“三板斧”来排查,大部分问题都能定位:
第一板斧:看last_install
这是最快的方式。直接cat /cache/recovery/last_install,看错误码。如果错误码是0但升级失败了,那说明问题出在升级完成后、系统重启的阶段。这时候要看logcat。
第二板斧:看recovery日志
Recovery模式下的日志保存在/cache/recovery/log。这个文件记录了Recovery启动后的所有输出,包括挂载分区、校验升级包、执行脚本等细节。
我曾经遇到一个案例:升级包校验通过,但安装到一半失败了。last_install里显示错误码3。我打开recovery日志,发现是updater-script里有一条mount命令写错了分区路径。这种问题,不看日志根本猜不到。
第三板斧:看kernel日志
如果前两个日志都没问题,那可能是底层驱动或硬件问题。这时候要看dmesg或/proc/last_kmsg。比如,升级过程中突然断电,或者emmc有坏块,都会在kernel日志里留下痕迹。
注意:有些设备在升级失败后会自动重启,导致recovery日志被清空。这时候,last_install是唯一能保留的信息。所以,永远不要只依赖logcat。
14.4 状态机与日志的联动分析
理解了状态机,再看日志就清晰多了。每个状态对应日志中的一段记录。我习惯把日志按状态分段看:
- IDLE阶段:检查是否有升级包,日志里会打印
check_for_update_package - VERIFY阶段:校验签名和哈希,日志里会打印
verify_package和校验结果 - INSTALL阶段:执行安装脚本,日志里会打印
install_package和每一步的执行结果 - REBOOT阶段:准备重启,日志里会打印
reboot和重启参数
举个例子,如果日志停在verify_package: failed,那问题就在校验阶段。如果日志停在install_package: 50%,那问题就在安装过程中。
实战经验:我遇到过一种情况,日志显示install_package: 100%,但设备就是重启不了。后来发现是misc分区写坏了,导致重启指令没被正确保存。这种问题,看last_install是看不出来的,必须结合kernel日志。
14.5 总结
升级状态机是骨架,last_install日志是血肉。两者结合,才能准确判断问题出在哪里。
我个人习惯在开发阶段,每次升级后都自动备份last_install和recovery日志到/data分区。这样即使设备反复重启,也能保留现场。
嗯,最后提醒一句:别等到线上出问题了才去学怎么看日志。平时多看看正常升级的日志,知道“正常”长什么样,出问题时才能一眼看出“异常”。
公众号:蓝海资料掘金营,微信deep3321