# PX3 升级流程说明 > 范围:仅梳理 PX3 本地 MPU 升级和 MCU 升级 > 代码:`D:\zdCode\zhongqi_px3` > 分支:`zhongqi_th7_px3_plus_security`,HEAD `8497c2da8` ## 1. 总体说明 PX3 当前有两条升级链路: | 类型 | 触发方式 | 新版包 | 旧版兼容 | | -------- | ------------ | ---------------- | ---------------------------- | | MPU/系统升级 | 开机或介质挂载后自动扫描 | `update_mpu.zip` | 受属性控制的 `update.img` | | MCU 升级 | 工程菜单手动触发 | `update_mcu.zip` | ZIP 不存在时兼容 `m3/cortex-*.bin` | 如果 `update_mpu.zip` 就走验签流程,如果有 `update.img` 就走老的升级流程, PX3 计划保留的 MPU 新旧兼容与 RK3568 不同: - RK3568:外层都叫 `update.zip`,根据包内是否存在 `ValidationFile.ini` 判断新旧格式。 - PX3 业务目标:按外层文件名分流,优先级是 `update_mpu.zip → update.img`。 - 当前 `1224` 源码尚未完全符合该目标:扫描函数仍主动检查 `update.zip`,独立裸 `update.img` 默认还会被属性开关拦截。 --- ## 2. MPU 升级流程 ### 2.1 触发和扫描 `RKUpdateReceiver` 在以下场景启动本地升级扫描: | 场景 | 延时 | |---|---:| | 系统启动完成 `BOOT_COMPLETED` | 20 秒 | | 存储介质挂载 `MEDIA_MOUNTED` | 7 秒 | | 特定 USB 状态变化 | 5 秒 | 扫描目录: ```text /data/media/0/ Environment.getExternalStorageDirectory()/ /mnt/external_sd0/ /mnt/usb_storage/ ``` 如果根目录没有命中,还会扫描 `/mnt/usb_storage` 的一级子目录。 ### 2.2 MPU 业务目标优先级 | 优先级 | 文件 | 处理方式 | |---:|---|---| | 1 | `update_mpu.zip` | 解压、验签内层 `update.img`、产品检查、RK image 升级 | | 2 | `update.img` | 属性允许时执行产品检查和 RK image 升级 | | 3 | 其他文件 | 不处理 | 服务发现第一个候选文件后立即返回。 ### 2.3 当前源码与目标的差异 当前 `getValidFirmwareImageFile()` 实际扫描顺序为: ```text update_mpu.zip → OTA_PACKAGE_FILE(默认 update.zip)→ update.img ``` 另外,`1224` 版本处理独立裸 `update.img` 时会读取: ```text persist.sys.update.show ``` - 属性为 `false`:直接忽略裸 `update.img`。 - 属性为 `true`:才允许继续产品检查和升级。 - 当前仓库中,唯一把该属性设置为 `true` 的位置在 `update_mpu.zip` 处理分支。 - `1009`、`1010` 等早期压缩版本没有该属性拦截。 因此,当前源码不能直接表述为“已经实现 `update_mpu.zip → update.img` 两级兼容”。要达到业务目标,还需要停止扫描 `update.zip`,并明确恢复裸 `update.img` 的允许条件。 ### 2.4 新版 `update_mpu.zip` 包结构: ```text update_mpu.zip ├── update.img └── ValidationFile.ini ``` `ValidationFile.ini` 当前读取: ```ini sign=<十六进制 RSA 签名> ``` 流程: ```text 检测到 update_mpu.zip ↓ 设置 persist.sys.update.show=true ↓ 解压到 update_mpu.zip 所在目录 ↓ 读取 update.img 和 ValidationFile.ini ↓ 计算 update.img 的 SHA-256 ↓ 使用硬编码 RSA-2048 公钥和 SHA256withRSA 验签 ↓ JNI 读取 update.img 产品名 ↓ 与 ro.product.model 比较 ↓ 弹出升级确认页 ↓ 用户确认 ↓ RecoverySystem.installRKimage() ↓ 写入 /cache/recovery/last_flag 和 command ↓ 执行 sync,等待 2 秒 ↓ 重启 Recovery 安装 update.img ``` Recovery 命令: ```text --update_rkimage= --locale=<当前语言> ``` 当前验签失败分支缺少 `return`,仍会打开确认页,并把外层 `update_mpu.zip` 当成标准 OTA 包再次校验。这是现有缺陷,不是兼容流程。 ### 2.5 旧版裸 `update.img` ```text 检测到 update.img ↓ 读取 persist.sys.update.show ├── false:忽略,不弹确认页 └── true:继续 ↓ 检查镜像产品名是否匹配 ro.product.model ↓ 用户确认 ↓ installRKimage() ↓ 重启 Recovery 安装 ``` 裸 `update.img` 没有新增 RSA 验签,只做产品名检查。 ### 2.6 MPU 结果处理 服务下次启动时读取: ```text /cache/recovery/last_flag ``` | 标记 | 含义 | |---|---| | `success$path=...` | Recovery 报告升级成功 | | `updating$path=...` | 上次升级未形成成功状态 | 当前结果流程尚未闭环: - 成功/失败提示 Activity 的启动代码被注释。 - 没有统一结果广播。 - 升级包删除没有稳定执行。 - 新版包验签后用户取消,升级锁没有释放。 - Recovery 写回 `last_flag` 的实现不在当前项目中。 --- ## 3. MCU 升级流程 ### 3.1 页面入口 ```text Pro 版本设置页 ↓ 在硬件版本位置 3 秒内连续点击 10 次 ↓ 工程菜单 ProjectMenuActivity ↓ 升级菜单 UpgradeMainActivity ↓ 选择“M3程序升级” ↓ ZhongQiM3UpdateActivity ↓ 用户确认 ↓ IM0ManagerService.sendUpdateRequest(type, flashType) ↓ ImplM0ManagerService ↓ MonitorM0Update.sendUpdateRequest() ``` 升级通过 Binder 发起。广播只用于 MCU 返回最终结果后通知页面。 ### 3.2 介质和文件 | 介质 | `flashType` | 文件路径 | |---|---:|---| | U 盘 | `0` | `/mnt/usb_storage/update_mcu.zip` | | TF 卡 | `1` | `/mnt/external_sd0/update_mcu.zip` | 当前正常 UI 没有传入 `FLASHTYPE=1`,所以实际默认走 U 盘。 代码保留 TF 卡分支,但页面状态检测历史上使用 `/mnt/external_sd`,通讯服务读取 `/mnt/external_sd0`,两边路径不一致。 `update_mcu.zip` 只在介质根目录查找,不递归搜索子目录。 ### 3.3 包结构 ```text update_mcu.zip ├── cortex-gdm4.bin ├── cortex-m3.bin └── ValidationFile.ini ``` 根据设备类型,实际刷写文件是 `cortex-gdm4.bin` 或 `cortex-m3.bin`。 ### 3.4 解压和验签 ```text 开始 sendUpdateRequest() ↓ 删除 /sdcard/zhongqi_mcu_update/ ↓ 解压 update_mcu.zip 到该目录 ↓ 根据 MCU 版本选择实际目标固件 ↓ 计算 SHA-256 ↓ 读取 ValidationFile.ini 中的 sign ↓ 使用硬编码 RSA-2048 公钥和 SHA256withRSA 验签 ├── 失败:返回 -2 └── 成功:选择实际固件并进入协议传输 ``` 当前算法先计算文件 SHA-256,再把摘要传给 `SHA256withRSA`,实际相当于: ```text RSA-Sign(SHA256(SHA256(payload))) ``` 制包工具必须使用相同的双重摘要方式。 ### 3.5 固件选择 页面选择升级类型: | MCU 版本 | 升级类型 | |---|---:| | `110px02m3`、`110rv01m3` | `0x01` | | `ae6501` | `0x0F` | | 其他版本 | `0x1F` | 通讯服务选择实际文件: | MCU 版本 | 实际传输文件 | |---|---| | `110px02m3`、`110rv01m3` | `cortex-m3.bin` | | 其他情况 | `cortex-gdm4.bin` | 当前工作区已改为使用同一个目标文件名完成验签和传输:M3 设备验签并传输 `cortex-m3.bin`,其他设备验签并传输 `cortex-gdm4.bin`。页面按 `-` 分割版本字符串后判断,通讯服务直接比较原始版本字符串,这个差异仍需后续统一。 ### 3.6 MCU 协议 | 消息号 | 名称 | 作用 | |---:|---|---| | `0xE1` | `MSG_REQUEST_UPDATE` | MCU 主动请求升级 | | `0xE2` | `MSG_SEND_UPDATE_REQUEST` | 主机发送固件总长度 | | `0xE3` | `MSG_REQUEST_UPDATE_DATA` | MCU 按偏移请求固件数据 | | `0xE4` | `MSG_RECV_UPDATE_RESULT` | MCU 返回最终结果 | 主时序: ```text Android 完成解压和验签 ↓ E2:主机发送固件总长度 ↓ MCU 返回状态和最大分包长度 ↓ E3:MCU 发送 offset(4B) + length(2B) ↓ 主机按偏移读取并返回固件数据 ↓ 重复 E3 直到传输完成 ↓ MCU 校验并执行升级 ↓ E4:MCU 返回最终结果 ↓ 主机回复 ACK ↓ 通讯服务发送 ACTION_M0_UPDATE_FILE 广播 ↓ 升级页面显示结果 ``` 收到 MCU 主动 E1 后,当前代码会再次删除临时目录、解压、验签并发送 E2,可能与已经开始的 Binder 升级会话冲突。 ### 3.7 状态码 E2 阶段: | 返回值 | 含义 | |---:|---| | `-2` | ZIP 不存在、验签失败或目标固件不可读 | | `-1` | 发送失败或等待响应超时 | | `0` | MCU 不支持升级 | | `1` | MCU 已准备好,开始传输 | | `2` | 固件长度超限 | E4 最终结果: | 返回值 | 含义 | |---:|---| | `1` | 升级成功 | | `2` | 固件校验和错误 | | `3` | 版本错误或固件非法 | | `4` | 文件或数据获取失败 | E2 成功响应当前没有检查至少包含 3 字节,截断响应可能导致数组越界。 ### 3.8 MCU 新旧兼容 历史裸固件路径: ```text <介质根目录>/m3/cortex-m3.bin <介质根目录>/m3/cortex-gdm4.bin ``` 当前工作区已恢复历史裸固件路径。 | 输入 | 当前行为 | |---|---| | 合法 `update_mcu.zip` | 解压、验签、传输 | | 非法 `update_mcu.zip` | 返回失败,不回退裸 bin | | ZIP 不存在,存在 `m3/cortex-m3.bin` | M3 设备使用旧版文件 | | ZIP 不存在,存在 `m3/cortex-gdm4.bin` | GDM4 设备使用旧版文件 | | ZIP 与裸 bin 同时存在 | 只处理 ZIP | PX3 当前分支不包含 RK3568 的 `446193a73` 新旧包兼容提交。 --- ## 4. 当前待完善点 ### MPU 1. 将未跟踪的 `ZQ_TH7_RKUpdateService` 纳入正式源码和构建基线。 2. 从业务扫描流程中移除 Rockchip 遗留 `update.zip` 分支。 3. 明确恢复裸 `update.img` 时对 `persist.sys.update.show` 的处理方式。 4. 验签失败后立即结束,不得回退裸 `update.img`。 5. 使用安全解压和私有暂存目录,保证验签文件与安装文件一致。 6. 补齐取消、异常、Recovery 结果和升级包清理流程。 ### MCU 1. 统一页面和通讯服务的 MCU 版本解析。 2. 增加升级会话互斥,避免 E1 重复初始化。 3. 修复 ZIP 路径校验、共享目录替换和文件流关闭问题。 4. 明确裸 bin 兼容允许使用的工程授权场景。 --- ## 5. 关键代码 ### MPU | 文件 | 行号 | 说明 | |---|---:|---| | `ZQ_TH7_RKUpdateService/src/android/rockchip/update/service/RKUpdateReceiver.java` | 53 | 本地升级触发 | | `ZQ_TH7_RKUpdateService/src/android/rockchip/update/service/RKUpdateService.java` | 328 | MPU 本地升级主流程 | | 同上 | 498 | 文件扫描和优先级 | | `ZQ_TH7_RKUpdateService/src/android/rockchip/update/service/ZipFileVerifier.java` | 86 | MPU 解压和验签 | | `ZQ_TH7_RKUpdateService/src/android/rockchip/update/service/UpdateAndRebootActivity.java` | 159 | 选择 RK image 或 OTA 模式 | | `ZQ_TH7_RKUpdateService/src/android/rockchip/update/service/RecoverySystem.java` | 354 | 安装 `update.img` | ### MCU | 文件 | 行号 | 说明 | |---|---:|---| | `YX_MainInterface_ZhongQi/src/main/java/com/yaxon/base/system/UpgradeMainActivity.java` | 111 | MCU 升级入口 | | `YX_MainInterface_ZhongQi/src/main/java/com/yaxon/base/system/ZhongQiM3UpdateActivity.java` | 321 | 发起 Binder 调用 | | `YX_CommunicatePro_ZhongQi/src/main/java/com/yaxon/telematics/service/ImplM0ManagerService.java` | 30 | AIDL 转发 | | `YX_CommunicatePro_ZhongQi/src/main/java/com/yaxon/telematics/service/protocol/monitor/m0/MonitorM0Update.java` | 75 | E1~E4 协议处理 | | 同上 | 203 | 查包、验签和 E2 请求 | | 同上 | 264 | 实际固件选择 | | `YX_CommunicatePro_ZhongQi/src/main/java/com/yaxon/utils/ZipFileVerifier.java` | 80 | MCU 解压和验签 | ## 6. 代码状态说明 - MPU 升级目录 `ZQ_TH7_RKUpdateService` 当前未纳入 Git。 - 当前源码实际扫描三种文件;业务目标只保留 `update_mpu.zip` 和 `update.img`。 - MCU 签名升级由 `aeb1d9c9e`、`897dc0607` 两笔提交引入。 - 2026-08-19 当前工作区恢复 `m3/cortex-m3.bin`、`m3/cortex-gdm4.bin` 旧版兼容,并改为验签实际传输的 ZIP 内固件。 - 本文只描述 MPU 和 MCU 本地升级,不包含其他升级类型。 不签名: 新版本 - >旧版本