2. OTA 基础架构

理解 Android OTA 的稳定性问题,第一步不是看日志,而是把“升级到底改了哪些分区、由谁执行、失败后如何回退”这条链路建立起来。Android 的 OTA 并不是简单替换一个系统镜像,而是围绕分区布局、启动控制、升级执行器和校验器共同构成的一套可恢复机制。分区体系决定了升级的物理边界,A/B 与 A-only 决定了回退策略,Recovery 与 update_engine 决定了执行路径,update_verifier 则决定了升级后能否被确认“真正可用”。

一、Android 分区体系:升级的物理边界

Android 设备通常包含 boot、system、vendor、product、dtbo、vbmeta、userdata、misc、metadata 等分区。其中与 OTA 强相关的核心分区如下:

  • boot:包含内核与 ramdisk,决定启动第一阶段;
  • system / vendor / product:构成 Android 运行时的主要只读镜像;
  • vbmeta:存放 AVB 校验元数据,校验失败会直接阻断启动;
  • misc:A-only 方案中用于写入 recovery 命令和升级状态;
  • userdata:用户数据区,通常不参与整包替换,但可能涉及 metadata 加密与回退;
  • slot 元数据:A/B 方案中记录当前活动槽位、成功标记与重试次数。

OTA 包本质上是一组针对这些分区的操作指令集合。整包升级会重写完整镜像,差分包则基于旧镜像做块级或文件级补丁。无论哪种形式,升级失败往往不是“包坏了”这么简单,而是某个分区的写入、校验或启动标记没有按预期完成。

二、A/B 与 A-only:两种回退哲学

A-only 方案只有一个系统槽位,升级时通常进入 Recovery 模式,把新镜像写入 system、vendor 等分区。它的优点是分区占用小、实现简单;缺点是升级过程中设备不可用,且一旦写入中断或新系统无法启动,回退能力有限,往往依赖 Recovery 中的备份或重新刷写。

A/B 方案则维护两套可启动槽位(slot_a、slot_b)。当前运行在 slot_a 时,OTA 把新版本写入 slot_b,完成后把 slot_b 标记为 active,重启后尝试从 slot_b 启动。如果启动失败,bootloader 会根据重试计数自动切回 slot_a。这种“后台写入 + 重启切换 + 失败回退”的机制,是 A/B OTA 稳定性的核心。

对比项 A-only A/B
槽位数量 1 套 2 套
升级执行环境 Recovery 模式 正常系统内 update_engine
升级期间可用性 不可用 可继续使用
失败回退 依赖 Recovery / 重刷 自动切回旧槽位
存储开销 较低 较高
典型状态记录 misc 分区 slot 元数据 + bootloader

三、Recovery 模式与 update_engine 的角色分工

Recovery 是一个独立的最小系统,负责在 A-only 方案中解析 OTA 包、校验签名、写入分区并更新 misc 中的命令状态。它不依赖主系统,因此即使 system 损坏也能进入。常见命令包括 --update_package、--wipe_data 等,执行结果会写回 misc,供下次启动判断。

update_engine 是 A/B 方案中的升级执行器,运行在正常系统内。它从 OTA 服务端下载或读取本地升级包,按 payload 中的操作逐块写入非活动槽位,同时维护进度、校验和槽位标记。它的关键状态包括当前 slot、目标 slot、payload 校验结果、写入偏移和 markBootSuccessful 调用时机。

# A/B 升级关键状态示例
current_slot: _a
target_slot:  _b
payload_url:  https://ota.example.com/payload.bin
payload_size: 1073741824
payload_hash: 9f2c...e81a
status:       INSTALLING
progress:     0.62

update_verifier 则出现在升级完成后的首次启动阶段。它读取 dm-verity 或 AVB 相关元数据,对已写入的分区做抽样或完整校验,确认新槽位内容与预期一致。如果校验失败,系统会标记该槽位不可启动,触发回退。因此 update_verifier 不是“升级执行者”,而是“升级可信度的确认者”。

Android OTA 基础架构:分区、方案与执行角色 分区体系 boot / dtbo / vbmeta system / vendor / product misc / metadata / userdata slot 元数据(A/B) 升级方案 A-only 单槽位 · Recovery 执行 A/B 双槽位 · 后台写入切换 执行与校验角色 Recovery:A-only 升级执行 update_engine:A/B 写入 update_verifier:启动校验 OTA 升级与回退主流程 1. 获取 OTA 包 整包 / 差分包 2. 校验签名与哈希 payload 完整性 3. 写入目标分区 A-only / 非活动槽位 4. 标记启动槽位 active / retry count 5. 重启 首次启动 update_verifier 校验新槽位 / 新系统 dm-verity / AVB 抽样校验 校验失败 → 回退旧槽位 / Recovery 避免设备变砖

四、典型场景与排障切入点

场景一:A/B 设备升级后卡在开机动画。此时应优先确认 slot 元数据中的 successful 标记是否写入、retry_count 是否耗尽,以及 update_verifier 是否在启动日志中报出校验失败。若校验失败,问题通常出在 payload 写入不完整或 vbmeta 与 boot 不匹配。

场景二:A-only 设备进入 Recovery 后提示 status 7。这通常表示 OTA 包中的设备断言与当前设备不匹配,或 system 分区剩余空间不足。需要检查 misc 中的命令状态和 Recovery 日志中的具体分区写入错误。

场景三:差分包升级失败但整包成功。差分包依赖旧镜像的精确哈希,若设备曾做过局部修改或分区被重新刷写,源数据不匹配就会导致 patch 失败。此时应核对源版本号、分区哈希和 payload 属性。

排障顺序建议:先确认方案类型(A/B 还是 A-only),再确认执行角色(update_engine 还是 Recovery),最后确认校验角色(update_verifier / AVB / dm-verity)。顺序错了,日志会看得很乱。

五、常见误区与复盘

  • 误区一:把 update_engine 当成校验器。update_engine 负责写入和进度管理,真正的启动可信校验由 update_verifier 与 AVB 完成。
  • 误区二:认为 A/B 一定不会变砖。如果 bootloader 的槽位控制逻辑或 vbmeta 校验被破坏,回退同样可能失败。
  • 误区三:忽略 misc 分区。A-only 的升级命令和结果都记录在 misc,misc 异常会导致 Recovery 反复进入或无法继续。
  • 误区四:只看升级日志,不看首次启动日志。很多 OTA 稳定性问题发生在升级完成后的第一次启动,update_verifier 的输出才是关键证据。

把分区、方案、执行器和校验器四者串起来,才能在实际排障中快速定位问题属于“写入阶段”“切换阶段”还是“启动校验阶段”。这也是后续分析 OTA 失败日志、回退异常和升级卡死问题的基础框架。