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

rk3568 A/B系统 OAT升级 实践

        在阅读本文档之前,读者可以参考瑞芯微官方文档参考文档:《Linux A/B System》。所谓的A/B System即把系统固件分为两份,系统可以从其中的一个slot上启动。当一份启动失败后可以从另份启动,同时升级时可以直接将固件拷贝到另一个slot上而无需进入系统升级模式。AB system 不考虑支持 recovery 升级。

1、修改分区文件parameter-buildroot-fit-ab.txt

      首先需要根据rk3568外挂的存储设备的大小以及需求来划分分区,因为只有将分区划分清楚后,才能开展后面的工作。A/B系统,意味着至少kernel,rootfs至少存在kernel_a,kernle_b,rootfs_a和rootfs_b分区。以笔者的设备为例,因为这是个存储设备,外挂的emmc容量很大,emmc划分的分区信息如下,如果没有对uboot升级的需求,其实uboot_b分区没有存在的意义。

    

       sdk默认使用的分区表是parameter-buildroot-fit.txt,为了区分,A/B分区使用的分区表为parameter-buildroot-fit-ab.txt。

        为了使的配置一开始就有效,将下面的配置放到对应的配置文件中即可,笔者的配置文件路径是:rk3568_bsp/device/rockchip/.chips/rk3566_rk3568/rockchip_rk3568_evb1_ddr4_v10_defconfig文件。读者根据自己的项目配置修改对应文件即可。

RK_PARAMETER="parameter-buildroot-fit-ab.txt"

2、uboot添加配置

增加uboot配置项如下:

        CONFIG_AVB_LIBAVB=y

        CONFIG_AVB_LIBAVB_AB=y

        CONFIG_AVB_LIBAVB_ATX=y

        CONFIG_AVB_LIBAVB_USER=y

        CONFIG_RK_AVB_LIBAVB_USER=y

        CONFIG_ANDROID_AB=y(默认未配置)

上面配置主要是使得spl程序能够根据标识去加载对用的uboot和kernel分区。

3、A/B系统分区挂载问题

        rk3568SDK中默认帮助我们划分了两个分区:userdata和oem。userdata用于存放可读写的内容如程序所需的配置文件,以及其他资源。oem分区是只读分区,用于存放用户只读的内容如可执行程序,库文件等。

        由于瑞芯微配置了oem和userdata分区,而在A/B分区方案中,修改为oem_a/_b和userdata_a/_b导致配置的/etc/fstab文件错误,错误挂载了分区信息。

        /etc/fstab内容如下,会自动挂载oem和userdata分区到/oem和/userdata。

          由于瑞芯微SDK中会将默认创建的userdata和oem分区自动添加到/etc/fstab文件中,该文件用于存放分区挂载文件信息,设备上电后会就会自动进行分区的挂载(/etc/init.d/S00mountall.sh文件来挂载分区,感兴趣的读者可以阅读该脚本)。

