3. OTA升级原理:升级流程与AB系统机制
OTA升级,说白了就是让设备自己给自己动手术。我刚开始接触这个领域时,总觉得这玩意儿挺玄乎——设备怎么能在运行的同时把自己给换了?后来拆开一看,其实核心就两件事:升级流程和分区切换。
这一章,咱们就把OTA升级的底裤扒干净。你理解了这些,后面分析日志时才能一眼看出问题出在哪个环节。
3.1 OTA升级的标准流程
一个完整的OTA升级,通常走五步。我习惯把这五步记成「下校解写切」——虽然不好听,但好记。
- 下载:从服务器拉取升级包
- 校验:确认包没被篡改或损坏
- 解压:把压缩的镜像释放出来
- 写入:把镜像刷到备用分区
- 切换:让系统下次从新分区启动
每一步都可能翻车。我在项目里见过最离谱的,是下载完校验通过,解压也正常,结果写入时断电了——设备直接变砖。嗯,后面我们会专门讲怎么从日志里定位这类问题。
3.1.1 下载阶段
设备通过HTTP/HTTPS或MQTT从OTA服务器拉取升级包。这里有个关键点:断点续传。
我曾经遇到一个案子,设备在弱网环境下反复下载失败。日志里全是「Download interrupted at 47%」。后来发现是下载模块没实现断点续传,每次失败都得从头下。你想想看,一个100MB的包,在信号不好的地方,永远下不完。
3.1.2 校验阶段
校验通常用MD5、SHA256或者签名验证。设备会把下载好的包算一遍哈希,跟服务器下发的哈希值对比。
这里有个坑:校验时机。有些方案是下载完才校验,有些是边下边校验。边下边校的好处是能提前发现坏包,但实现复杂一些。
3.1.3 解压阶段
升级包通常是压缩的——gzip、lzma或者差分包。解压需要内存和CPU。嵌入式设备资源有限,这里容易出问题。
我记得有个项目,解压时总是报「Out of memory」。查了半天,发现是解压算法需要的内存峰值超过了设备可用内存。后来换了流式解压,边解边写,才搞定。
3.1.4 写入阶段
把解压后的镜像写入备用分区。这一步最危险,因为涉及擦写Flash。
Flash写入有几个特点:
- 写入前必须先擦除
- 擦除是按块(Block)进行的
- 写入过程中断电会丢数据
我见过最惨的一次,写入到90%时电源被拔了。重启后系统发现两个分区都坏了——主分区是旧的但被标记为脏,备用分区只写了一半。这就是典型的「双分区全废」场景。
3.1.5 切换阶段
写入完成后,系统会修改启动标志,让下次启动加载新分区。这一步通常很快,但决定成败。
切换策略有两种:
- 立即切换:写入完直接重启进新分区
- 延迟切换:标记新分区,下次冷启动时生效
我个人更倾向延迟切换。为什么呢?因为立即切换如果新系统起不来,设备就彻底失联了。延迟切换至少还能远程回滚。
3.2 分区表与AB系统机制
AB系统,说白了就是准备两套系统分区。A分区跑着,B分区等着。升级时刷B,刷完切到B启动。这样就算B起不来,还能回A。
分区表就是告诉系统:你的A区在哪、B区在哪、数据区在哪。我习惯把分区表理解成一张「房产证」——每个分区的地址、大小、用途都写得清清楚楚。
3.2.1 典型AB分区布局
| 分区名称 | 起始地址 | 大小 | 用途 |
|---|---|---|---|
| boot_a | 0x00000000 | 2MB | A系统内核 |
| boot_b | 0x00200000 | 2MB | B系统内核 |
| system_a | 0x00400000 | 64MB | A系统文件 |
| system_b | 0x04400000 | 64MB | B系统文件 |
| data | 0x08400000 | 128MB | 用户数据 |
| misc | 0x10400000 | 1MB | 启动控制信息 |
misc分区特别重要。它里面存着当前应该启动哪个分区、升级状态、回滚次数等信息。我见过不少故障,就是因为misc分区被写坏了,系统不知道往哪启动。
3.2.2 AB系统的启动逻辑
系统启动时,Bootloader会读misc分区,判断该启动A还是B。逻辑其实很简单:
if (misc.boot_partition == PARTITION_A) {
try_boot(PARTITION_A);
if (boot_success) {
// 正常启动
return;
} else {
// A启动失败,切到B
misc.boot_partition = PARTITION_B;
try_boot(PARTITION_B);
}
} else {
// 类似逻辑处理B分区
}
这里有个关键机制:启动计数。系统启动后会递增一个计数器,如果用户正常使用,计数器会清零。如果系统反复重启,计数器一直增加,超过阈值就触发回滚。
3.3 AB系统升级流程全景图
下面这张图,把整个AB升级流程串起来了。我建议你多看几遍,后面分析日志时,脑子里要有这张图。
3.4 常见失败场景与日志特征
有了上面的基础,咱们来看看实际项目中常见的翻车场景。我整理了一个表格,方便你对照日志快速定位。
| 失败阶段 | 典型日志关键词 | 可能原因 | 我见过的案例 |
|---|---|---|---|
| 下载 | Download failed, Timeout, HTTP 404 | 网络不稳定、服务器地址错误 | 设备在工厂内网,OTA服务器配成了外网域名 |
| 校验 | Checksum mismatch, Signature invalid | 包损坏、证书过期、哈希算法不匹配 | 服务器更新了哈希算法,设备端没同步 |
| 解压 | Decompress failed, Out of memory | 内存不足、压缩包格式错误 | 差分包基版本不对,解出来全是乱码 |
| 写入 | Write error, Flash erase failed | Flash坏块、写入超时、电源不稳 | 某批次Flash有坏块,写入到固定地址就挂 |
| 切换 | Boot count exceeded, Rollback triggered | 新系统启动失败、misc分区损坏 | 新内核驱动不兼容硬件,反复重启后回滚 |
3.5 小结
OTA升级的核心就两件事:流程要完整,AB要可靠。流程上,下载、校验、解压、写入、切换,一步都不能省。AB机制上,关键是要保证「失败了还能回来」。
你分析日志时,先看升级卡在哪一步,再看那一步的日志有没有异常。如果看到「Rollback」相关的关键词,别慌——那是AB系统在保护你的设备。