RK 平台升级开发:全场景方案与实践指南,覆盖常规系统和ab系统

频道:保险市场 日期: 浏览:58743

嵌入式Linux开发领域,瑞芯微Rockchip)平台凭借其稳定的性能和丰富的生态支持,被广泛应用于各类智能设备中。而设备的升级功能作为保障产品生命周期、优化用户体验的核心模块,其开发质量直接影响产品的市场竞争力。本文基于Rockchip Linux updateEngine升级方案官方文档,系统梳理RK平台升级开发的核心技术方案、实现流程及关键注意事项,为开发工程师提供全面的实践指引。

wKgZO2ll9tGAI9SeAAAO64SlduI615.png

开始之前我们先看一下spi+pcie升级log:

root@linaro-alip:/# updateEngine --image_url=/userdata/update.img --misc=update --savepath=/userdata/update.img --reboot &[1] 3788root@linaro-alip:/# LOG_INFO: *** update_engine: V1.0.1-g
    
      ***.
    LOG_INFO: Current Mode is 'A' system.LOG_INFO: start RK_ota_url url [/userdata/update.img] save path [/userdata/update.img].LOG_INFO: save image to /userdata/update.img.LOG_INFO: url = /userdata/update.img.LOG_INFO: [MiscUpdate:90] save path: /userdata/update.imgLOG_INFO: In A system, now upgrade B system.LOG_INFO: [RK_ota_set_partition:125] num [16]LOG_INFO: need update parameter.LOG_INFO: need update uboot_b.LOG_INFO: need update boot_b.LOG_INFO: need update system_b.LOG_INFO: start RK_ota_start.LOG_INFO: rk m_status =1.LOG_INFO: where the file is local.LOG_INFO:[RK_ota_set_partition:125] num [16]LOG_INFO: entry0: storage =512firmware_offset =192, firmware_size =6226506LOG_INFO: entry1: storage =2048firmware_offset =6226698, firmware_size =5079775818LOG_DEBUG: uiTag =57464b52.LOG_DEBUG: usSize =66.LOG_DEBUG: dwVersion =1000000.LOG_DEBUG: btMajor =1, btMinor =0, usSmall =00.LOG_DEBUG: dwBootOffset =66.LOG_DEBUG: dwBootSize =771c0.LOG_DEBUG: dwFWOffset =77226.LOG_DEBUG: dwFWSize =579004.LOG_DEBUG: tag =1178684242size =5738496machine_model = RK3588 manufacturer = RK3588 version =16777216item =5.LOG_INFO: ================================================LOG_DEBUG: name = package-file file = package-file offset =490214flash_offset = -1usespace =1size =127LOG_DEBUG: name = parameter file = parameter.txt offset =492262flash_offset =0usespace =1size =299LOG_DEBUG: name = bootloader file = MiniLoaderAll.bin offset =102flash_offset = -1usespace =239size =487872LOG_DEBUG: name = uboot_a file = uboot.img offset =983782flash_offset =16384usespace =2560size =5242880LOG_DEBUG: name = uboot_b file = uboot.img offset =983782flash_offset =32768usespace =2560size =5242880LOG_INFO: new md5:7ea81bce7a98f59d890aafb5009c9f1bLOG_INFO: MD5Check is ok of /userdata/update.imgLOG_ERROR: MD5Check is error of /userdata/update.imgLOG_ERROR: Md5Check update.img fwSize:6226474LOG_DEBUG: uiTag =57464b52.LOG_DEBUG: usSize =66.LOG_DEBUG: dwVersion =1000000.LOG_DEBUG: btMajor =1, btMinor =0, usSmall =00.LOG_DEBUG: dwBootOffset =66.LOG_DEBUG: dwBootSize =771c0.LOG_DEBUG: dwFWOffset =77226.LOG_DEBUG: dwFWSize =2ebfc804.LOG_DEBUG: tag =1178684242size =784320512machine_model = RK3588 manufacturer = RK3588 version =16777216item =10.LOG_INFO: ================================================LOG_DEBUG: name = package-file file = package-file offset =6716720flash_offset = -1usespace =1size =227LOG_DEBUG: name = parameter file = parameter.txt offset =6718768flash_offset =0usespace =1size =460LOG_DEBUG: name = bootloader file = MiniLoaderAll.bin offset =102flash_offset = -1usespace =239size =487872LOG_DEBUG: name = misc file = misc.img offset =7210288flash_offset =16384usespace =24size =49152LOG_DEBUG: name = boot_a file = boot.img offset =7259440flash_offset =24576usespace =17525size =35889664LOG_DEBUG: name = boot_b file = boot.img offset =7259440flash_offset =155648usespace =17525size =35889664LOG_DEBUG: name = system_a file = rootfs.img offset =43150640flash_offset =352256usespace =2450944size =724566016LOG_DEBUG: name = system_b file = rootfs.img offset =43150640flash_offset =15032320usespace =2450944size =724566016LOG_DEBUG: name = oem file = oem.img offset =767716656flash_offset =29712384usespace =9182size =18804736LOG_DEBUG: name = userdata file = userdata.img offset =786521392flash_offset =29974528usespace =2204size =4513792LOG_INFO: new md5:1fdb493d189fec4198c90d2f27974e9cLOG_INFO: MD5Check is ok of /userdata/update.imgLOG_ERROR: MD5Check is error of /userdata/update.imgLOG_ERROR: Md5Check update.img fwSize:784808490LOG_INFO: found rkimage_hdr.item[1].name = parameter mtd =0.LOG_INFO: found rkimage_hdr.item[6].name = parameter mtd =0.LOG_INFO: found rkimage_hdr.item[4].name = uboot_b mtd =0.LOG_INFO: found rkimage_hdr.item[10].name = boot_b mtd =0.LOG_INFO: found rkimage_hdr.item[12].name = system_b mtd =0.LOG_INFO: size more than4G, after adjusting is5019533312.LOG_INFO: Current device is not MTDLOG_INFO: now write parameter to /dev/block/by-name/gpt.LOG_INFO: ingore misc.LOG_INFO: now write uboot_b to /dev/block/by-name/uboot_b.LOG_INFO: update_cmd.flash_offset =0.LOG_INFO: flash_normal:200start.LOG_INFO: flash_normal:222, diff check for uboot_bLOG_WARN: Not a diff image, ret =80LOG_INFO: block_write src /userdata/update.img dest /dev/block/by-name/uboot_b.LOG_INFO: new md5:fdc69aec10a16d9d81b1a08b6ce8305dLOG_INFO: MD5Check is ok of /dev/block/by-name/uboot_bLOG_INFO: new md5:fdc69aec10a16d9d81b1a08b6ce8305dLOG_INFO: MD5Check is ok of /userdata/update.imgLOG_INFO: check /dev/block/by-name/uboot_b ok.LOG_INFO: now write boot_b to /dev/block/by-name/boot_b.LOG_INFO: update_cmd.flash_offset =0.LOG_INFO: flash_normal:200start.LOG_INFO: flash_normal:222, diff check for boot_bLOG_WARN: Not a diff image, ret =80LOG_INFO: block_write src /userdata/update.img dest /dev/block/by-name/boot_b.LOG_INFO: new md5:8ac9471d56990e08c4b1b9245f32a002LOG_INFO: MD5Check is ok of /dev/block/by-name/boot_bLOG_INFO: new md5:8ac9471d56990e08c4b1b9245f32a002LOG_INFO: MD5Check is ok of /userdata/update.imgLOG_INFO: check /dev/block/by-name/boot_b ok.LOG_INFO: now write system_b to /dev/block/by-name/system_b.LOG_INFO: update_cmd.flash_offset =0.LOG_INFO: flash_normal:200start.LOG_INFO: flash_normal:222, diff check for system_bLOG_WARN: Not a diff image, ret =80LOG_INFO: block_write src /userdata/update.img dest /dev/block/by-name/system_b.LOG_INFO: new md5:ba696b83e3db9d44f45c2a5378762517LOG_INFO: MD5Check is ok of /dev/block/by-name/system_bLOG_INFO: new md5:ba696b83e3db9d44f45c2a5378762517LOG_INFO: MD5Check is ok of /userdata/update.imgLOG_INFO: check /dev/block/by-name/system_b ok.LOG_INFO: RK_ota_start is ok!LOG_INFO: rk ota success.LOG_INFO: Current Mode is 'A' system.LOG_INFO: Current device is not MTDLOG_INFO: Current device is not MTDLOG_INFO: rk m_status =0.