etc/init.d/S00mountall.sh 内容如下:
#!/bin/sh
### BEGIN INIT INFO
# Provides:       mount-all
# Required-Start:
# Required-Stop:
# Default-Start:  S
# Default-Stop:
# Description:    Mount all internal partitions in /etc/fstab
### END INIT INFOcase "$1" instart|"")# 执行mount-helper函数处理挂载问题mount-helper;;restart|reload|force-reload)echo "Error: argument '$1' not supported" >&2exit 3;;stop|status)# No-op;;*)echo "Usage: start" >&2exit 3;;
esac:
mount-helper脚本内容如下:
#!/bin/sh
### BEGIN INIT INFO
# Provides:       mount-all
# Default-Start:  S
# Default-Stop:
# Description:    Mount all internal partitions in /etc/fstab
### END INIT INFO# Don't exit on error status
set +e# Uncomment below to see more logs
# set -x. $(dirname $0)/disk-helperLOGFILE=/var/log/mount-all.logBASIC_FSTYPE="proc devtmpfs devpts tmpfs sysfs configfs debugfs pstore"do_part()
{# Not enough args[ $# -lt 6 ] && return# <file system> <mount pt>      <type>  <options>       <dump>  <pass>DEV=${1##*=}  #删除最长匹配*=的头部模式,将$1从头部开始最长匹配=之前包括=一起删除MOUNT_POINT=$2FSTYPE=$3OPTS=$4#跳过fsckPASS=$6 # Skip fsck when pass is 0# Setup check/mount tools and do some prepare# 检查分区是否存在等准备工作prepare_part || return# Check and repair partition# 是否进行fsck操作check_part# Mount partition# 挂载分区mount_part || return# Resize partition if neededresize_part# Restore ro/rw# 恢复原来的状态remount_part $MOUNT_RO_RW
}mount_all()
{# 根目录下的.auto_mkfs文件,用于自动格式化分区AUTO_MKFS="/.auto_mkfs"if [ -f $AUTO_MKFS ];thenecho "Note: Will auto format partitons, remove $AUTO_MKFS to disable"elseunset AUTO_MKFSfi# 根目录下的.skip_fsck文件,用于跳过fsckSKIP_FSCK="/.skip_fsck"if [ -f $SKIP_FSCK ];thenecho "Note: Will skip fsck, remove $SKIP_FSCK to enable"elseecho "Note: Create $SKIP_FSCK to skip fsck"echo " - The check might take a while if didn't shutdown properly!"unset SKIP_FSCKfi# Ignore basic file systemsID=0# -w      Match whole words only,完全匹配# -v      Select non-matching lines,选中非匹配项# -E      PATTERN is an extended regexp,使用扩展正则表达式,因为使用了|符号# grep查找 /etc/fstab中#或$BASIC_FSTYPE中内容开头以外的项# read 读取一行到LINE中grep -vwE "^#|${BASIC_FSTYPE// /|}" /etc/fstab | while read LINE;do#进行挂载处理do_part $LINE&ID=$(( $ID + 1 ))
done
wait
}case "$1" instart|"")echo "Start mounting all internal partitions in /etc/fstab"echo "Log saved to $LOGFILE"# Mount basic file systems firstly# ${var//pattern/repl}替换所有匹配的pattern为repl# 将BASIC_FSTYPE中的空格替换为逗号(,)#  -a, --all  mount all filesystems mentioned in fstab#  -t, --types <list>      limit the set of filesystem types# mount -a -t list, 挂载fstab中类型在BASIC_FSTYPE中的项mount -a -t "$(echo "${BASIC_FSTYPE// /,}")"# 处理剩下分区的挂载,将过程中的输出既输出到终端又保存到文件LOGFILE中mount_all 2>&1 | tee $LOGFILE;;*)echo "Usage: mount-helper start" >&2exit 3;;
esac:

         由于我们修改了userdata和oem的分区名为 userdata_a/b,oem_a/b。但是SDK并不知道,所以需要修改SDK对应脚本中的内容,能够动态修改/etc/fstab中的内容,当从A分区系统启动时挂载userdata_a,oem_a分区,当从B分区系统启动时挂载userdata_b,oem_b分区。当然整体而言也包括kernel和rootfs的分区信息也需要修改。

        笔者的处理方法是sdk编译时默认不让添加userdata和oem的挂载分区信息到/etc/fstab文件中。设备上电后在mount-helper脚本中根据uboot传递到/proc/cmdline中表示使用A/B系统中的哪个系统的标志(android_slotsufix=_a或android_slotsufix=_b)动态的添加usetdat和oem分区的内容到/etc/fstab文件中。

动态设置挂载userdata_a/b,oem_a/b分区到/etc/fstab文件如下:
add_part()
{userdata_a="/dev/mmcblk0p9\t/userdata\text4\tdefaults\t0\t0" oem_a="/dev/mmcblk0p11\t/oem\text4\trelatime,ro\t0\t0"userdata_b="/dev/mmcblk0p10\t/userdata\text4\tdefaults\t0\t0"oem_b="/dev/mmcblk0p12\t/oem\text4\trelatime,ro\t0\t0" slotsufix=$(cat "/proc/cmdline" | grep -o 'android_slotsufix=_\w')	if [ -n $slotsufix ] ; thenslot=$(echo $slotsufix | cut -d'=' -f2)fi	if [ "$slot" == "_a" ] ; thenoem=${oem_a}userdata=${userdata_a}elif [ "$slot" == "_b" ] ; thenoem=${oem_b}userdata=${userdata_b}elseecho "slotsufix error,using default _a"oem=${oem_a}userdata=${userdata_a}fi   # 由于字符串中存在\t转义字符,grep不会处理其中的转义字符,使用printf来处理转义字符value_oem=$(grep "$(printf $oem)" /etc/fstab || echo "Not found")value_userdata=$(grep $"$(printf $userdata)" /etc/fstab || echo "Not found")if [ "$value_oem" == "Not found" -o "$value_userdata" == "Not found" ] ; thenecho "Not find oem or userdata partitons,will create it"echo -e "$oem" echo -e "$userdata" sed -i '/oem/d' 		/etc/fstabsed -i '/userdata/d' 	/etc/fstabecho -e "$oem" >> /etc/fstabecho -e "$userdata" >> /etc/fstabfi
}

        为什么我们非要将动态分区的挂载放在/etc/fstab中来处理?我们可以自己在程序或者脚本中使用mount函数来挂载分区不行吗? 其实都是可以的,主要是我们想偷个懒。因为使用瑞芯微的挂载脚本其可以帮我们处理resize的问题。

        以笔者的设备为例,SDK编译出来的userdata.img只有几百K,但是userdata_a/b分区的大小是100M。如果不进行resize处理的话,通过df查看的userdata分区就是镜像文件的大小几百K。为了让这个分区的大小为期望的100M,需要进行resize操作。如果对resize感兴趣的同学可以阅读resize相关的脚本,在脚本中会探测分区有没有被resize过,如果没有就进行resize操作,resize完成后在分区中存放一个隐藏文件,表明该分区被resize过。后面设备再上电只要检测到该隐藏文件就跳过resize操作,这里不再继续进行展开,大家知道有这么个事情就行,点到即止。

        resize后分区情况如下:

         

