12 KiB
PX3 升级流程说明
范围:仅梳理 PX3 本地 MPU 升级和 MCU 升级
代码:D:\zdCode\zhongqi_px3
分支:zhongqi_th7_px3_plus_security,HEAD8497c2da8
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 秒 |
扫描目录:
/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() 实际扫描顺序为:
update_mpu.zip → OTA_PACKAGE_FILE(默认 update.zip)→ update.img
另外,1224 版本处理独立裸 update.img 时会读取:
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
包结构:
update_mpu.zip
├── update.img
└── ValidationFile.ini
ValidationFile.ini 当前读取:
sign=<十六进制 RSA 签名>
流程:
检测到 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 命令:
--update_rkimage=<update.img完整路径>
--locale=<当前语言>
当前验签失败分支缺少 return,仍会打开确认页,并把外层 update_mpu.zip 当成标准 OTA 包再次校验。这是现有缺陷,不是兼容流程。
2.5 旧版裸 update.img
检测到 update.img
↓
读取 persist.sys.update.show
├── false:忽略,不弹确认页
└── true:继续
↓
检查镜像产品名是否匹配 ro.product.model
↓
用户确认
↓
installRKimage()
↓
重启 Recovery 安装
裸 update.img 没有新增 RSA 验签,只做产品名检查。
2.6 MPU 结果处理
服务下次启动时读取:
/cache/recovery/last_flag
| 标记 | 含义 |
|---|---|
success$path=... |
Recovery 报告升级成功 |
updating$path=... |
上次升级未形成成功状态 |
当前结果流程尚未闭环:
- 成功/失败提示 Activity 的启动代码被注释。
- 没有统一结果广播。
- 升级包删除没有稳定执行。
- 新版包验签后用户取消,升级锁没有释放。
- Recovery 写回
last_flag的实现不在当前项目中。
3. MCU 升级流程
3.1 页面入口
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 包结构
update_mcu.zip
├── cortex-gdm4.bin
├── cortex-m3.bin
└── ValidationFile.ini
根据设备类型,实际刷写文件是 cortex-gdm4.bin 或 cortex-m3.bin。
3.4 解压和验签
开始 sendUpdateRequest()
↓
删除 /sdcard/zhongqi_mcu_update/
↓
解压 update_mcu.zip 到该目录
↓
根据 MCU 版本选择实际目标固件
↓
计算 SHA-256
↓
读取 ValidationFile.ini 中的 sign
↓
使用硬编码 RSA-2048 公钥和 SHA256withRSA 验签
├── 失败:返回 -2
└── 成功:选择实际固件并进入协议传输
当前算法先计算文件 SHA-256,再把摘要传给 SHA256withRSA,实际相当于:
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 返回最终结果 |
主时序:
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 新旧兼容
历史裸固件路径:
<介质根目录>/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
- 将未跟踪的
ZQ_TH7_RKUpdateService纳入正式源码和构建基线。 - 从业务扫描流程中移除 Rockchip 遗留
update.zip分支。 - 明确恢复裸
update.img时对persist.sys.update.show的处理方式。 - 验签失败后立即结束,不得回退裸
update.img。 - 使用安全解压和私有暂存目录,保证验签文件与安装文件一致。
- 补齐取消、异常、Recovery 结果和升级包清理流程。
MCU
- 统一页面和通讯服务的 MCU 版本解析。
- 增加升级会话互斥,避免 E1 重复初始化。
- 修复 ZIP 路径校验、共享目录替换和文件流关闭问题。
- 明确裸 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 本地升级,不包含其他升级类型。
不签名: 新版本 - >旧版本