一、升级方案核心架构:两种启动模式的选择与对比

RK Linux平台提供两种核心升级启动模式,分别适配不同的应用场景,开发人员需根据产品需求灵活选择。

(一)Recovery模式

Recovery模式通过在设备中划分独立的recovery分区(由kernel+resource+ramdisk组成)专门负责升级操作。其核心逻辑是通过u-boot读取misc分区的引导参数,判断是否进入Recovery系统执行升级。

优势:升级完整性强,即便过程中出现异常掉电等中断情况,重启后仍可继续执行升级,避免升级失败导致设备故障。

劣势:额外占用存储分区资源,且升级必须重启进入Recovery模式,无法在正常系统(Normal系统)中直接完成。

(二)Linux A/B模式

A/B模式采用双固件设计,设备中存储两套独立的系统(slot Aslot B),可实现无缝切换。升级时无需进入专用升级模式,在Normal系统中即可完成,重启后直接切换到升级后的系统。

优势:升级过程无需切换至专用模式,用户体验流畅;双系统冗余设计可有效防止设备变砖,若当前slot升级失败或系统损坏,可自动切换至另一slot启动;支持版本回滚,保障系统稳定性。

劣势:双系统设计会增加Flash存储占用率,对存储资源要求更高。

两种模式的核心差异还体现在代码支持上:updateEngine工具同时支持两种模式(RV1126/RV1109平台专用),而rkupdate工具仅支持Recovery模式(适用于其他平台)。

