当前位置: 首页 > news >正文

rk35xx 通过recovery升级问题

Firefly 的recovery库是一个核心组件,它构建了一个独立的微型 Linux 系统,专门用于在设备主系统之外执行高可靠性的固件升级。简单来说,它的工作流程是:主系统通过命令触发,将升级指令写入特定分区并重启;随后,引导程序(U-Boot)加载recovery系统;最后,recovery系统解析并执行升级包,完成固件更新。

整个流程与 Rockchip 平台深度集成,主要用于实现系统级(OTA)升级和恢复出厂设置。

🔄 OTA 升级原理与完整流程

Rockchip 平台的 OTA 升级流程可以清晰地拆分为以下几个步骤:

渲染错误:Mermaid 渲染失败: Parse error on line 5: .... 写入升级指令| D[misc 分区 (BCB)] A --> -----------------------^ Expecting 'SQE', 'DOUBLECIRCLEEND', 'PE', '-)', 'STADIUMEND', 'SUBROUTINEEND', 'PIPE', 'CYLINDEREND', 'DIAMOND_STOP', 'TAGEND', 'TRAPEND', 'INVTRAPEND', 'UNICODE_TEXT', 'TEXT', 'TAGSTART', got 'PS'
步骤 1: 升级触发与数据准备

用户触发升级后,升级程序 (update_enginerkupdate) 会完成两项核心工作:

  1. 校验升级包:首先对 OTA 包(如update.imgupdate.zip)进行签名校验,确保其完整性和来源可信。
  2. 写入 BCB 指令:校验通过后,会向misc分区的启动控制块(BCB)写入特定指令。其中,command字段是关键,通常为boot-recovery,同时recovery字段会携带升级包的路径(例如--update_package=/udisk/update.img)。这个操作就是告诉引导程序下次启动时要做什么。

💡 关于misc分区和 BCB 结构体

misc分区是一个数据中转站,在用户空间通常通过文件系统节点(例如/dev/block/by-name/misc)进行访问。

BCB 结构体的核心内容定义在bootable/recovery/bootloader.h中:

