2. 升级中断场景分析:断电中断、通信中断、存储空间不足、版本校验失败、硬件异常
做固件升级最怕什么?我最怕升级到一半,啪,断了。不管是断电还是通信断了,设备变砖的风险就在眼前。这一章咱们把五种常见的中断场景掰开揉碎了讲。你想想看,只有知道敌人长什么样,才能设计出靠谱的恢复策略。
核心观点:升级中断不是「会不会发生」的问题,而是「什么时候发生」的问题。好的恢复策略,必须覆盖每一种中断场景。
2.1 断电中断
这是最要命的场景。没有之一。我在一个智能电表项目里遇到过,设备正在写 Flash 的时候突然断电,结果分区表被写了一半,整个系统再也起不来了。
断电中断的核心问题在于:写操作不是原子的。Flash 写入是按页进行的,一页通常是 256 字节或 512 字节。如果写到一半断电,这一页的数据就是残缺的。
我曾经踩过的坑:以为加个大电容就能解决所有问题。后来发现电容只能撑几十毫秒,而写一页 Flash 需要 5-10 毫秒,写一个完整固件需要几秒到几十秒。电容根本扛不住。
断电中断的典型后果:
- 引导区损坏——设备彻底变砖,连 bootloader 都进不去
- 固件镜像不完整——校验失败,回退机制失效
- 文件系统损坏——如果升级涉及文件系统操作,断电可能导致整个文件系统崩溃
我的建议:至少保留两个固件分区——一个运行分区,一个备份分区。升级时先写备份分区,写完后做原子切换。这样即使断电,运行分区还是好的。
2.2 通信中断
无线升级最头疼的就是这个。信号不稳定、连接超时、数据包丢失……说白了,通信中断不是「会不会」的问题,而是「多久一次」的问题。
我记得有个项目用的是 BLE 升级,用户走到隔壁房间,信号一弱,升级就断了。更麻烦的是,通信中断后设备处于「半升级」状态——旧固件已经被擦除了,新固件只收到一半。
通信中断的几种常见形式:
| 中断类型 | 典型原因 | 恢复难度 |
|---|---|---|
| 连接超时 | 网络延迟、服务器响应慢 | 低——可重连续传 |
| 数据包丢失 | 无线干扰、信号弱 | 中——需要重传机制 |
| 连接断开 | 设备移动、网关重启 | 高——需要重新握手 |
| 协议栈崩溃 | 内存泄漏、驱动异常 | 极高——可能需要复位 |
怎么应对?我个人习惯用「断点续传」的思路。把固件分成固定大小的块,每块都带 CRC 校验。接收端记录已收到的块号,重连后从断点继续发。
// 断点续传的块管理结构
typedef struct {
uint32_t total_blocks; // 总块数
uint32_t received_blocks; // 已接收块数
uint32_t block_size; // 每块大小
uint32_t crc_table[MAX_BLOCKS]; // 每块CRC
uint8_t bitmap[MAX_BLOCKS/8]; // 接收位图
} ResumeContext;
2.3 存储空间不足
这个场景容易被忽视。你想想看,嵌入式设备的 Flash 和 RAM 都是寸土寸金。新固件比旧固件大 10%,可能就装不下了。
我在一个物联网网关项目里遇到过:固件从 512KB 升级到 640KB,但 Flash 分区只留了 600KB 的空间。结果升级到 90% 的时候,写入失败,系统直接崩溃。
存储空间不足的三种情况:
- Flash 空间不够——新固件太大,放不进目标分区
- RAM 空间不够——解压或校验时需要临时缓冲区,RAM 不够用
- 文件系统碎片——虽然总空间够,但连续空间不够
关键原则:升级前必须做空间预检。不要等到写的时候才发现空间不够。预检包括:目标分区大小、临时缓冲区大小、备份分区大小。
2.4 版本校验失败
校验失败分两种:一种是固件本身有问题,另一种是传输过程中数据被篡改。
我记得有一次,客户反馈升级后设备反复重启。查了半天,发现是固件包的 CRC 校验码在传输过程中被代理服务器修改了。设备校验通过,但实际运行的是被篡改的固件。
版本校验的完整链条:
- 固件包完整性校验——使用 SHA-256 或 CRC32 验证包是否完整
- 签名校验——使用 RSA 或 ECDSA 验证固件来源是否可信
- 版本号校验——新版本必须高于当前版本,防止回滚攻击
- 兼容性校验——新固件是否与当前硬件版本、配置兼容
我曾经犯过的错:只做了 CRC 校验,没做签名校验。结果有人伪造了固件包,设备升级后直接变砖。从那以后,我所有项目都强制要求签名校验。
2.5 硬件异常
这个场景最不可控。Flash 写入超时、看门狗复位、电源纹波过大、温度过高导致 Flash 写入失败……硬件异常的种类太多了。
硬件异常的特点是:随机性强,复现困难。你在实验室测一百次都没问题,到现场就出问题。
常见的硬件异常场景:
| 异常类型 | 表现 | 应对策略 |
|---|---|---|
| Flash 写入超时 | 写操作卡死,无法返回 | 加超时机制,超时后复位重试 |
| 看门狗复位 | 升级过程中看门狗超时 | 升级期间喂狗,或暂停看门狗 |
| 电源异常 | 电压波动导致写入错误 | 加电压检测,低于阈值时暂停 |
| 温度超限 | 高温下 Flash 写入不可靠 | 温度检测,超限时延迟升级 |
我的经验:硬件异常很难完全避免,但可以通过「重试机制」来降低影响。比如 Flash 写入失败后,等 100ms 再重试,最多重试 3 次。大部分硬件异常都是瞬时的,重试就能过去。