二、关键升级场景的实现流程

(一)基础OTA升级:RecoveryA/B模式通用实现

OTAOver-the-Air)升级是设备远程更新的核心方式,支持网络下载升级和本地升级两种形式,核心流程如下:

1.版本校验:通过--version_url参数指定版本文件地址,与设备本地/etc/version中的版本号对比,判断是否需要升级(该参数可缺省,缺省时跳过版本校验)。

2.固件获取:通过--image_url参数指定远程固件地址或本地固件路径,下载并保存至--savepath指定的目录(默认路径为/tmp/update.img,建议自定义为/userdata/update.img以避免临时目录空间不足)。

3.分区升级:通过--partition参数指定待升级分区(建议使用0x3FFC00,不支持升级parameterloader分区)。

4.重启生效:添加--reboot参数,升级完成后自动重启设备,Recovery模式重启进入Recovery系统完成最终升级,A/B模式重启后切换至升级后的slot

示例命令

网络升级(A/B模式):

updateEngine --image_url=http://xxx/update_ota.img --update --reboot

本地升级(Recovery模式):

updateEngine --image_url=/userdata/update.img --misc=update --reboot &

(二)差分升级:高效压缩升级包

针对大尺寸固件升级时带宽占用高、传输耗时久的问题,RK平台支持差分升级方案,通过制作新旧固件的差分补丁包(update_diff.img),仅传输变化部分数据,大幅降低升级包体积。

1.前置依赖

代码依赖:需确保buildrootexternal/recoverytools目录中包含差分升级相关补丁(如0001-ota-add-diff-firmware-script.patch等)。

工具依赖:PC端需安装bsdiffsudo apt install bsdiff)和md5sum工具。

2.关键限制

支持分区:uboot/trust/kernel分区及squashfs格式的rootfs分区。

不支持场景:ext2/ext4文件系统、mtd驱动的nand flash系统、加密分区及A/B模式。

分区空间要求:存储差分补丁包的分区(如userdata)空闲空间需不小于差分包(update_diff.img)与完整新rootfs.img的体积之和。

3.补丁包制作

通过工具脚本实现新旧固件的差分处理,命令如下:

