OTA打包和升级


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 03/20/2024

    1. 概述

    本文介绍的是Sigmastar的IPC、NVR平台在OTA升级中打包、解包、升级的流程。支持分区打包、分区升级、个别文件升级、新旧文件夹文件对比批量打包和升级、文件差分升级。

    升级包后台服务器维护、终端下载及管理,请结合第三方服务。


    2. 分区打包流程

    2.1. 打包工具介绍

    打包工具在Linux服务器上执行,运行环境ubuntu 20.04。只会根据当前要升级的文件生成所需的文件头。

    打包工具的bin所在目录:

    project/image/makefiletools/bin/otapack

    2.1.1. otapack工具命令参数介绍

    -c --create: 创建一个空的升级包文件头,此命令创建文件头的同时可以用-b或-e添加开始或结束升级的脚本。

    -b --begin-script: 在服务器上指定一个shell脚本文件,并把它打包进升级包中用于板子在升级前执行的脚本。

    -e --end-scrip: 在服务器上指定一个shell脚本文件,并把它打包进升级包中用于板子在升级结束后执行的脚本。

    -a --append: 在已经创建的升级包中追加新的头信息,追加新的信息中必须告知升级的相关讯息,具体方法请参考范例,或者在剩余的参数介绍中根据需要配置。

    -s --src-file: 指定服务器上需要更新的源文件路径。

    -d --dst-file: 指定需要更新的目标文件或者分区节点在目标板子中的路径。

    -t --dst-file-size: 需要更新的目标文件或者分区的大小,单位为byte,可以用16/10进制表示。

    -m --file-mode: 指定更新的文件权限,参考Linux的mode_t。

    -o --diff-old: 指定服务器中差分升级的旧文件或者文件夹目录。

    -n --diff-new: 指定服务器中差分升级的新文件或者文件夹目录。

    -l --add-log: 指定字符串信息,使升级每一个block或文件时可获取该字符串信息,限制最大512 byte,此功能在1.2版本开始支持。

    --block-update: 设定服务器中指定的源文件为裸分区数据。

    --ubi-update: 设定服务器中指定的源文件为UBI文件系统的volume。

    --file-update: 设定服务器中指定的源文件为单个文件升级。

    --file-add: 设定服务器中指定的源文件为目标板子中新增加的文件。

    --file-delete: 仅更新打包的数据头,删除板子上指定的目标文件。

    --file-update-diff: 对服务器中设定的新旧文件的差分数据进行打包。

    --dir-update: 扫描新旧两个文件夹中的内容,并比较差异、增加、减少的部分,然后进行批量打包。

    --dir-update-diff: 扫描新旧两个文件夹中的内容,并比较差异、增加、减少的部分,然后进行批量打包。其中差异的文件对其差分数据进行打包。

    --script-add: 在服务器上打包--src-file指定的一个shell脚本在目标板子上执行,执行时显示的脚本文件名为--dst-file所示内容,此功能在0.3版本开始支持。

    --out-layout: 输出ota bin的layout分区表文件, 参数 '-r' 指定 ota bin文件。

    --default-mask: 指定需要更新的目标文件或者分区节点的升级掩码。

    --help: 打印帮助信息。

    --debug: 打开调试信息。

    2.1.2. otaunpack工具命令参数介绍

    -x: 解包并升级压缩的文件

    -r: 解包并升级非压缩的文件

    -t: 指定一个可写的文件夹路径用于差分升级。

    2.1.3. 打包流程举例

    1、 创建一个空的header:

    otapack -c SstarOta.bin
    

    2、 若有需要可以用-b/-e指令添加脚本(start.sh 及end.sh 需要先创建)

    otapack -c SstarOta.bin -b start.sh -e end.sh
    

    3、 根据需要打包的文件更新header数据:

    otapack -a SstarOta.bin -s ./images/kernel -d /dev/mtd3 -t 0x500000 --block-update -l kernel
    

    4、 循环执行步骤3,所有的文件进行打包。

    5、 压缩升级包:

    gzip SstarOta.bin
    

    2.2. 在ALKAID中打包介绍

    OTA打包流程目前已经整合到了Makefile中。

    当程序编译和打包完成后,在project下输入指令:

    make image-ota
    

    会出现如下交互界面,指定在板子上执行的脚本路径,可以选择添加或者不添加(需要预先创建脚本,默认路径是project/image目录下):

    Start scripts:
    
    End scripts:
    

    在打包分区时,列出了打包的分区数据:

    Make ipl ?(yes/no)
    

    做出相关的选择后,会在project/image/output/images/下产生SstarOta.bin.gz

    在配置partition的config文件中会配置分区进行打包。

    举例:

    文件 spinand.squashfs.partition.config中有变量:OTA_IMAGE_LIST,在此变量后面追加需要打包的分区名称,并在分区的配置中添加字段xxx$(OTABLK),配置该分区需要升级的目标节点路径。只有在OTA_IMAGE_LIST添加了分区名,才会在make image-ota的时候会询问该分区是否要进行ota升级。

    分区打包脚本的所有逻辑在image/ota.mk中实现,有兴趣的可以自行研究 。

    注意:

    1. 此打包流程不支持 CIS 和 rootfs 分区打包。
    2. 不支持 boot 分区中的单独分区打包,例如不支持单独打包 ipl/ipl_cust/uboot 等。

    2.3. 不带文件系统的RAW DATA打包

    分区升级步骤是大同小异的,会把需要升级的文件填到对应的目标分区中,因此打包的流程也大体上是一样的。稍有不同的是在RAW DATA分区打包要自行实现升级包头的创建和数据填充,这里以spinand的boot分区打包举例:

    define makeota
    @read -p "Make $(1) ?(yes/no)" select;    \
    if [ "$${select}" == "yes" -o "$${select}" == "y" ]; then    \
        $(PROJ_ROOT)/image/makefiletools/bin/otapack -s $(2) -d "$(3)" -t $(4) -m $(5) $(6) -l "$(1)" -a $(IMAGEDIR)/SStarOta.bin; \
        if [ -n "$($(1)$(BLKENV))" ]; then    \
            echo -e "$($(1)$(BLKENV))" | sed 's/^/\/etc\/fw_setenv /g' > $(IMAGEDIR)/$(1)_otaenv.sh;    \
            $(PROJ_ROOT)/image/makefiletools/bin/otapack -s $(IMAGEDIR)/$(1)_otaenv.sh -d $(1)_otaenv.sh --script-add -l "$(1)" -a $(IMAGEDIR)/SStarOta.bin;    \
        fi;    \
    fi;
    endef
    
    boot_$(FLASH_TYPE)_mkota_:
        $(call makeota,$(patsubst%_$(FLASH_TYPE)_mkota_,%,$@),$(IMAGEDIR)/boot.bin,$($(patsubst%_$(FLASH_TYPE)_mkota_,%,$@)$(OTABLK)),$($(patsubst %_$(FLASH_TYPE)_mkota_,%,$@)$(PATSIZE)),0,--block-update)
    

    2.4. ubifs/squashfs/jffs2/lwfs/lfs/ext4打包

    如果新创建了这些分区,并且把它们加到OTA_IMAGE_LIST中,则无需再ota.mk中添加特殊处理,这一类的分区升级文件会统一处理。

    UBIFS的分区升级方式与其它两种格式稍有差异,因此在打包的时候UBIFS打包的时候请使用--ubi-update

    2.5. 个别文件打包

    个别文件打包的选项是--file-update,目前ALKAID中还没有专门针对文件更新的打包,因此使用者需要手动添加。

    2.6. 脚本文件打包

    选项--script-add可以在服务器上打包一个shell脚本文件,用于板子上执行,在板子上打包的shell脚本文件名由--dst-file制定,也可以不指定。

    2.7. 差分数据打包

    对个别文件进行差分数据打包的选项是--file-update-diff,除了普通文件外,也可以对kernel、uboot等raw image进行差分,也可以对只读文件系统的镜像文件进行差分,但是不可以对可写的文件系统进行差分。

    差分升级需要依赖于第三方开源的bsdiff、bspatch。

    bsdiff工具在打包的时候会使用,bspatch在板子上使用。

    bsdiff、bspatch工具的源码在project/tools/bsdiff

    编译方式:

    tar -vxf bzip2-1.0.6.tar.gz
    
    tar -vxf bsdiff-4.3.tar.gz
    
    cd bzip2-1.0.6
    
    make
    
    cd bsdiff-4.3
    
    make
    

    编译完成后在当前目录下可以看到执行档案bsdiff、bspatch:

    默认编译出来的是pc上使用的,编译板子上使用bspatch请改Makefile。

    编译完成后的bsdiff要放到pc中的/usr/bin/路径下,或者环境变量$PATH所指定的位置。

    同理板子上bspatch也要放到对应的位置,或者环境变量$PATH所指定的位置。

    2.8. 新旧文件夹扫描并批量文件打包

    文件夹扫描分两种,一种是扫描出的有差异的文件进行强制更新。

    --dir-update

    命令举例:

    otapack -a ./test-diff.bin -o ./old/ -n ./new/ -d /config --dir-update
    

    另外一种是扫描出的有差异的文件进行差分升级。

    --dir-update-diff

    命令举例:

    otapack -a ./test-diff.bin -o ./old/ -n ./new/ -d /config --dir-update-diff
    

    3. 分区更新流程

    3.1. 升级流程

    3.2. 分区升级前注意

    在分区升级之前请确保分区umount成功。可以在start scripts脚本中作相关的umount动作。若需更新文件,请确保文件所在可读写的文件系统中,并且有写权限。

    3.3. 压缩的升级包更新

    otaunpack -x SstarOta.bin.gz
    

    3.4. 非压缩的升级包更新

    otaunpack -r SstarOta.bin
    

    3.5. 升级UI显示

    升级时可指定一张全屏的背景图片贴到framebuffer上,图片支持jpg和png格式。同时在framebuffer中绘制进度条,otaunpack在0.2版本之后支持进度条和文字UI旋转,设定-s参数0/½/3支持None/90°/180°/270°旋转。

    otaunpack -x SstarOta.bin.gz -p upgrade.jpg
    

    3.6. 差分升级

    若压缩包中存在差分升级的数据,需要指定一个临时的可以写的文件夹,若不指定,则会在当前目录临时生成 tmp.diff 文件,命令:

    otaunpack -x SstarOta.bin.gz -t /tmp
    

    3.7. 升级状态获取

    升级完成后会显示OTA UPGRADE STATUS,可以获取升级的状态。

    OTA UPGRADE STATUS为0则升级成功,其他返回值则参考5. OTA返回值章节。

    3.8. SPI-NAND坏块处理

    使用--block-update命令打包升级的程序中,如果设定的是mtdblock或者mmcblk块设备节点,这种操作不会处理坏块,推荐nor flash和emmc升级可以使用此节点,若spinand需要升级同时处理坏块,请用--block-update设定为mtd的字符设备节点,otapack和otaunpack应用程序在0.2版本后可以支援使用mtd-utils在升级的时候处理坏快,调用的是busybox中的nand_write和flash_eraseall。

    3.9. 流式更新

    当本地空间没有足够的空间存放OTA包时,请使用流式更新,用户需要通过外部进程向标准输出管道写入数据,再使用otaunpack从标准输出管道读取数据进行更新,命令如下:

    otaunpack -i "External Commands"
    

    如果是使用差分升级,命令如下:

    otaunpack -i "External Commands" -t /tmp
    

    4. A/B分区打包与升级

    4.1. A/B分区打包

    被升级的镜像文件有可能在升级时所要升级的目标分区或者文件可能有多个匹配,一般地会存在A、B两组分区,这两组分区互为备份。

    在不考虑A/B分区互为备份的启动流程的基础上,A/B分区的打包要考虑到匹配多种升级目标路径,或者匹配多个备份升级文件,具体有以下两种情况:

    1. 单个镜像源文件对应多个目标地址

      例如KERNEL分区,对应/dev/mtd4和/dev/mtd5,那么在打包时,-d选项可以带多个目标路径例如:

      ./otapack -s ./KERNEL -d “/dev/mtd4 /dev/mtd5”
      
    2. 多个镜像源文件对应单个目标地址

      与非A/B分区的打包设定无异,在打包时可以填入同样的目的地址。

    4.2. 分区表

    在1.3版本之后支持输出分区表

    命令:

    ./otapack --out-layout layout.txt -r pack.bin
    

    --out-layout:指定输出的分区表文件名称以及路径

    -r:指定OTA升级包,必须是未压缩的

    输出的分区表格式:

    0,boot.bin,/dev/mtd0,0x1
    0,boot.bin,/dev/mtd1,0x1
    1,kernel,/dev/mtd3,0x1
    1,kernel,/dev/mtd4,0x1
    2,kernel_otaenv.sh,kernel_otaenv.sh,0x1
    3,misc.fwfs,/dev/mtd6,0x1
    4,miservice.ubifs,/dev/ubi0_0,0x1
    5,customer.ubifs,/dev/ubi0_1,0x1
    

    其中每一行用于描述一个分区的信息,格式如下:

    [image id],[dst file name],[destination path],[upgrade mask]
    

    image id:每个分区或者文件都有一个唯一的序号。

    dst file name:分区或者文件打包时填入的文件名。

    destination path:目标地址,当有多个目标时有可能同样的分区不同的目标地址用多行表示,例如上表分区boot.bin。

    upgrade mask:升级掩码,可以人工修改掩码,用于改变升级策略,升级掩码必须是16进制,必须带前缀‘0x’。

    4.3. A/B分区升级

    使用otapack工具输出分区表之后,可以人工通过修改升级掩码用于定义升级的方式。

    请注意,分区表仅可由otapack工具生成,除了升级掩码之外,不可以修改任何字符。

    利用分区表进行升级的命令在原来使用otaunpack的命令基础上增加-y指定分区表,增加-m配置升级时所要参考的升级掩码。

    升级时参数-m与实际的-y所指定的分区表中所定义的升级掩码进行逻辑与运算(&),如果结果不为0,则表示可以升级,那么otaunpack则进行升级操作。

    工具otapack默认输出的升级掩码为0x1,在otaunpack升级时使用-m 0x1即可默认升级全部分区。

    举例:

    KERNEL分区有2个目标路径,所对应分区表中的2行信息:

    1,kernel,/dev/mtd3,0x2
    
    1,kernel,/dev/mtd4,0x4
    

    若定义目标路径/dev/mtd3为A分区,定义/dev/mtd4为B分区,则前者使用升级掩码为‘0x2’(bit1),后者使用‘0x4’(bit2),那么在升级A分区时使用的命令是:

    ./otaunpack -r pack.bin -y layout.txt -m 0x2
    

    升级B分区,使用的命令是:

    ./otaunpack -r pack.bin -y layout.txt -m 0x4
    

    若定义的分区表中只有部分分区是分A/B分区的,例如下表,那么还是通过指定A分区的升级掩码为‘0x2’,B分区的升级掩码为‘0x4’,非A/B分区的升级掩码为‘0x1’

    0,boot.bin,/dev/mtd0,0x2
    0,boot.bin,/dev/mtd1,0x4
    1,kernel,/dev/mtd3,0x2
    1,kernel,/dev/mtd4,0x4
    2,kernel_otaenv.sh,kernel_otaenv.sh,0x1
    3,misc.fwfs,/dev/mtd6,0x1
    4,miservice.ubifs,/dev/ubi0_0,0x1
    5,customer.ubifs,/dev/ubi0_1,0x1
    

    那么在升级时有多种选择。

    只升级A分区时使用的命令是:

    ./otaunpack -r pack.bin -y layout.txt -m 0x2
    

    只升级B分区,使用的命令是:

    ./otaunpack -r pack.bin -y layout.txt -m 0x4
    

    升级A分区和普通分区时使用的命令是:

    ./otaunpack -r pack.bin -y layout.txt -m 0x3
    

    升级B分区和普通分区时使用的命令是:

    ./otaunpack -r pack.bin -y layout.txt -m 0x5
    

    5. OTA返回值

    1. OTAPACK返回值说明如表所示。

      返回值 描述
      0 返回成功
      -1 返回失败
    2. OTAUNPACK返回值说明如表所示。

      返回值 描述
      0 返回成功
      1 参数错误 或 升级包校验失败
      2 begin-script脚本执行失败
      3 升级过程产生IO异常

    返回值可以通过shell命令"echo $?"获取。返回值流程图说明如下:

    6. 版本更新记录

    版本号 说明
    0.1 初始版本
    0.2 支援使用mtd-utils在升级的时候处理坏块
    0.3 增加--script-add功能,可以任意打包要处理的shell脚本
    1.2 该版本主要是为了更好的支持用户做A/B分区备份升级功能而修改的
    1、支持一份源文件多个dst路径升级
    举例:
    otapack xxx -s ./images/kernel -d “/dev/mtd8 /dev/mtd9” xxx
    “-d” 参数后用空格隔开若干个路径,以上例子中,在升级时能够同时升级mtd8和mtd9,或者其中之一,只有目标路径同时打开失败才会导致升级流程失败。这个功能可以避免同一份src打包两次的情况,也可以让用户有选择的升级目标路径。
    2、增加选项”-l --add-log”,用户可以使每一个被升级的文件用字符串标记
    举例:
    otapack xxx -s ./images/kernel -l kernel xxx
    那么在otaunpack的main.c中可以在fpFileOpen的回调函数中通过”ps8UserLog”获取该字符串,这样能够在otaunpack中识别用户打包的文件,从而能更加方便地二次开发用户的升级代码。
    3、升级文件的校验机制由原来的checksum改成了md5
    1.3 此版本在原1.2版本上进一步优化。
    1、移除fpFileOpen中ps8UserLog
    2、在otaunpack中新增加callback函数fpFileAccess
    3、该函数在升级任何文件或分区时都会先执行,并询问是否可以升级,返回-1则跳过,返回0表示允许升级。
    4、fpFileAccess有四个形参分别是:
    “const char *pOpenData”,“unsigned int u32ImageId”,“ unsigned int u32PathId”、“const char *ps8UserLog”。
    “const char *pOpenData”:为要升级目标文件或分区的路径。
    “unsigned int u32ImageId”,当前所要升级的文件或者分区所对应的唯一id。
    “unsigned int u32PathId”: 当一个image对应多个Dst目标分区或者文件位置时,按照顺序升级的序号。
    “const char *ps8UserLog”: 该升级image在打包时使用-l带入的字符串。
    1.5 此版本支援打包时生成分区表及升级时指定 mask 进行升级
    1.打包时生成分区表
    举例:otapack --out-layout SStarOtaLayout.txt -r SStarOta.bin
    2.通过 mask 指定分区升级
    举例:otaunpack -x SStarOta.bin.gz -y SStarOtaLayout.txt -m 0x2
    1.6 此版本在原1.5版本上进一步优化。
    1.OTA返回值的说明
    2.支持流式更新功能
    举例:otaunpack -i "External Commands"