structbootloader_message{charcommand[32];// 如 "boot-recovery"charstatus[32];// 升级进度状态charrecovery[1024];// 详细升级指令,如 "--update_package=/sdcard/update.zip"// ... 其他字段};
步骤 2: 重启并进入 Recovery 模式
  1. 主系统执行重启命令(reboot)。硬件重启,控制权移交给引导程序(通常是 U-Boot)。
  2. U-Boot 在启动过程中会检查misc分区的 BCB 数据。若读取到command字段包含boot-recovery,U-Boot 便会根据预设配置,加载recovery分区上的recovery.img镜像,而不是常规的boot.img
步骤 3: Recovery 系统执行升级

recovery.img被加载到内存并启动,它实际上是一个包含精简内核最小根文件系统(通常基于initramfs)的微型系统。其启动流程如下:

  1. 系统启动:内核启动,并挂载initramfs。第一个执行的程序通常是/init
  2. 启动核心程序init进程会根据配置文件(如init.rc)启动recovery主程序。recovery服务会解析 BCB 信息。
  3. 调用具体执行者recovery程序会解析 BCB 中的指令,识别升级包类型,并调用相应的升级后端:
    • rkupdate后端:专门用于处理 Rockchip 私有格式的update.img完整镜像包。
    • update_engine后端:功能更强大,支持update.zipupdate.img等多种包格式,并兼容 A/B 分区升级。
  4. 写入固件rkupdateupdate_engine根据指令,解析升级包文件,并将其中包含的各个分区镜像(如boot.img,system.img等)准确地写入到 Flash 存储的对应分区中。

🔬 关键代码模块与实现分析

recovery项目的源码目录通常位于bootable/recovery/。以下是其核心模块与代码实现的关键部分。

1.recovery主程序:流程控制中枢 (recovery.cpp)

recovery程序的入口在recovery.cppmain()函数。它会解析 BCB,决定是执行升级还是显示菜单,是升级流程的控制中心。

// bootable/recovery/recovery.cpp (简化逻辑)intmain(intargc,char**argv){// 1. 加载并解析 BCB (Bootloader Control Block)std::string boot_command;std::string boot recovery;// ... 从 misc 分区读取数据,参考 bootloader.cpp 的 get_bootloader_message_mtd// 读取到的内容会被存入结构体 struct bootloader_message// 2. 解析命令行参数,例如 --update_package=/path/to/package// adb 等会将这些参数写入 /cache/recovery/command// get_args() 会合并 BCB 和 /cache/recovery/command 中的参数// update_package 变量最终会包含 OTA 包的路径,如 /sdcard/update.zip// 3. 根据命令执行相应操作// process_update_package(update_package) 是执行升级的核心函数if(!update_package.empty()){// 处理 OTA 升级包intstatus=install_package(update_package);// 升级成功则重启,失败则可能显示错误菜单}elseif(!wipe_data){// 显示 Recovery 主菜单ui->ShowMenu();}return0;}

代码逻辑参考了 Android 原生 recovery 模块的实现方式。

updater机制:脚本驱动的升级逻辑当升级包为update.zip格式时,recovery会启动updater程序。updater的核心是执行包内的META-INF/com/google/android/updater-script脚本,该脚本使用 Edify 语言编写,定义了每一步升级操作,如分区擦除、文件写入等。

updater-script示例

# 显示进度 ui_print("Starting update..."); # 擦除 system 分区 format("ext4", "EMMC", "/dev/block/by-name/system", "0"); # 将 new_system.img 写入 system 分区 block_image_update("/dev/block/by-name/system", package_extract_file("system.transfer.list"), "system.new.dat", "system.patch.dat"); # 写入 boot 分区 package_extract_file("boot.img", "/dev/block/by-name/boot"); ui_print("Update completed successfully.");
2.rkupdate后端:Rockchip 私有格式执行者 (external/rkupdate/)

rkupdate是处理 Rockchip 私有update.img固件的后端程序。update.img是一个包含多个分区镜像的集合包。rkupdate的核心功能是解析这个集合包,并将每个分区镜像烧录到 Flash 的正确位置。

下面是update.img解析的核心代码片段(简化逻辑):

// external/rkupdate/rkupdate.c (简化逻辑)intdo_rkupdate(constchar*package_path){FILE*fp=fopen(package_path,"rb");// 1. 解析 Rockchip 固件头部 (RC4)// 读取前几个字节,确认是 RC4 格式,并获取头部信息intfd=open(package_path,O_RDONLY);rc4_header header;read(fd,&header,sizeof(header));// 2. 循环处理每个分区镜像// 根据头部信息找到每个分区的起始地址和长度// 然后逐个分区进行烧写for(inti=0;i<header.num_images;i++){// 获取分区镜像的偏移和大小off_toffset=get_partition_offset(i);size_tsize=get_partition_size(i);constchar*name=get_partition_name(i);// 3. 烧写到对应分区// 调用 rkflash 相关函数写入 /dev/block/by-name/ 下的设备节点if(write_partition(name,fd,offset,size)!=0){LOGE("Failed to write partition %s",name);return-1;}// 写入进度更新update_progress(...);}fclose(fp);LOGI("rkupdate completed successfully!");return0;}
3.update_engine后端:现代化升级方案 (external/recovery/update_engine/)

update_engine是一个设计上更现代化、功能更全面的升级后端。它是一个独立的守护进程,通过 D-Bus 通信,采用状态机管理升级任务,将升级过程抽象为IDLE->CHECKING->DOWNLOADING->UPDATING等状态。

  • 架构优势:通过抽象接口(PartitionWriter,FileSystem等)实现了高内聚低耦合,便于移植和扩展。
  • 多格式支持:原生支持update.zipupdate.img

update_engine的状态机迁移可以简化为:

IDLE -> CHECKING -> DOWNLOADING -> UPDATING -> IDLE | | | +------------+--------------+-> ERROR

🛠️ 独立实现与进阶方案

除了使用 Rockchip 的官方方案,嵌入式 Linux 设备还有多种构建 OTA 能力的途径。

独立实现方案

要独立实现一套 OTA 系统,核心在于构建一个可靠、安全的升级环境。关键步骤和组件如下:

  1. 制作 Recovery 镜像 (recovery.img):这个镜像本身是一个独立的 Linux 系统。你可以采用以下方式构建:
    • 基于 Buildroot:在 Buildroot 的配置中为另一个配置 (output/recovery/) 选择最小化的 Linux 内核和 BusyBox,并加入升级程序源码。
  2. BCB 操作与系统服务
    • 编写一个独立程序(例如my_ota_client)来操作/dev/block/by-name/misc分区,用于写入和读取 BCB 指令。
    • 使用 Linux 的inotify机制或实现一个简单的守护进程来监听升级事件。
  3. 引导程序适配:修改 U-Boot 源码,使其在启动流程中加入对misc分区的检查逻辑。这通常涉及 Rockchip 特有的reboot mode驱动。
  4. 升级包生成脚本:编写一套脚本,用于生成最终可在设备上使用的update.imgupdate.zip升级包。
进阶实现方案
  1. 使用开源框架 (SWUpdate/RAUC/Mender):这是实现专业级 OTA 功能的主流选择。它们功能完善,社区活跃,可极大缩短开发周期。

    • SWUpdate:最灵活,支持本地、网络等多种升级方式,并可直接复用update-engine
    • RAUC:在需要复杂的 A/B 分区更新和回滚机制的场景下,架构非常清晰。
    • Mender:提供开箱即用的完整解决方案。
  2. 引入 A/B (Seamless) 分区升级:这是提升用户体验的关键。系统拥有两套独立分区(A 和 B)。升级时,系统在后台更新非当前运行的那套分区,完成后只需简单重启即可切换,实现了真正的“无缝”升级,且升级失败能自动回滚。

两种方案对比
维度Rockchip 官方方案开源方案 (SWUpdate 等)
集成难度低,与 SDK 深度集成中高,需独立移植
灵活性受限于 Rockchip 框架非常高,可深度定制
社区生态依赖 Rockchip 支持全球开发者社区,活跃
维护成本随 SDK 更新需要持续关注上游

总的来说,Firefly 的recovery库展示了 Rockchip 平台实现系统升级的标准方法,其核心是围绕recovery系统这一独立环境来保证升级的高可靠性。在工程实践中,如果追求快速开发和与 SDK 的深度集成,Rockchip 的官方方案是首选;而当项目需要更灵活的升级策略、更强的社区支持或有特定的安全要求时,采用 SWUpdate 等成熟的开源框架将更具优势。

http://www.jsqmd.com/news/886724/

相关文章:

  • ssm高校推免报名系统(10102)
  • 企业级AI语音合成采购决策白皮书(2024真实报价单首次公开)
  • 本地Windows容器迁移至云服务器
  • 【MySQL数据库 | 第一篇】 概述
  • # AI音乐生成API的可控性与专业化演进研究
  • 配置OpenClaw Agent使用Taotoken作为后端模型提供商
  • 【Qwen3.6】关键技术:线性注意力(Linear Attention/DeltaNet)和标准多头注意力(Standard Attention)混合
  • 2024年网盘下载终极免费解决方案:八大平台直链解析技术深度解析
  • Windows终极PDF处理工具:3步免费安装Poppler完整指南
  • 如何处理AI生成代码中的错误
  • 5分钟搭建原神私服:KCN-GenshinServer终极图形化解决方案
  • DeepSeek幻觉问题深度复盘(2023–2024真实故障库首发):从token级偏差到语义坍塌的全链路溯源
  • Owl-Alpha 新手快速上手指南
  • LSTM 算法的完整计算过程
  • MySQL GROUP BY 原理与优化
  • 基于双T振荡器的正弦波LED调光电路设计与实践
  • Linux系统Vim编辑器
  • 你的企业还在用“人海战术”处理发票和报表?2026智能体进化论
  • 别再死磕理论了!用Python手搓一个蒙特卡洛强化学习小游戏(附完整代码)
  • pan-baidu-download:百度网盘多线程下载加速器架构解析与性能优化指南
  • 【绝密PEST压力测试报告】:Claude 3.5在金融/医疗/政务三大敏感领域的17项穿透式评估结果(仅剩最后87份)
  • 边缘AI落地总失败?DeepSeek架构的4层容错机制,92%故障在毫秒级自愈
  • DeepSeek多卡训练通信开销超62%?紧急发布:NCCL拓扑感知AllReduce重排+梯度压缩阈值动态调优指南
  • Neon Glowing效果失效全解析,深度解读--v 6.2下--style raw与--no ambient_light的冲突机制及绕过方案
  • 面试必问:Temperature=0为何仍不确定?真相揭秘
  • 博弈论导向的车辆队列运动协同分层控制算法【附算法】
  • 幽灵请求与内存泄漏:一次全栈高并发下的性能惊魂复盘
  • 【2026收藏版】小白程序员必学的20个核心AI大模型基础概念(通俗易懂无废话)
  • Hugging Face 中tokenizer.json 和vocab.json 有区别?
  • 冰雪重制版手游官网下载:冰雪重制版最新官方下载渠道