cdtools/linux/Linux_Diff_Firmware/./mk-diff-ota.sh update_old.img update_new.img update_diff.img

生成update_diff.img可直接通过updateEngine工具进行OTA升级。

(三)SD卡启动盘升级:离线升级方案

SD卡升级适用于设备无法联网或首次烧录固件的场景,需根据系统模式区分制作流程:

1.通用制作步骤

使用RK提供的SDDiskTool工具(Windows端路径:toolswindowsSDDiskTool),选择目标SD卡、升级模式(SD启动),加载对应的固件文件,点击开始创建生成启动盘。成功后SD卡根目录会生成sdupdate.img(由原始update.img重命名而来),将SD卡插入设备并重启即可自动触发升级。

2.模式专属配置

Recovery模式:直接使用update.img通过SDDiskTool制作启动盘。

A/B模式:需先通过SDK编译生成update_sdcard.img(专门用于制作A/B模式启动盘),用该镜像制作启动盘后,再将update_ab.img(完整双分区固件)或update_ota.img(单slot固件)拷贝至SD卡,设备启动时会优先识别update_ab.img

(四)恢复出厂设置:数据清除方案

恢复出厂设置的核心是格式化userdata分区(存储用户配置数据和应用数据),回归出厂默认配置,实现方式如下:

1.触发方式:通过硬件按键组合(RECOVERY + VOLUMEUP)触发,或执行命令updateEngine --misc=wipe_userdata --reboot

2.执行流程:命令会向misc分区偏移4K位置写入格式化指令,设备重启后,S21mountall.sh脚本识别该指令并格式化userdata分区。

3.注意事项:--reboot参数可缺省,缺省时需等待设备下次重启才会执行格式化。

三、开发配置与编译关键步骤

(一)Recovery模式编译配置

1.Buildroot配置(make menuconfig):

BR2_PACKAGE_RECOVERY=y # 开启升级功能BR2_PACKAGE_RECOVERY_USE_UPDATEENGINE=y # 使用updateEngine工具BR2_PACKAGE_RECOVERY_RECOVERYBIN=y # 开启recovery bin文件BR2_PACKAGE_RECOVERY_UPDATEENGINEBIN=y # 编译updateEngineBR2_PACKAGE_RECOVERY_NO_UI=y # 关闭UI(无屏设备必选)

2.编译命令:

sourceenvsetup.sh# 选择对应平台的rootfs和recovery配置make clean:recovery./build.sh# 新SDK可简化为:./build.sh recovery && ./build.sh

(二)A/B模式编译配置

1.Uboot配置(修改defconfig,如rk3308_defconfig):

CONFIG_AVB_LIBAVB=yCONFIG_AVB_LIBAVB_AB=yCONFIG_ANDROID_AB=y

2.Buildroot配置(make menuconfig):

BR2_PACKAGE_RECOVERY=yBR2_PACKAGE_RECOVERY_BOOTCONTROL=y # 开启引导控制脚本BR2_PACKAGE_RECOVERY_RETRY= # 可选,引导模式为reset retry(默认successful boot)BR2_PACKAGE_RECOVERY_USE_UPDATEENGINE=y

3.分区表配置:在BoardConfig.mk中指定A/B模式分区表,如export RK_PARAMETER=parameter-ab-64bit.txt

4.固件输出:编译后生成update_ab.img(烧录用)、update_ota.imgOTA升级用)、update_sdcard.imgSD卡启动用)。

(三)自定义分区升级

若需扩展升级自定义分区(如factory分区),需修改external/recovery/update_engine/update.cpp中的UPDATE_CMD结构体数组,添加自定义分区配置:

{"factory",false,false,0,0,0,"", flash_normal},

同时在--partition参数中设置对应位值为1,确保升级工具识别该分区。

(四)SPI+PCIe方案专属配置:patch添加说明

若采用SPI+PCIe存储方案(区别于上述eMMC方案),需额外添加以下专属patch以保障升级功能正常实现,否则可能出现无法进入系统的问题,具体操作及问题说明如下:

1.必备patch清单

