# OTA 稳定性改造实施路线 ## 1. 目标与原则 本路线的核心目标是:先利用现有 App OTA 发布一个风险尽可能小的桥接版本,建立可靠的升级控制、状态上报和灰度发布能力;随后验证系统级 OTA,修复 Kernel 和 Mini FOTA 中无法通过 App OTA 解决的问题;最后根据 Flash 空间和硬件条件决定是否实施 A/B 分区。 实施过程中遵循以下原则: - 第一次桥接升级尽量小,不同时引入大量业务改动。 - 固件升级和音频资源更新相互独立,任何一方失败都不影响另一方。 - 每个阶段先小批量验证,通过验收门槛后再扩大范围。 - 所有升级必须可追踪、可暂停,并准备串口烧录救援方案。 - 在系统 OTA 和回滚能力验证完成前,不假设设备具备可靠的自动恢复能力。 ## 2. 当前能力边界 当前生成的 `fota.bin` 只包含 `customer_app.bin`,属于 App-only OTA,可更新正常业务程序,但不能更新: - Kernel; - Mini FOTA 系统; - Bootloader; - 分区表; - `customer_fs` 文件系统镜像; - GNSS、DSP、RF 等底层固件。 当前设备没有明确的标准 A/B 应用分区。Mini FOTA 会下载并写入 `customer_app`,底层备份和回滚能力尚未得到完整验证。设备进入 FOTA 后,如果下载地址长期不可用,存在持续重启和无法进入正常业务程序的风险。 ## 3. 推荐实施顺序 ```text 阶段 0:建设发布基础设施和救援能力 ↓ 阶段 1:发布最小 App 桥接版本 ↓ 阶段 2:独立上线音频资源同步 ↓ 阶段 3:实验室验证系统级 OTA ↓ 阶段 4:更新 Kernel 和 Mini FOTA ↓ 阶段 5:建立启动健康确认和失败恢复 ↓ 阶段 6:评估并实施 A/B 或备份恢复方案 ``` --- ## 4. 阶段 0:发布基础设施和救援准备 ### 目标 在不升级设备的前提下,降低第一次桥接 OTA 的发布风险。 ### 工作内容 1. 固定 OTA 文件地址,发布后禁止覆盖、删除或改名。 2. 对固件下载服务器增加可用性、响应时间和错误率监控。 3. 为每个固件保存以下发布信息: - 产品型号; - 硬件版本范围; - 软件版本; - 构建时间; - Git commit; - 文件大小; - SHA-256; - 下载地址。 4. 服务端支持: - 测试设备白名单; - 分批灰度; - 暂停下发; - 防止重复下发; - 成功率和失败率统计。 5. 准备专用测试设备和串口烧录救援流程。 6. 使用当前旧 FOTA 测试以下场景: - 弱网和网络切换; - DNS 失败; - 下载前断网; - 下载过程中断网; - HTTP 404、500 和超时; - 重复下发相同升级命令; - 下载服务器临时不可用。 ### 验收门槛 - 可以只向指定测试设备下发 OTA。 - 可以随时停止后续批次。 - 固件文件能够长期稳定访问。 - 能通过设备 ID、任务 ID 和版本号追踪升级结果。 - 已验证串口烧录恢复流程。 --- ## 5. 阶段 1:最小 App 桥接版本 ### 目标 整理正常 App 内的 OTA 控制逻辑,为后续系统 OTA、资源同步和结果追踪建立可靠入口。 ### 5.1 统一 OTA 启动入口 - OTA 只允许由一个明确的业务入口启动。 - `parse_command()` 只解析和校验消息,不执行延时、删除文件、重启或调用 FOTA。 - 删除当前解析阶段和处理阶段可能重复启动 OTA 的设计。 - 检查并处理 `ql_fullfota_app_start()` 的返回值。 - OTA 准备期间拒绝或合并重复升级命令。 ### 5.2 建立 OTA 状态机 建议至少包含以下状态: ```text IDLE RECEIVED VALIDATED ACCEPTED PRECHECKING STARTING REBOOTING FIRST_BOOT SUCCEEDED FAILED ``` 状态变化和任务信息应持久化,避免重启后丢失上下文。 ### 5.3 校验升级命令 升级前至少校验: - OTA 任务 ID; - 目标版本; - 产品型号; - 硬件版本; - 固件类型; - URL 协议; - 域名白名单; - 允许的端口和路径; - 声明的文件大小; - 声明的 SHA-256; - 是否为重复升级; - 是否属于未授权降级。 说明:正常 App 可以校验命令和服务器声明,但实际固件由重启后的旧 Mini FOTA 下载。在 Mini FOTA 支持 SHA-256 前,App 不能替代它对最终下载内容进行完整哈希校验。 ### 5.4 OTA 前置检查 调用 FOTA 前检查: - SIM 和网络注册状态; - PDP 是否正常; - DNS 是否能够解析; - 下载地址是否可以建立连接; - HTTP 是否返回 200; - `Content-Length` 是否合理; - 电池、电压或外部供电是否满足升级条件; - 当前是否正在执行通话等关键业务。 推荐执行顺序: ```text 解析命令 → 校验任务 → 网络和 URL 预检查 → 持久化任务信息 → 向服务器上报已接受 → 确认消息发送完成 → 调用 FOTA 接口 → 重启进入 Mini FOTA ``` 预检查只能过滤明显的 URL、404 和服务器故障,不能保证重启后的 Mini FOTA 网络仍然正常。 ### 5.5 升级结果补报 新版本第一次启动后读取持久化的 OTA 任务信息,上报: - 任务 ID; - 原版本; - 目标版本; - 当前实际版本; - 开始和结束时间; - 最终结果; - 最后错误码; - 是否发生异常重启。 暂时无法联网时,应保留结果并在下次连接后补报。 ### 5.6 音频与 OTA 解耦 - 删除 OTA 前调用 `app_file_check_del()` 的行为。 - FBF 下载和 updater 安装期间不清空现有音频。 - 新 APP 启动、版本确认等于 OTA 目标且网络就绪后,才删除服务器管理的音频并立即补下载。 - `barge_in_cute.mp3` 纳入删除和补下载范围;发布前必须确认固定资源地址可用。 - 音频下载失败不得影响固件升级结果。 - 固件升级失败不得破坏原有可用音频。 ### 第一版明确不做 - 不修改分区表; - 不更新 Kernel 或 Mini FOTA; - 不修改 Bootloader; - 不替换整个 `customer_fs`; - 不同时进行大规模业务重构; - 不引入独立音频 manifest、SHA-256 或签名协议。 ### 验收门槛 - 单条 OTA 命令只触发一次 FOTA。 - 无效 URL、错误型号和重复版本不会导致重启。 - 设备重启前能够上报已接受状态。 - 新版本启动后能够补报最终结果。 - OTA 下载失败时原有音频不被删除。 - 新版本确认成功后,服务器管理的音频被刷新且缺失文件能够在后续联网时继续补下载。 - 小批量设备升级成功率达到预定标准后才能扩大灰度。 --- ## 6. 阶段 2:独立音频资源同步 ### 目标 在不更新整个 `customer_fs.bin` 的情况下,安全地下发新增音频,并确保资源失败不会影响设备核心业务。 ### 6.1 资源清单 每个资源至少记录: - 资源版本; - 文件名; - 下载 URL; - 文件大小; - SHA-256; - 是否必需; - 最低 App 版本。 ### 6.2 单文件下载流程 ```text 检查 LittleFS 剩余空间 → 下载到临时文件 → 检查实际文件大小 → 校验 SHA-256 → 校验文件基本格式 → 原子重命名为正式文件 → 更新本地资源状态 ``` ### 6.3 可靠性要求 - 不能仅以“文件存在”判断下载成功。 - 下载中断后不能留下被当作有效资源的半文件。 - 新文件校验失败时保留原文件。 - 音频同步在后台低优先级执行,不阻塞 MQTT 上线。 - 每个文件独立记录重试次数,采用退避重试。 - 写入前计算 LittleFS 剩余空间并保留安全余量。 - 7 条超时提示音只从已校验有效的文件中随机选择。 - 新增资源全部不可用时,继续使用原 `tts_error.mp3` 作为兜底。 ### 验收门槛 - 断网、空间不足或校验失败不会破坏现有音频。 - 半文件在重启后能够被识别并重新下载。 - 资源服务器不可用时设备仍能正常连接 MQTT。 - 新增 6 条音频全部写入后,LittleFS 仍保留规定的安全空间。 --- ## 7. 阶段 3:实验室验证系统级 OTA ### 目标 确认 SDK 的系统 FOTA 是否能够安全更新 Kernel、Mini FOTA 和相关底层组件。 ### 验证内容 1. 确认系统升级包的生成工具、输入文件和版本基线。 2. 确认升级包实际包含和修改的分区。 3. 确认是整包升级还是指定旧版本到新版本的差分升级。 4. 验证暂存空间、RAM 和 Flash 空间是否满足要求。 5. 验证以下异常场景: - 下载前断网; - 下载中断网; - Flash 写入期间断电; - URL 返回 404 或 500; - 文件被截断; - checksum 或签名错误; - 固件型号不匹配; - 版本基线不匹配; - 新系统无法正常启动; - 连续多次升级失败。 6. 确认失败后设备是否能恢复旧系统或进入明确的恢复模式。 此阶段可以与桥接版本研发并行,但系统 OTA 的正式上线必须在桥接版本稳定之后。 ### 验收门槛 - 明确系统包的生成、签名、校验和发布流程。 - 明确升级会修改哪些分区。 - 关键断电和断网测试不会造成设备永久失联。 - 失败原因可以被持久化和上报。 - 已具备批量发布所需的恢复方案。 --- ## 8. 阶段 4:更新 Kernel 和 Mini FOTA ### 目标 解决当前 App OTA 无法修复的底层下载、重试、恢复和安全问题。 ### 工作内容 1. 持久化 FOTA 失败次数。 2. 设置单次启动和跨重启的最大重试次数。 3. 网络错误使用指数退避,不再主要依靠重启设备进行重试。 4. 区分并记录以下错误: - 网络注册失败; - PDP 激活失败; - DNS 失败; - TCP/TLS 连接失败; - HTTP 非 200; - 下载超时; - 文件格式错误; - Flash 擦除或写入失败; - checksum 或签名失败。 5. 超过重试上限后清除 FOTA 状态,恢复进入旧 App。 6. 正常 App 启动后上报失败阶段和错误码。 7. 评估并启用可靠的断点续传。 8. 支持备用下载地址或可靠的服务端容灾。 9. 使用 HTTPS,并正确校验证书。 10. 对升级包进行数字签名验证。 11. 验证产品型号、硬件版本和升级基线。 “超过重试上限后恢复旧 App”应优先于 A/B 实施,用于直接解决当前可能无限重启的问题。 ### 验收门槛 - 永久不可用的 URL 不会导致设备无限重启。 - 达到重试上限后能够恢复正常 App 或进入明确恢复模式。 - 异常原因能够被持久化并在联网后上报。 - 非法、损坏或型号不匹配的固件不会被安装。 --- ## 9. 阶段 5:启动健康确认与失败恢复 ### 目标 不再把“固件写入完成”直接等同于“升级成功”。 新版本启动后至少检查: - 文件系统挂载成功; - 关键配置读取成功; - 关键线程正常运行; - 看门狗状态正常; - 网络能够注册; - MQTT 能够连接; - 设备版本和 OTA 任务可以正常上报; - 没有连续崩溃或反复重启。 只有达到健康条件后才确认升级成功。 如果多次启动仍不能确认健康: - 具备 A/B 时回滚到旧分区; - 不具备 A/B 时恢复备份 App 或进入恢复模式。 --- ## 10. 阶段 6:A/B 或备份恢复方案 ### 优先方案:标准 A/B ```text app_a app_b boot metadata 持久化升级状态 启动健康确认 自动回滚 ``` A/B 实施前必须确认: - Flash 是否能够容纳两个完整 App; - Bootloader 是否支持分区选择和回滚; - 分区表如何迁移; - 现有设备是否能够在线完成分区变更; - 工厂烧录包和售后工具是否同步支持新布局。 ### 空间不足时的次优方案 ```text 单 App 分区 + 下载暂存区 + 旧 App 备份区 + 持久化失败计数 + 启动健康确认 + 明确恢复模式 ``` 如果现有设备必须修改分区表才能实现上述方案,不应默认可以通过当前 App OTA 安全完成。部分设备可能需要工厂重新烧录。 --- ## 11. 灰度发布建议 每个阶段建议按以下顺序发布: 1. 开发板和可串口救援设备; 2. 内部测试设备; 3. 少量真实网络环境设备; 4. 1% 灰度; 5. 5% 灰度; 6. 20% 灰度; 7. 全量发布。 每一批次至少观察: - 命令接收率; - 开始升级率; - 下载成功率; - 平均重试次数; - 最终版本到达率; - 异常重启率; - 设备重新上线时间; - 音频和文件系统异常率。 出现以下任一情况应暂停后续批次: - 设备持续重启; - 升级后无法上线; - 失败率超过预设阈值; - 出现无法自动恢复的设备; - 固件文件、下载服务或 MQTT 服务异常; - 发现型号、版本或升级包对应错误。 ## 12. 最终结论 当前最合适的路线不是立即实现 A/B,而是先发布 OTA-ready 工厂基线和最小 FULLOTA2,修复 OTA 入口、命令校验、预检查、状态持久化和结果补报。音频删除已从 OTA 前移到新 APP 版本确认成功且网络就绪之后,并由现有缺失文件下载器补回;后续再升级为带版本、SHA-256 和原子替换的独立资源清单。然后在实验设备上验证系统级 OTA,通过系统 OTA 修复 Mini FOTA 的恢复和安全校验问题;最后根据未来 Flash 空间决定是否采用标准 A/B。