3、AB分区升级流程:升级包下载、升级包校验、写入非活跃分区、切换槽位、重启生效
AB分区的升级流程,说白了就是一套「先准备好,再切换」的原子操作。我最早接触这个机制时,觉得它跟双缓冲渲染有点像——你在后台画好下一帧,然后瞬间切过去。嗯,本质上确实如此。
整个流程可以拆成五个关键步骤。每一步都有坑,我一个个说。
3.1 升级包下载
升级包通常是一个完整的系统镜像,也可能是差分包。下载阶段,系统会把包写入cache分区或data分区的临时目录。
这里有个容易被忽略的点:下载过程中不能断电。我遇到过一台设备,下载到80%时用户拔了电源,结果cache分区文件系统损坏,连正常系统都起不来了。后来我们强制要求:下载前先校验剩余电量,低于30%直接拒绝下载。
3.2 升级包校验
校验不只是检查文件完整性。它通常包含三层:
| 校验层级 | 校验内容 | 失败处理 |
|---|---|---|
| 完整性校验 | SHA256 / MD5 哈希比对 | 删除包,重新下载 |
| 签名校验 | RSA/ECDSA 公钥验签 | 标记包无效,记录日志 |
| 元数据校验 | 版本号、硬件兼容性、分区大小 | 拒绝升级,提示不兼容 |
签名校验是安全底线。我记得有一次,测试团队拿了一个自编译的镜像刷进去,签名校验没通过,系统直接拒绝写入。嗯,这堵墙必须砌死。
分区大小 ≥ 镜像大小 + 预留空间。
3.3 写入非活跃分区
这是AB分区最核心的一步。系统当前运行在slot A,那么升级包就写入slot B。反过来也一样。
写入过程不是简单的dd复制。它通常包含:
- 分区格式化:先擦除非活跃分区的数据,避免残留数据干扰
- 镜像写入:按块写入,每写一块校验一次CRC
- 增量更新:如果是差分包,需要先读取活跃分区的基线数据,再应用补丁
写入过程中如果发生意外(比如掉电),最多是非活跃分区损坏,活跃分区纹丝不动。这就是AB分区最大的价值——写入操作与运行环境完全隔离。
关键指标:写入速度通常受限于闪存性能。我见过最慢的设备,写入一个2GB的system镜像花了12分钟。这种情况下,我会建议用户插着电源升级,或者做成后台静默升级。
3.4 切换槽位
写入完成后,系统不会立刻切换。它需要做两件事:
- 标记新分区为可启动:在misc分区或vbmeta中写入slot B的启动计数
- 设置启动次数:通常设为1,表示「下次启动尝试一次,失败就回滚」
切换槽位的操作是元数据写入,不是物理跳线。它修改的是bootloader读取的启动参数。我习惯把这个过程叫做「扳道岔」——火车(bootloader)看到道岔指向B,就开进B轨道。
sync()和fdatasync()能解决大部分问题。
3.5 重启生效
最后一步,重启。bootloader读取槽位标记,发现slot B被标记为「待启动」,于是加载slot B的内核和ramdisk。
重启后,系统会做一次启动验证:
- 如果启动成功,用户空间的服务正常拉起,系统会把slot B标记为「启动成功」
- 如果启动失败(比如内核panic、init崩溃),bootloader会在超时后自动回滚到slot A
这个回滚机制是AB分区最让人放心的设计。你想想看,就算新系统炸了,旧系统还在那里,重启一次就回来了。
3.6 整体流程图
下面这张图把整个流程串起来了。你可以看到,每一步都有校验和回退路径,保证系统在任何异常情况下都能恢复。
3.7 关键参数速查表
最后,我整理了一份常用参数表。你在实现或调试AB分区升级时,可以直接参考。
| 参数 | 典型值 | 说明 |
|---|---|---|
| 升级包存储路径 | /cache/update.zip 或 /data/ota_package/ |
取决于分区大小和策略 |
| 校验算法 | SHA256 + RSA-2048 | 完整性+签名双重保障 |
| 写入块大小 | 4096 bytes | 对齐闪存页大小,提升写入性能 |
| 槽位标记位置 | misc 分区偏移 0x200 |
bootloader 启动时读取 |
| 启动验证超时 | 30 秒 | 超时未确认则触发回滚 |
嗯,以上就是AB分区升级的完整流程。每一步都不复杂,但串联起来就是一个非常健壮的升级体系。你想想看,从下载到重启,每个环节都有校验和回退,这才是工业级系统该有的样子。