核心驱动适配patch0001-spi-pcie-storage-adapt-update-engine.patch(适配SPI+PCIe存储设备与updateEngine工具的通信驱动,解决存储识别异常问题)

分区管理优化patch0002-spi-pcie-partition-manager-enhance.patch(优化SPI+PCIe方案下的分区读写逻辑,提升升级过程中数据传输稳定性)

A/B模式根分区适配patch:修改u-boot/common/android_ab.c文件(解决SPI+PCIe方案下A/B模式启动时根分区识别失败问题),具体patch内容如下:

--- a/u-boot/common/android_ab.c+++ b/u-boot/common/android_ab.c@@ -472,6 +472,7 @@void ab_update_root_partition(void) /* Judge the partition device type. */ switch (dev_desc->if_type) { case IF_TYPE_MMC:+ case IF_TYPE_SCSI: /* scsi 0: UFS */ if (strstr(part_type, "ENV")) snprintf(root_part_dev, 64, "root=/dev/mmcblk0p%d", part_num); else if (strstr(part_type, "EFI"))@@ -496,6 +497,8 @@void ab_update_root_partition(void) break; default: printf("%s: Not found part type, failed to set root part device.n", __func__);+ ab_update_root_uuid();+ printf("Unknown part type, set default 'root=' with UUID.n"); return; }

2.未添加patch的报错信息

若未添加上述A/B模式根分区适配patch,设备启动时会因根分区识别失败无法进入系统,具体错误日志如下:

[ 4.933965] nvme nvme0:8/0/0default/read/poll queues[ 4.940453] nvme0n1: p1 p2 p3 p4 p5 p6 p7 p8[ 4.940808]Waitingforroot device...

四、调试与问题排查

(一)日志查看

1.串口日志:在buildroot/output/rockchip_***/target目录下创建隐藏文件.rkdebug,可在串口输出Recovery模式升级日志。

2.文件日志:升级完成后,在设备userdata/recovery/log文件中查看详细升级记录,命令:cat userdata/recovery/log

(二)常见问题解决

1.升级失败:检查分区空间是否充足(尤其是差分升级时的userdata分区)、固件是否为对应模式支持的格式(A/B模式需使用update_ota.imgupdate_ab.img)、--partition参数是否包含不支持的分区(如loaderparameter)。

2.A/B模式切换失败:检查misc分区中引导参数(偏移2K位置)是否正确,通过updateEngine --misc=display调试查看分区引导信息,确保slot优先级和尝试启动次数配置合理。

3.SD卡升级无响应:确认SD卡启动盘制作正确(A/B模式需包含update_sdcard.img和对应的升级固件)、SD卡是否正常识别、固件文件名是否为sdupdate.img

五、工具与附录支持

(一)固件打包工具

1.Windows平台:toolswindowsAndroidToolrockdev,修改package-file文件指定需打包的镜像,执行mkupdate.bat生成update.img

2.Linux平台:tools/linux/Linux_Pack_Firmware/rockdev,修改package-file文件,执行mkupdate.sh生成update.img

(二)Misc分区关键说明

Misc分区为无文件系统分区,用于存储引导配置参数,核心偏移地址功能如下:

2K位置:存储A/B模式分区引导信息(优先级、启动次数、启动状态等)。

4K位置:存储格式化命令(恢复出厂设置用)。

16K位置:实现Recovery系统与Normal系统的通信。

结语

RK平台的升级方案覆盖了OTA远程升级、SD卡离线升级、差分升级等全场景需求,开发人员需根据产品的存储资源、用户体验要求选择合适的启动模式。在实际开发过程中,需重点关注编译配置的完整性、分区空间的合理性及日志调试的有效性,同时遵循官方对分区升级的限制(如不支持loaderparameter分区升级),确保升级功能的稳定性和可靠性。通过本文的梳理,希望能为RK平台开发工程师提供清晰的升级开发路径,助力高效完成产品升级模块的设计与实现。

下期我们详细分析ab系统下spi+pcie双存储方案升级的点点滴滴。


  • 随机文章
  • 热门文章
  • 热评文章