LV001-OTA全景与设计目标
一、 OTA 是什么
1. OTA 的定义
OTA(Over-The-Air,空中下载)升级,是指设备通过无线或有线网络远程获取新固件并完成自我更新,全程无需返厂、无需连接烧录器、无需人工拆机干预。它解决的核心问题是:设备卖出去之后,固件 Bug 修复、功能迭代、安全补丁如何触达成千上万的在网设备。
一次完整的 OTA 升级可以概括为一行流水线:
检查更新 → 下载升级包 → 校验 → 写入存储 → 切换启动 → 确认生效 / 失败回滚2. OTA 与 IAP、ICP 的辨析
嵌入式领域有三个容易混淆的烧录/升级术语,它们的区别在于"谁来提供新固件、走什么通道":
| 术语 | 全称 | 通道 | 固件来源 | 典型场景 |
|---|---|---|---|---|
| ICP | In-Circuit Programming | SWD / JTAG 调试口 | 烧录器 | 产线烧录、开发调试 |
| IAP | In-Application Programming | 任意通信口(UART / USB / CAN…) | 上位机、调试助手 | bootloader 在线烧录 |
| OTA | Over-The-Air | 网络(Wi-Fi / 4G / 以太网 / LoRa…) | 远程服务器 | 量产设备远程升级 |
三者的关系可以这样理解:
- ICP 是"外科手术",需要接触硬件调试口,设备必须拿到手边
- IAP 是一种能力:应用程序在运行中自己擦写 Flash。OTA 的写入动作本质上就是 IAP
- OTA 是一种业务:在 IAP 能力之上,叠加了版本管理、远程分发、校验、回滚等一整套机制
一句话:IAP 是让芯片能自己写自己,OTA 是让设备能从云端拿新固件再自己写自己。本专题讨论的正是后者这套完整业务。
3. OTA 的适用对象
OTA 不是 Linux 设备的专利,从几 KB Flash 的单片机到车载域控制器都可以做 OTA,只是方案复杂度差异巨大:
- 资源受限 MCU(如 STM32F103):需要自己实现 Bootloader、选槽、回滚的全部机制,详见 LV022-MCU无BankSwap落地方案 与 LV025-MCU有BankSwap落地方案
- 带 MMU、跑 Linux 的应用处理器(如 RK3568、i.MX6ULL):U-Boot + 开源框架(SWUpdate / RAUC / Mender)已经把机制做成熟了,重点在方案选型与集成,详见 LV028-Linux平台OTA方案
二、 OTA 系统的角色与架构
一套 OTA 系统由三个角色构成:服务器端负责生产与分发升级包,传输通道负责可靠送达,设备端负责接收、校验、安装与自我恢复。
1. 服务器端
服务器端是整个 OTA 体系的"大脑",职责包括:
- 版本管理:维护固件仓库,记录每个版本适用的设备型号、硬件批次、区域
- 升级策略:决定"谁该升、什么时候升"——灰度发布、分组推送、强制升级
- 差分包生成:基于新旧版本镜像用 bsdiff 等算法预先生成差分包,减少设备下载流量
服务器端不一定是云端平台,小型项目里一台 HTTP 文件服务器加一个版本描述 JSON 就足够了。服务器端的详细设计见 LV031-发布与量产运维。
2. 传输通道
传输通道的唯一要求是可靠地把字节流送达设备,常见的有:
- HTTPS:最通用,自带 TLS 加密与证书体系,Linux 设备首选
- MQTT:适合 IoT 平台,借发布/订阅通道推送升级通知,固件本身一般仍走 HTTP 拉取
- 私有协议:MCU 外挂通信模组(ESP8266、4G 模组)时,常见"MCU 用 UART 逐块向模组要数据"的私有分块协议
除了这三类网络通道,OTA 还大量使用近场通道——UART(YMODEM)、USB DFU、CAN、BLE 等,多用于开发调试、产线与救砖,详见 LV013-升级通道协议。
通道层不保证的内容(包是否完整、是否被篡改、是否适配本机)由设备端自己校验,这是"不信任通道"的基本安全原则,详见 LV019-升级安全机制。
3. 设备端
设备端内部又分为三层,职责严格分离:
- App(业务应用):正常运行时负责查询更新、下载升级包、写入非活动槽、置升级标志。升级的主要工作其实发生在旧 App 还活着的时候
- OTA 代理:App 内部(或独立任务/进程)负责下载、分块校验、写 Flash 的逻辑模块
- Bootloader:设备上电的第一段代码,升级后负责校验新固件、决定启动哪个槽、失败时回滚。它是升级安全的最后防线,因此自身必须简单、稳定,通常不参与 OTA 更新
【注意】
Bootloader 不参与自身升级是通用原则:一旦 Bootloader 被刷坏,设备失去一切自救能力,只能拆机用调试口恢复。
三、 OTA 通用升级流程
无论 MCU 还是 Linux 平台,OTA 的流程骨架是一致的,差异只在每一步的实现手段。
1. 发现新版本
三种触发模式:
- 手动触发:用户主动点"检查更新"。服务器压力最小,但版本收敛最慢,适合有屏幕、有人操作的设备
- 设备轮询:设备定期向服务器请求版本描述文件(JSON / 私有格式),与本地版本比对。实现简单,服务器无状态,是绝大多数方案的选择
- 服务器推送:服务器通过 MQTT 等长连接主动通知设备升级。实时性好,适合需要统一调度的大规模设备群
发现新版本之后还有两个独立选择:要不要弹提示等用户确认、什么时候执行。它们与触发模式一起构成"升级在用户侧怎么发生"这个运营维度,三种选择的组合与取舍见 LV004-升级方案维度与选型 第四节。
版本比对不能只看版本号大小,还要匹配设备型号、硬件版本、区域、灰度白名单,防止把 A 型号的固件推给 B 型号。
2. 下载升级包
下载阶段的核心诉求是抗网络抖动:
- 断点续传:记录已下载偏移,网络中断后从断点继续,而不是从头再来
- 分块校验:边下载边按块校验(如每 4 KB 一个 CRC),尽早发现数据错误,避免整个包下完才发现损坏
- 写入位置:下载的固件必须写到非活动槽 / 暂存区,绝不能直接覆盖正在运行的系统
3. 校验升级包
下载完成后、置位升级标志之前,必须完成两道校验:
- 完整性校验:对整个镜像计算 SHA-256(或 CRC32),与包内元数据中的预期值比对
- 真实性校验:用设备内置的厂商公钥对升级包签名做验签,确认包确实来自厂商而非攻击者
任何一道不通过,丢弃升级包并上报失败原因,设备继续运行旧固件,本次升级对用户无感。
4. 请求切换
校验通过后,App 把"请下次从 B 槽启动"这个意图写入 Flash 中的启动参数区(boot control),然后主动重启。从这一刻起,决策权移交给 Bootloader。参数区的字段设计与读写时序是 OTA 可靠性的核心,详见 LV016-选槽与回滚机制。
5. Bootloader 引导与确认
重启后 Bootloader 读取参数区,发现有待试用的新固件:
(1)再次校验新槽镜像(不信任 App 之前的结论,独立复查)
(2)校验通过则引导新固件,并记录"已尝试启动次数"
(3)新固件启动后进行自检(关键外设、通信链路、看门狗喂养正常)
(4)自检通过 → 新固件自己写参数区"确认转正"(mark good),升级完成
(5)自检失败或反复重启超过次数上限 → Bootloader 切回旧槽,回滚到旧固件
这个"试用—确认—超限回退"的机制保证了:哪怕新固件有严重 Bug 导致系统无法正常工作,设备也能自己退回旧版本,不会变砖。
四、 OTA 的核心设计目标
设计任何一套 OTA 方案时,所有取舍都围绕下面四个目标展开,后文每一篇的机制分析也都会回到这四条上。
1. 原子性
升级的任意时刻掉电,设备都必须处于一个确定的状态:要么还是完整的旧系统,要么是完整的新系统,绝不能是"刷了一半"的中间态。原子性靠"先写非活动区、校验通过后再原子地翻标志位"来保证。
2. 可回滚
新固件自身有缺陷(能启动但功能异常、或反复崩溃)时,设备必须能自动退回旧版本。回滚的前提是旧固件的副本在升级全程不被破坏——这正是 A/B 双槽方案相比单槽复制方案的本质优势。
3. 安全性
升级通道是攻击者刷入恶意固件的天然入口,必须设防:
- 来源可信:数字签名 + 设备端公钥验签
- 传输可信:TLS 加密,防中间人篡改
- 版本可信:防回滚机制,禁止降级到已知有漏洞的旧版本
4. 资源可控
OTA 不能影响设备正常业务:下载在后台限速进行,写 Flash 避开业务高峰,重启切换尽量快。Linux 上 A/B 方案可以做到"用户无感升级",MCU 上则通常需要接受一次短暂重启。
五、 本专题的结构与阅读路径
本专题 11 篇按"原理 → 机制 → 平台方案 → 工程实践"四层组织,编号顺序即阅读顺序。四层之间是抽象递减、落地递增的关系:原理层建立共同语言,机制层讲平台无关的做法,平台层落到具体芯片,实践层处理发布与运维。
1. 各篇职责与权威主题
每个主题在全专题只有一个权威出处,其余篇章只给结论并跳转,不重复展开。下表第四列即该篇的权威主题——要找某个机制的完整设计与代码,直接查这一列。
| 层 | 篇目 | 回答的问题 | 权威主题 |
|---|---|---|---|
| 原理 | LV001-OTA全景与设计目标 | OTA 是什么、系统由谁构成 | 角色架构、通用流程骨架、四个设计目标 |
| 原理 | LV004-升级方案维度与选型 | 有哪些做法、怎么选 | 存储布局对比、XIP 与 RAM 运行、触发与安装时机、升级期间可用性根因、选型决策树 |
| 机制 | LV007-升级包格式与传输机制 | 包长什么样、怎么可靠送达 | 包头格式、断点续传、分块校验、Flash 擦写约束 |
| 机制 | LV010-差分算法对比与嵌入式移植 | 差分怎么真正落地 | 差分算法对比、嵌入式移植、压缩选型、差分与 A/B 组合、补丁生成策略 |
| 机制 | LV013-升级通道协议 | 字节流走哪条线 | UART / USB DFU / CAN UDS / BLE / 网络模组的协议实现、通道分层原则 |
| 机制 | LV016-选槽与回滚机制 | 装完怎么保证还能启动 | 启动参数区、双副本掉电安全、选槽决策、回滚状态机、看门狗配合 |
| 机制 | LV019-升级安全机制 | 怎么防止被刷入假固件 | 签名验签、信任链、防回滚、包加密、密钥管理 |
| 平台 | LV022-MCU无BankSwap落地方案 | 老 MCU 上怎么落地 | STM32F103 分区规划、四种方案、Bootloader 完整工程、App 改造清单、开源 Bootloader 复用 |
| 平台 | LV025-MCU有BankSwap落地方案 | 硬件能帮掉什么忙 | Bank Swap 地址映射、STM32L4/L5 实现、各系列差异、i.MX RT |
| 平台 | LV028-Linux平台OTA方案 | Linux 上怎么用现成机制 | U-Boot bootcount、eMMC / NAND 分区、SWUpdate / RAUC / Mender、dm-verity、FIT 签名 |
| 工程实践 | LV031-发布与量产运维 | 怎么发布、怎么测、怎么运维 | 版本描述文件、发布流水线、灰度分批、异常注入测试、量产 FAQ |
2. 阅读路径
(1)只想搞懂原理:LV001 → LV004。两篇读完即可参与方案讨论,不必深入机制层。
(2)在 MCU 上落地:LV001 → LV004 → LV007 → LV013 → LV016 → LV019 → LV022 或 LV025。最后一步取决于芯片是否支持硬件 Bank Swap:不支持走 LV022,支持走 LV025。差分与流量敏感时再补 LV010。
(3)在 Linux 上落地:LV001 → LV004 → LV016 → LV019 → LV028 → LV031。机制层可跳过 LV007 与 LV013——Linux 的传输由框架与 HTTP 栈接管,不需要自己设计包格式与通道协议。
(4)排查线上升级故障:先看 LV031 的 FAQ 表定位失败阶段,再到 LV016 的异常场景推演对照掉电点行为,最后按失败阶段回到对应机制篇(下载 / 校验 → LV007,写槽 → LV022 或 LV028,启动 → LV016,验签 → LV019)。
3. 本篇的定位
本篇是原理层的入口,只做三件事:说清 OTA 与 IAP / ICP 的区别(第一节)、给出"服务器—通道—设备"的角色架构(第二节)、走一遍平台无关的流程骨架(第三节)。第四节提出的原子性、可回滚、安全性、资源可控四个目标,是后续每一篇做取舍时的共同判据——机制层的每套设计,最终都要回答"它满足了这四条中的哪几条、牺牲了什么"。
本文档由 markdowncli 技能辅助生成