4、其他分区配置

        笔者的设备上将剩余的分区都配置到data分区中。

        在sdk目录下执行make menuconfig配置来设置分区自定义的分区:

最终生成的配置信息如下:

RK_EXTRA_PARTITION_NUM=3
#
# Extra partition 3
#
RK_EXTRA_PARTITION_3_NAME="data"
RK_EXTRA_PARTITION_3_DEV="auto"
RK_EXTRA_PARTITION_3_MOUNTPOINT="/home/userspace"
RK_EXTRA_PARTITION_3_FSTYPE="ext4"
RK_EXTRA_PARTITION_3_OPTIONS="defaults"
RK_EXTRA_PARTITION_3_SRC="normal"
RK_EXTRA_PARTITION_3_SIZE="auto"
# RK_EXTRA_PARTITION_3_BUILTIN is not set
RK_EXTRA_PARTITION_3_FEATURES="${RK_EXTRA_PARTITION_3_BUILTIN:+builtin}"
RK_EXTRA_PARTITION_3_STR="${RK_EXTRA_PARTITION_3_DEV:-auto}:$RK_EXTRA_PARTITION_3_NAME:$RK_EXTRA_PARTITION_3_MOUNTPOINT:$RK_EXTRA_PARTITION_3_FSTYPE:$RK_EXTRA_PARTITION_3_OPTIONS:${RK_EXTRA_PARTITION_3_SRC// /,}:$RK_EXTRA_PARTITION_3_SIZE:$RK_EXTRA_PARTITION_3_FEATURES"

将上面的配置存放到sdk的配置文件中就能一开始就生效。

5、ota升级

        将需要升级的分区的镜像文件下载到本地后,如果当前系统运行在A分区,则需要刷写B系统对应的分区。刷写分区时使用open,read,write,fsync等系统调用操作/dev/mmcblk0px分区即可。所有待升级的分区刷写成功后,需要修改misc分区中的标志。这部分在瑞芯微的官方文档中有详细描述这里不再赘述。

        正常情况下只有ota升级成功后才会去设置切面标志,使设备ota后从另一面启动。比如当前设备在A面,ota时烧录的是B面,烧录成功后将设置启动面B面,下次设备上电后从B面启动。OTA升级完成了,从B面启动,但是之前升级包里面的内容存在bug,导致设备卡死在kernel某个位置,这时就无法回退到A面。我们需要设计一种回退机制,使得设备在某个面启动过程中出现问题时,被外部看门狗重启后,设备能够切换到另外一面。瑞芯微在uboot中提供的reset retry模式能够解决上述问题。

        为了在进行烧录时同时将A/B系统都进行烧录,需要设置如下配置:

        RK_AB_UPDATE=y

相关文章:

  • 人形机器人的 “灵动密码”:动作捕捉与 AI 如何为其注入活力
  • 低碳理念在道路工程中的应用--装配式基层
  • Python GIL 与 pybind11 GIL管理机制
  • C盘哪些文件删除之后无影响,可以清理磁盘空间。
  • AdaBoost算法的原理及Python实现
  • VS乱码问题
  • C++ 的未来战场:从技术深耕到职业破局
  • ArcGIS Pro几个小知识点分享
  • 驾驭音质,尽享四通道力量——AXPA17851
  • 开源 RAG 框架对比:LangChain、Haystack、DSPy 技术选型指南
  • Arthas 使用攻略
  • Java从入门到精通 - Java入门
  • PCB设计工艺规范(五)PCB尺寸、外形要求
  • 1295. 统计位数为偶数的数字
  • 学习笔记:Qlib 量化投资平台框架 — MAIN COMPONENTS Part Ⅲ
  • 6.应用层
  • 【计算机视觉】目标检测:深度解析Detectron2:Meta开源目标检测与图像分割框架实战指南
  • 2025年4月AI科技领域周报(4.21-4.27):大模型生态加速演进 通用AI开启产业融合新范式
  • element-plus + splitpanes 实现左右拖动控制宽度
  • (eNSP)Smart Link配置实验
  • 新华时评:需要“重新平衡”的是美国心态
  • 2025年第一批“闯中人”已经准备好了
  • 光明日报社论:用你我的匠心,托举起繁盛的中国
  • 摩根大通任命杜峯为亚太区副主席,加码中国市场业务布局
  • 外媒称菲方允许菲官员窜台,国台办:应停止在台湾问题上玩火
  • 荆州市委书记汪元程:全市各级干部要做到慎微、慎初、慎独、慎友