Rockchip RK3588 - Rockchip Linux Recovery rkupdate升级

----------------------------------------------------------------------------------------------------------------------------

开发板 :ArmSoM-Sige7开发板eMMC64GBLPDDR48GB
显示屏 :15.6英寸HDMI接口显示屏u-boot2017.09linux5.10
----------------------------------------------------------------------------------------------------------------------------

如果对Rockchip Linux SDK不了解的前提下,请先阅读以下两篇文章:

  • Rockchip RK3588 - Rockchip Linux SDK编译》;
  • Rockchip RK3588 - Rockchip Linux SDK Buildroot文件系统构建》。

一、rkupdate in & mk分析

接下来我们来研究《配置recovery》小节中我们添加了如下配置项究竟实现了什么功能;

#rkupdate升级方式配置项
BR2_PACKAGE_RKUPDATE=y

注意:本节仅仅分析rkupdate升级方式。

在为Buildroot自定义软件包时,在软件包目录下通常为引入.in.mk文件;

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll package/rockchip/rkupdate/
-rw-r--r--  1 root root  704  6月  9 12:58 Config.in
-rw-r--r--  1 root root   82  6月  9 12:58 rkupdate.hash
-rw-r--r--  1 root root 1017  6月  9 12:58 rkupdate.mk
1.1 Config.in

我们首先从Config.in文件入手,该文件实际上就是定义make menuconfig支持的配置选项;

config BR2_PACKAGE_RKUPDATE
        bool "Rockchip rkupdate for linux"
        depends on BR2_TOOLCHAIN_HAS_THREADS # libpthread-stubs  此配置项依赖于BR2_TOOLCHAIN_HAS_THREADS(其开启的情况下才可用)
        select BR2_PACKAGE_LIBPTHREAD_STUBS   # 如果启动,自动选择启用以下列出的其他软件包和库
        select BR2_PACKAGE_UTIL_LINUX
        select BR2_PACKAGE_UTIL_LINUX_LIBUUID
        help
          Rockchip rkupdate for linux.

if BR2_PACKAGE_RKUPDATE

config BR2_PACKAGE_RKUPDATE_SINGNATURE_FW
        bool "update signature firmware"
        help
                update signature firmware.

config BR2_PACKAGE_RKUPDATE_SIMULATE_ABNORMAL_POWER_OFF
        bool "simulate abnormal power off during updating fw"
        help
                simulate abnormal power off during updating fw.

config BR2_PACKAGE_RKUPDATE_STATIC
        bool "Enable static"
        default y if BR2_STATIC_LIBS
        select BR2_PACKAGE_UTIL_LINUX_STATIC

endif

由于我们勾选了Rockchip rkupdate for linux,因此在生成的output/rockchip_rk3588_recovery/.config配置文件会配置:

BR2_PACKAGE_RKUPDATE=y
1.2 rkupdate.mk

buildroot编译rkupdate所需要的设置rkupdate.mk,包括源码位置、安装目录、权限设置等。

################################################################################
#
# Rockchip rkupdate For Linux
#
################################################################################

RKUPDATE_VERSION = develop
RKUPDATE_SITE = $(TOPDIR)/../external/rkupdate
RKUPDATE_SITE_METHOD = local

RKUPDATE_LICENSE = Apache V2.0
RKUPDATE_LICENSE_FILES = NOTICE

RKUPDATE_DEPENDENCIES = \
        libpthread-stubs util-linux

RKUPDATE_CFLAGS = $(TARGET_CFLAGS) -fPIC -lpthread -luuid

ifeq ($(BR2_PACKAGE_RKUPDATE_SINGNATURE_FW),y)
RKUPDATE_CFLAGS += -DUSE_SIGNATURE_FW=ON
endif

ifeq ($(BR2_PACKAGE_RKUPDATE_SIMULATE_ABNORMAL_POWER_OFF),y)
RKUPDATE_CFLAGS += -DUSE_SIMULATE_POWER_OFF=ON
endif

ifeq ($(BR2_PACKAGE_RKUPDATE_STATIC),y)
RKUPDATE_CFLAGS += -static
endif

define RKUPDATE_BUILD_CMDS
        $(TARGET_MAKE_ENV) $(MAKE) -C $(@D) \
                CXX="$(TARGET_CXX)" CFLAGS="$(RKUPDATE_CFLAGS)"
endef

define RKUPDATE_INSTALL_TARGET_CMDS
        $(INSTALL) -D -m 755 $(@D)/rkupdate $(TARGET_DIR)/usr/bin/
endef

$(eval $(generic-package))
1.2.1 约定配置

首先映入眼帘的是一些约定的配置:

  • RKUPDATE_VERSION:定义了源码的版本号为develop
  • RKUPDATE_SITE:定义了源码下载地址,这里指定为<SDK>/external/rkupdate
  • RKUPDATE_SITE_METHOD:定义了源码下载的方式,该处指定为本地获取(local);
  • RKUPDATE_LICENSE:设置许可证类型为Apache V2.0
  • RKUPDATE_LICENSE_FILES:设置许可证文件NOTICE
1.2.2 编译选项

接下来的是编译选项和依赖关系配置:

(1) RKUPDATE_CFLAGS:编译选项配置,包括开启线程支持、uuid等;

RKUPDATE_CFLAGS = $(TARGET_CFLAGS) -fPIC -lpthread -luuid

其中:

  • -fPICGCC和其他兼容编译器的选项,表示生成位置无关的代码,用于动态链接库。这是因为动态链接库在编译时无法确定加载地址,因此需要生成位置无关的代码;
  • -lpthread:表示链接pthread库,即POSIX线程库,用于多线程编程;
  • -luuid:表示链接uuid库,该库提供了生成和操作通用唯一标识符的函数。

这些选项通常用于构建需要多线程、uuid支持的应用程序或库。在编译时,它们告诉编译器在链接阶段需要使用这些特定的外部库。

(2) RKUPDATE_DEPENDENCIES:定义依赖项,包括libpthread-stubsutil-linux,这样在编译rkupdate软件包的时候才会构建和安装依赖包。

1.2.3 条件编译配置

紧跟着的就是一些条件编译配置项;

ifeq ($(BR2_PACKAGE_RKUPDATE_SINGNATURE_FW),y)
RKUPDATE_CFLAGS += -DUSE_SIGNATURE_FW=ON   # 不走这里
endif

ifeq ($(BR2_PACKAGE_RKUPDATE_SIMULATE_ABNORMAL_POWER_OFF),y)
RKUPDATE_CFLAGS += -DUSE_SIMULATE_POWER_OFF=ON  # 不走这里
endif

ifeq ($(BR2_PACKAGE_RKUPDATE_STATIC),y)
RKUPDATE_CFLAGS += -static # 不走这里
endif

由于这些配置项我们都未开启,因此直接跳过。

1.2.4 CMD命令之BUILD

接着是定义一系列的编译命令,这些_CMD结尾的变量会在buildroot框架编译的时候执行,用于给源码的Makefile传递编译选项和链接选项,调用源码的Makefile

define RKUPDATE_BUILD_CMDS
        $(TARGET_MAKE_ENV) $(MAKE) -C $(@D) \
                CXX="$(TARGET_CXX)" CFLAGS="$(RKUPDATE_CFLAGS)"
endef

RKUPDATE_BUILD_CMDSmake <pkg>build阶段被执行;

(TARGET_MAKE_ENV) $(MAKE) -C $(@D) CC="$(TARGET_CC)" CFLAGS="$(RKUPDATE_CFLAGS)"

这里同updateEngine源码分析,不再重复介绍。其中:

  • MAKE变量值被设置为make
  • CC变量值被设置为$(TARGET_CC)
  • CFLAGS变量值被设置为$(RKUPDATE_CFLAGS)

其中:

TARGET_CC = <SDK>/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-gcc

RKUPDATE_CFLAGS = $(TARGET_CFLAGS) -fPIC -lpthread -luuid

我们知道buildroot软件包在编译时会将源码拷贝到output/rockchip_rk3588_recovery/build目录下,rkupdate软件包对应的目录为rkupdate-develop

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ ll output/rockchip_rk3588_recovery/build/rkupdate-develop/
-rw-r--r--  1 root root    860  6月  9 12:59 Android.mk
-rwxr-xr-x  1 root root    832  6月 18 01:48 .build.sh*
-rwxr-xr-x  1 root root    158  6月 18 01:48 .configure.sh*
-rw-r--r--  1 root root  13748  6月  9 12:59 CRC.cpp
-rw-r--r--  1 root root   7648  6月 18 01:48 CRC.o
-rw-r--r--  1 root root   9516  6月  9 12:59 DefineHeader.h
-rwxr-xr-x  1 root root    795  6月 18 01:48 .deploy.sh*
-rw-r--r--  1 root root   1170  6月  9 12:59 Endian.h
-rw-r--r--  1 root root      0  6月 18 01:48 .files-list-host.txt
-rw-r--r--  1 root root      0  6月 18 01:48 .files-list-images.txt
-rw-r--r--  1 root root      0  6月 18 01:48 .files-list-staging.txt
-rw-r--r--  1 root root     19  6月 18 01:48 .files-list-target.txt
-rw-r--r--  1 root root     28  6月 18 01:48 .files-list.txt
-rw-r--r--  1 root root   5145  6月  9 12:59 gpt.h
-rw-r--r--  1 root root   1574  6月  9 12:59 LICENSE
-rw-r--r--  1 root root   1435  6月  9 12:59 main.cpp
-rw-r--r--  1 root root   3696  6月 18 01:48 main.o
-rw-r--r--  1 root root    360  6月  9 12:59 Makefile
-rw-r--r--  1 root root  25035  6月  9 12:59 MD5Checksum.cpp
-rw-r--r--  1 root root   4792  6月  9 12:59 MD5ChecksumDefines.h
-rw-r--r--  1 root root  16694  6月  9 12:59 MD5Checksum.h
-rw-r--r--  1 root root  17984  6月 18 01:48 MD5Checksum.o
-rw-r--r--  1 root root   2633  6月  9 12:59 Property.hpp
-rw-r--r--  1 root root 116700  6月  9 12:59 RKAndroidDevice.cpp
-rw-r--r--  1 root root   9743  6月  9 12:59 RKAndroidDevice.h
-rw-r--r--  1 root root  87464  6月 18 01:48 RKAndroidDevice.o
-rw-r--r--  1 root root   8826  6月  9 12:59 RKBoot.cpp
-rw-r--r--  1 root root   2879  6月  9 12:59 RKBoot.h
-rw-r--r--  1 root root   6840  6月 18 01:48 RKBoot.o
-rw-r--r--  1 root root  17886  6月  9 12:59 RKComm.cpp
-rw-r--r--  1 root root   7447  6月  9 12:59 RKComm.h
-rw-r--r--  1 root root  22200  6月 18 01:48 RKComm.o
-rw-r--r--  1 root root  18278  6月  9 12:59 RKDevice.cpp
-rw-r--r--  1 root root   6709  6月  9 12:59 RKDevice.h
-rw-r--r--  1 root root  15728  6月 18 01:48 RKDevice.o
-rw-r--r--  1 root root  10811  6月  9 12:59 RKImage.cpp
-rw-r--r--  1 root root   2494  6月  9 12:59 RKImage.h
-rw-r--r--  1 root root  14488  6月 18 01:48 RKImage.o
-rw-r--r--  1 root root   1365  6月  9 12:59 RKLog.cpp
-rw-r--r--  1 root root    586  6月  9 12:59 RKLog.h
-rw-r--r--  1 root root   6048  6月 18 01:48 RKLog.o
-rwxr-xr-x  1 root root 132992  6月 18 01:48 rkupdate*
-rw-r--r--  1 root root 143360  6月 18 01:48 rkupdate-develop.tar
-rw-r--r--  1 root root      0  6月 18 01:48 .stamp_built
-rw-r--r--  1 root root      0  6月 18 01:48 .stamp_configured
-rw-r--r--  1 root root      0  6月 18 01:48 .stamp_installed
-rw-r--r--  1 root root      0  6月 18 01:48 .stamp_rsynced
-rw-r--r--  1 root root      0  6月 18 01:48 .stamp_target_installed
-rwxr-xr-x  1 root root   2700  6月 18 01:48 .target_install.sh*
-rwxr-xr-x  1 root root    984  6月 18 01:48 .update.sh*
-rw-r--r--  1 root root  37184  6月  9 12:59 Upgrade.cpp
-rw-r--r--  1 root root    440  6月  9 12:59 Upgrade.h
-rw-r--r--  1 root root  41432  6月 18 01:48 Upgrade.o
1.2.5 CMD命令之INSTALL
define RKUPDATE_INSTALL_TARGET_CMDS
        $(INSTALL) -D -m 755 $(@D)/rkupdate $(TARGET_DIR)/usr/bin/
endef

这行命令使用了makefile中定义的INSTALL变量,以及自动变量$(@D)和预定义变量TARGET_DIR。它的作用是将源码rkupdate编译出来的rkupdate可执行文件安装到目标系统的/usr/bin/目录下,并设置相应的权限;

因此如果在recovery软件包编译安装完成后,我们可以在<SDK>/buildroot/output/rockchip_rk3588_recovery/target/usr/bin中看到rkupdate可执行文件;

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$  ll output/rockchip_rk3588_recovery/target/usr/bin/rkupdate
-rwxr-xr-x 1 root root 106568  6月 18 01:48 output/rockchip_rk3588_recovery/target/usr/bin/rkupdate*
1.2.6 $(eval $(generic-package))

($eval$(generic-package)) 最核心的就是这个东西了,一定不能够漏了,不然源码不会被编译,这个函数就是把整个.mk构建脚本,通过Buildroot框架的方式,展开到Buildroot/目录下的Makfile中,生成的构建目标。

1.3 Makefile

经过前面对rkupdate.mk的分析,我们已经知道rkupdate的源码位于本地<SDK>/external/rkupdate目录;

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp$ ll external/rkupdate/
-rw-r--r--  1 root root    860  6月  9 12:59 Android.mk
-rw-r--r--  1 root root  13748  6月  9 12:59 CRC.cpp
-rw-r--r--  1 root root   9516  6月  9 12:59 DefineHeader.h
-rw-r--r--  1 root root   1170  6月  9 12:59 Endian.h
-rw-r--r--  1 root root   5145  6月  9 12:59 gpt.h
-rw-r--r--  1 root root   1574  6月  9 12:59 LICENSE
-rw-r--r--  1 root root   1435  6月  9 12:59 main.cpp
-rw-r--r--  1 root root    360  6月  9 12:59 Makefile
-rw-r--r--  1 root root  25035  6月  9 12:59 MD5Checksum.cpp
-rw-r--r--  1 root root   4792  6月  9 12:59 MD5ChecksumDefines.h
-rw-r--r--  1 root root  16694  6月  9 12:59 MD5Checksum.h
-rw-r--r--  1 root root   2633  6月  9 12:59 Property.hpp
-rw-r--r--  1 root root 116700  6月  9 12:59 RKAndroidDevice.cpp
-rw-r--r--  1 root root   9743  6月  9 12:59 RKAndroidDevice.h
-rw-r--r--  1 root root   8826  6月  9 12:59 RKBoot.cpp
-rw-r--r--  1 root root   2879  6月  9 12:59 RKBoot.h
-rw-r--r--  1 root root  17886  6月  9 12:59 RKComm.cpp
-rw-r--r--  1 root root   7447  6月  9 12:59 RKComm.h
-rw-r--r--  1 root root  18278  6月  9 12:59 RKDevice.cpp
-rw-r--r--  1 root root   6709  6月  9 12:59 RKDevice.h
-rw-r--r--  1 root root  10811  6月  9 12:59 RKImage.cpp
-rw-r--r--  1 root root   2494  6月  9 12:59 RKImage.h
-rw-r--r--  1 root root   1365  6月  9 12:59 RKLog.cpp
-rw-r--r--  1 root root    586  6月  9 12:59 RKLog.h
-rw-r--r--  1 root root  37184  6月  9 12:59 Upgrade.cpp
-rw-r--r--  1 root root    440  6月  9 12:59 Upgrade.h

首先我们需要了解源码的Makefile是怎么样的,其内容如下;

点击查看代码
PROJECT_DIR := $(shell pwd)
PROM = rkupdate
OBJ =CRC.o \
        MD5Checksum.o \
        RKAndroidDevice.o \
        RKBoot.o \
        RKComm.o \
        RKDevice.o \
        RKImage.o \
        RKLog.o \
        Upgrade.o \
        main.o

$(PROM): $(OBJ)
        $(CXX) -o $(PROM) $(OBJ) $(CFLAGS)

%.o: %.cpp
        $(CXX) -c $< -o $@ $(CFLAGS)

clean:
        rm -rf $(OBJ) $(PROM)

install:
        sudo install -D -m 755 $(PROJECT_DIR)/rkupdate -t $(DESTDIR)/usr/bin/

这段脚本写的比较简单,在编译rkupdate软件包的build阶段,会执行如下命令;

(TARGET_MAKE_ENV) $(MAKE) -C $(@D) CC="$(TARGET_CC)" CFLAGS="$(RKUPDATE_CFLAGS)"

其中:

  • CC<SDK>/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-gcc
  • CFLAGS$(TARGET_CFLAGS) -fPIC -lpthread -luuid
1.3.1 变量定义

脚本开始定义了一些变量:

  • PROJECT_DIR:既时变量,值在定义时就确定,为当前工作路径;
  • PROM:延时变量,值在使用的时候才确定,这里设置为rkupdate
1.3.2 目标rkupdate

第一个目标rkupdate,是由若干个.o文件通过aarch64-buildroot-linux-gnu-gcc编译器链接生成的可执行文件。

OBJ =CRC.o \
        MD5Checksum.o \
        RKAndroidDevice.o \
        RKBoot.o \
        RKComm.o \
        RKDevice.o \
        RKImage.o \
        RKLog.o \
        Upgrade.o \
        main.o

$(PROM): $(OBJ)
        $(CXX) -o $(PROM) $(OBJ) $(CFLAGS)

.o文件实际上是由.c文件通过aarch64-buildroot-linux-gnu-gcc编译器编译生成的。

%.o: %.cpp
        $(CXX) -c $< -o $@ $(CFLAGS)
1.3.3 目标clean

伪目标clean用于执行清理工作;

clean:
        rm -rf $(OBJ) $(PROM)
1.3.4 目标install

伪目标install用于执行安装工作;

install:
        sudo install -D -m 755 $(PROJECT_DIR)/rkupdate -t $(DESTDIR)/usr/bin/
1.4 编译

在《Rockchip RK3588 - Rockchip Linux SDK Buildroot文件系统构建》中介绍过buildroot编译命令;

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make -j8

或者使用如下命令单独编译rkupdate软件包:

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make rkupdate-dirclean
root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot$ sudo make rkupdate

其中rkupdate编译日志如下:

点击查看代码
>>> rkupdate develop Syncing from source dir /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/../external/rkupdate
rsync -au --chmod=u=rwX,go=rX  --exclude .svn --exclude .git --exclude .hg --exclude .bzr --exclude CVS /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/../external/rkupdate/ /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/rkupdate-develop
>>> rkupdate develop Configuring
>>> rkupdate develop Building
PATH="/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin" /usr/bin/make  -C /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/rkupdate-develop CXX="/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++" CFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid"
make[1]: 进入目录“/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/rkupdate-develop”
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c CRC.cpp -o CRC.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c MD5Checksum.cpp -o MD5Checksum.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c RKAndroidDevice.cpp -o RKAndroidDevice.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c RKBoot.cpp -o RKBoot.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c RKComm.cpp -o RKComm.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c RKDevice.cpp -o RKDevice.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c RKImage.cpp -o RKImage.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c RKLog.cpp -o RKLog.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c Upgrade.cpp -o Upgrade.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -c main.cpp -o main.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++ -o rkupdate CRC.o MD5Checksum.o RKAndroidDevice.o RKBoot.o RKComm.o RKDevice.o RKImage.o RKLog.o Upgrade.o main.o -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid
make[1]: 离开目录“/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/rkupdate-develop”
>>> rkupdate develop Installing to target
/usr/bin/install -D -m 755 /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/rkupdate-develop/rkupdate /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/target/usr/bin/

在日志中输出了rkupdate软件包构建的各个阶段的信息,可以验证我们之前的分析是否正确。比如编译命令:

PATH="/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/sbin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin" /usr/bin/make  -C /work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/build/rkupdate-develop CXX="/work/sambashare/rk3588/armsom/armsom-rk3588-bsp/buildroot/output/rockchip_rk3588_recovery/host/bin/aarch64-buildroot-linux-gnu-g++" CFLAGS="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -Os -g0 -D_FORTIFY_SOURCE=1 -fPIC -lpthread -luuid"

二、rkupdate源码分析

由于rkupdate可执行文件是由 MD5Checksum.cRKAndroidDevice.cRKBoot.cRKComm.cRKDevice.cRKImage.cRKLog.cUpgrade.cmain.c文件编译而成,程序的入口为main.cpp文件。

2.1 main.cpp

main函数实现如下:

FILE *cmd_pipe = NULL;
int sdBootUpdate = 0;

int main(int argc, char *argv[])
{
    int status;

    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
    if (argc != 5)
    {
        printf("unexpected number of arguments (%d)\n", argc);
        fprintf(stderr, "unexpected number of arguments (%d)\n", argc);
        return 1;
    }
    int fd = atoi(argv[2]);
    cmd_pipe = fdopen(fd, "wb");
    setlinebuf(cmd_pipe);

    char *filepath = argv[3];
    sdBootUpdate = atoi(argv[4]);

    //call update
    bool bRet = do_rk_firmware_upgrade(filepath, (void *)handle_upgrade_callback,
                                       (void *)handle_upgrade_progress_callback);

    if (!bRet)
    {
        status = INSTALL_ERROR;
    }
    else
    {
        status = INSTALL_SUCCESS;
    }

    sleep(5);
    sync();
    return status;
}

函数接收5个参数:

  • 第一个参数为当前可执行文件,即rkupdate
  • 第二个参数:
  • 第三个参数是文件描述符fd
  • 第四个参数为升级的固件文件filepath,比如/userdata/update.img
  • 第五个参数为sdBootUpdate:指明当前设备启动方式是否为SD启动;

main函数内部主要调用do_rk_firmware_upgrade来实现固件的升级,函数接收4个参数;

  • szFw:需要升级的固件文件路径;
  • pCallback:固件升级回调函数;
  • pProgressCallback:固件升级进度回调函数;
  • szBootDev:设备是否是SD卡启动;
2.2 Upgrade.cpp

do_rk_firmware_upgrade函数位于Upgrade.cpp文件;

UpgradeCallbackFunc g_callback = NULL;
UpgradeProgressCallbackFunc g_progress_callback = NULL;

extern int sdBootUpdate;
bool do_rk_firmware_upgrade(char *szFw, void *pCallback, void *pProgressCallback, char *szBootDev)
{
    bool bSuccess = false, bRet = false, bLock;
    int iRet;
    CRKImage *pImage = NULL;
    CRKLog *pLog = NULL;
    CRKAndroidDevice *pDevice = NULL;
    CRKComm *pComm = NULL;
    STRUCT_RKDEVICE_DESC device;
    BYTE key[514];
    UINT nKeySize = 514;
    BYTE uid[RKDEVICE_UID_LEN];
    tstring strFw = szFw;
    tstring strUid;
    bool bUpdateLoader = true;

    // 1. 设置了全局的回调函数,并立即调用进度回调函数报告0.1的进度和10秒的耗时。
    g_callback = (UpgradeCallbackFunc)pCallback;
    g_progress_callback = (UpgradeProgressCallbackFunc)pProgressCallback;
    if (g_progress_callback)
    {
        g_progress_callback(0.1, 10);
    }

    // 2. 初始化日志对象pLog用于记录升级过程中的信息
    pLog = new CRKLog();
    if (!pLog)
    {
        goto EXIT_UPGRADE;
    }
    pLog->Record("Start to upgrade firmware...");
    
    // 3. 创建固件镜像对象pImage
    pImage = new CRKImage(strFw, bRet);
    if (!bRet)
    {
        pLog->Record("ERROR:do_rk_firmware_upgrade-->new CRKImage failed!");
        goto EXIT_UPGRADE;
    }
    
    // 4. 创建通信对象pComm用于后续的设备交互
    pComm = new CRKUsbComm(pLog);
    if (!pComm)
    {
        pLog->Record("ERROR:do_rk_firmware_upgrade-->new CRKComm failed!");
        goto EXIT_UPGRADE;
    }

    // 5. 创建设备对象pDevice	
    pDevice = new CRKAndroidDevice(device);
    if (!pDevice)
    {
        pLog->Record("ERROR:do_rk_firmware_upgrade-->new CRKAndroidDevice failed!");
        goto EXIT_UPGRADE;
    }
    pDevice->SetObject(pImage, pComm, pLog);

    // 6. 如果设备不是eMMC闪存,则生成并记录UUID。
    if (!pComm->RKU_IsEmmcFlash())    //chad.ma if is Emmc flash don't create UUID.
    {
        if (CreateUid(uid))
        {
            pDevice->Uid = uid;
            pLog->PrintBuffer(strUid, uid, RKDEVICE_UID_LEN);
            pLog->Record("uid:%s", strUid.c_str());
        }
    }

    // 7. 获取闪存信息
    pDevice->m_pCallback = (UpgradeCallbackFunc)pCallback;
    pDevice->m_pProcessCallback = (UpgradeProgressCallbackFunc)pProgressCallback;
    pLog->Record("Get FlashInfo...");
    bRet = pDevice->GetFlashInfo();
    if (!bRet)
    {
        pLog->Record("ERROR:do_rk_firmware_upgrade-->GetFlashInfo failed!");
        goto EXIT_UPGRADE;
    }

    // 8. 判断升级的固件是否存在bootloader
    bUpdateLoader = pDevice->IsExistBootloaderInFw();

    if (IsRK3308_Platform() && Compatible_rk3308bs_loader())
    {
   		// rk3308 才会进入
        .......
    }

    #ifndef USE_SIGNATURE_FW           // 未定义进入
    if (bUpdateLoader)        // 更新bootloader
    {
        printf("############### update bootloader start ############\n");

        pLog->Record("IDBlock Preparing...");
        printf("\t\t############### IDBlock Preparing...\n");
        iRet = pDevice->PrepareIDB();
        if (iRet != ERR_SUCCESS)
        {
            pLog->Record("ERROR:do_rk_firmware_upgrade-->PrepareIDB failed!");
            goto EXIT_UPGRADE;
        }
        pLog->Record("IDBlock Writing...");
        printf("\t\t############### IDBlock Writing...\n");
        iRet = pDevice->DownloadIDBlock();
        if (iRet != ERR_SUCCESS)
        {
            pLog->Record("ERROR:do_rk_firmware_upgrade-->DownloadIDBlock failed!");
            goto EXIT_UPGRADE;
        }
        printf("############### update bootloader Success############\n");

        if (strFw.find(_T(".bin")) != tstring::npos)
        {
            pLog->Record("INFO:do_rk_firmware_upgrade-->Download loader only success!");
            bSuccess = true;
            return bSuccess;
        }
    }

    // 9. 下载固件
    iRet = pDevice->DownloadImage();
    if (iRet != ERR_SUCCESS)
    {
        pLog->Record("ERROR:do_rk_firmware_upgrade-->DownloadImage failed!");
        goto EXIT_UPGRADE;
    }

    #else                 // 不会进入
    printf("use signature firmware to update.\n");
	......
    #endif

    bSuccess = true;

EXIT_UPGRADE:
    if (bSuccess)
    {
        pLog->Record("Finish to upgrade firmware.");
    }
    else
    {
        pLog->Record("Fail to upgrade firmware!");
    }
    if (pLog)
    {
        delete pLog;
        pLog = NULL;
    }
    if (pImage)
    {
        delete pImage;
        pImage = NULL;
    }
    if (pDevice)
    {
        delete pDevice;
        pDevice = NULL;
    }
    else
    {
        if (pComm)
        {
            delete pComm;
            pComm = NULL;
        }
    }

    return bSuccess;
}

三、系统升级测试

3.1 buildroot系统升级

首先我们需要将我们制作的统一固件update.img(这里采用的buildroot系统)烧录到开发板eMMC中,具体烧录步骤可以参考《Rockchip RK3588 - Rockchip Linux SDK编译》。

需要注意的是:我们烧录的buildroot文件系统要按照本篇博客第一节的配置进行编译,即编译出来的rootfs.imgrecovery.img包含用于升级的updateEnginerkupdate可执行文件;

root@rk3588-buildroot:~# ls /usr/bin/updateEngine -l
-rwxr-xr-x    1 root     root         80544 Jun 17 17:48 /usr/bin/updateEngine
root@rk3588-buildroot:~# ls /usr/bin/rkupdate -l
-rwxr-xr-x    1 root     root        106568 Jun 17 17:48 /usr/bin/rkupdate
3.1.1 制作升级固件

按照正常的固件编译流程,制作用于升级的update.img固件,可以参考《Rockchip RK3588 - Rockchip Linux SDK编译》。

升级固件不一定要全分区升级,可修改 package-file 文件,将不要升级的分区去掉,这样可以减少升级包的大小。

例如,执行如下命令(可参考文件tools/linux/Linux_Pack_Firmware/rockdev/rk3588-package-file):

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp$ sudo ./build.sh edit-package-file

rootfs的相对路径改为 RESERVED,这样就不会打包根文件系统,即不升级根文件系统分区。

# NAME  PATH
package-file    package-file
parameter       parameter.txt
bootloader      MiniLoaderAll.bin
uboot   uboot.img
misc    misc.img
boot    boot.img
recovery        recovery.img
backup  RESERVED
rootfs  rootfs.img
oem     oem.img
userdata  RESERVED

注意: 若将升级固件放至设备的/userdata/目录,则不要打包userdata.img,需要将image/userdata.img改为RESERVED

执行如下命令生成统一固件;

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp$ sudo ./build.sh updateimg

将制作好的升级固件拷贝到U盘、TF卡或者开发版的/userdata/目录下。

我们可以将统一镜像复制到/work/tftpwork目录下:

root@ubuntu:/work/sambashare/rk3588/armsom/armsom-rk3588-bsp$ cp ./rockdev/update.img /work/tftpboot/
3.1.2 rkupdate升级测试

rkupdate升级流程如下:

  • 将升级固件update.img放在SD卡或U盘根目录或者设备的/userdata目录下;
  • normal系统下执行升级程序update ota /xxx/update.img
  • 升级recovery分区;
  • 重启;
  • 设备将会进入recovery模式,并进行升级;
  • 升级成功后会reboot到正常的normal系统;

可使用的路径如下:

  • U盘的挂载路径:/udisk
  • sdcard的挂载路径:/mnt/sdcard//sdcard
  • eMMC的挂载路径:/userdata/

升级流程图如下:

接下来我们进行测试,开发板从ubuntu tftp服务器下载统一镜像:

root@rk3588-buildroot:/userdata# tftp -g -l update.img 192.168.0.200

然后执行rkupdate升级命令:

root@rk3588-buildroot:/userdata# update ota /userdata/update.img

等待升级完成,升级成功后开发版会重新启动进入系统。

3.2 debian/ubuntu系统升级

Buildroot recovery升级一样,该Recovery OTA升级方案也支持DebianUbuntu系统下的升级。

由于Recovery模式下升级需要通过设备各个分区节点来识别并写入不同设备分区节点的固件数据,Buildroot系统是通过udev中的别名方式(by-name)来对设备分区节点做了通用的易识别的处理。

DebianUbuntu系统中因为缺少这样的方式,导致了实际中Recovery不能正常运行的情况,所以只需要将DebianUbuntu系统中设备分区的节点也跟Buildroot系统下可通过by-name别名方式标识出来,Recovery即可正常工作。

具体修改方式如下:

buildroot/output/rockchip_rkxxxx/target/lib/udev/rules.d/61-partition-init.rules 
或者
buildroot/output/rockchip_rkxxxx_recovery/target/lib/udev/rules.d/61-partitioninit.rules

拷贝到DebianUbuntu系统下相关的位置,如rootfs/overlay-debug/lib/udev/rules.d/下。此处rkxxxx为具体某一rk芯片平台(RK3308RK3328RK3399RK3326等)。修改的目的就是开机启动后可以将Debian系统或Ubuntu系统中各个分区节点形如/dev/mmcblk0p0/dev/mmcblk0p1/dev/mmcblk0p2/dev/mmcblk0p3 ... 修改为/dev/block/byname/uboot /dev/block/by-name/misc/dev/block/by-name/boot/dev/block/byname/ rootfs ...等。

若还是出现如下类似设备节点:

root@linaro-alip:~# ls /dev/block/
179:0 179:3 179:5 179:7 179:96 7:0 7:3 7:6
179:1 179:32 179:6 179:8 1:0 7:1 7:4 7:7
179:2 179:4 179:64 179:9 254:0 7:2 7:5

可尝试将61-partition-init.rules放在DebianUbuntu /etc/udev/rules.d/lib/udev/rules.d/

参考文章

[1] Rockchip Linux updateEngine升级方案介绍

[2] Rockchip Linux Recovery升级开发指南

[3] 嵌入式Linux开发之Makefile

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/752964.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【产品经理】订单处理9-台账库存管理

在订单处理过程中&#xff0c;台账库存的具体设计怎么做&#xff1f; 在订单处理过程中&#xff0c;分配仓库成功后要扣除仓库库存并计算商品缺货情况&#xff0c;仓库库存就是台账库存。 1&#xff0c;台账库存是针对某个仓库的库存&#xff0c;且台账库存只计算此商品SKU的库…

小马搬运物品-第13届蓝桥杯省赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第89讲。 小马搬运物品&…

C#/.NET量化开发实现财富自由【4】实现EMA、MACD技术指标的计算

听说大A又回到了2950点以下&#xff0c;对于量化交易来说&#xff0c;可能这些都不是事儿。例如&#xff0c;你可以预判到大A到顶了&#xff0c;你可能早就跑路了。判断逃顶还是抄底&#xff0c;最简单的方式就是判断是否顶背离还是底背离&#xff0c;例如通过MACD&#xff0c;…

华为5288 V5服务器安装BCLinux8U4手记

本文记录了华为5288 V5服务器安装BCLinux8U4操作系统的过程。 一、系统环境 1、服务器 华为FusionServer Pro 5288 V5服务器 2、操作系统 BCLinux-R8-U4-Server-x86_64-220725.iso 官网下载地址 sha256sum&#xff1a;1d31d3b8e02279e89965bd3bea61f14c65b9d32ad2ab6d4eb…

MySQL数据库基础练习系列——教务管理系统

项目名称与项目简介 教务管理系统是一个旨在帮助学校或教育机构管理教务活动的软件系统。它涵盖了学生信息管理、教师信息管理、课程管理、成绩管理以及相关的报表生成等功能。通过该系统&#xff0c;学校可以更加高效地处理教务数据&#xff0c;提升教学质量和管理水平。 1.…

uniapp获取证书秘钥、Android App备案获取公钥、签名MD5值

一、 uniapp获取证书秘钥 打开uniapp开发者中心下载证书打开cmd输入以下这段代码&#xff0c;下载提供查看到的密钥证书密码就可以了&#xff01;下载证书在 java 环境下运行才可以 // your_alias 换成 证书详情中的别名&#xff0c;your_keystore.keystore 改成自己的证书文件…

炸裂行情,只涨指数难涨票!你的股票涨了吗?

今天的A股&#xff0c;让人愣住了&#xff0c;你知道是为什么吗&#xff1f;盘面上出现2个耐人寻味的重要信号&#xff0c;一起来看看&#xff1a; 1、今天A股冲高回落&#xff0c;很多人愣住了&#xff0c;别慌&#xff01;主力增量在不断增加&#xff0c;7月的一波主线反弹正…

小程序web-view无法打开该页面的解决方法

问题&#xff1a;开发者工具可以正常打开&#xff0c;正式上线版小程序使用 web-view 组件测试时提示&#xff1a;“无法打开该页面&#xff0c;不支持打开 https://xxxxxx&#xff0c;请在“小程序右上角更多->反馈与投诉”中和开发者反馈。” 解决方法&#xff1a;需要配…

计网实训——不相同网段的PC相互通信

目录 提前准备APP路由器指令 实验一1、实验需求&#xff08;1&#xff09;实现同网段的PC相互通信。&#xff08;2&#xff09;实现不相同网段的PC相互通信。&#xff08;3&#xff09;分析相同和不同网段PC通信时MAC地址的变化。 2、实验拓扑3、实验步骤及实验截图&#xff08…

金顺心贸易有限公司简介

金顺心贸易有限公司成立于2015年&#xff0c;注册地位于风景如画的广西壮族自治区防城港市东兴市。 金顺心贸易如他们的名字一样&#xff0c;有着实实在在的业绩和口碑的。他们专注于国际贸易&#xff0c;主营越南进口食品&#xff1a;果汁饮料、春卷皮、调味品、汤底、米粉、…

【LeetCode】九、双指针算法:环形链表检测 + 救生艇

文章目录 1、双指针算法1.1 对撞双指针1.2 快慢双指针 2、leetcode141&#xff1a;环形链表3、leetcode881&#xff1a;救生艇 1、双指针算法 用两个指针来共同解决一个问题&#xff1a; 1.1 对撞双指针 比如先有一个有序的数组array int[] array {1, 4, 5, 7, 9}先要找两个…

# Kafka_深入探秘者(10):kafka 监控

Kafka_深入探秘者&#xff08;10&#xff09;&#xff1a;kafka 监控 一、kafka JMX 1、JMX &#xff1a;全称 Java Managent Extension 在实现 Kafka 监控系统的过程中&#xff0c;首先我们要知道监控的数据从哪来&#xff0c;Kafka 自身提供的监控指标(包括 broker 和主题的…

Zabbix如何帮助企业将监控数据转化为竞争优势

By Fernanda Moraes 在我们生活的高度互联世界中&#xff0c;变化以越来越快和激烈的速度发生。这影响了消费者的认知与行为&#xff0c;迫使零售商寻找更有效的方式来吸引客户。Linx 是 StoneCo 集团旗下的一家公司&#xff0c;也是零售技术专家&#xff0c;Linx了解这一点&am…

无线麦克风领夹哪个牌子好,2024年领夹麦克风品牌排行榜推荐

​随着短视频热潮的兴起&#xff0c;越来越多的人倾向于用vlog记录日常生活&#xff0c;同时借助短视频和直播平台开辟了副业。在这一过程中&#xff0c;麦克风在近两年内迅速发展&#xff0c;从最初的简单收音功能演变为拥有多样款式和功能&#xff0c;以满足视频创作的需求。…

数据脱敏学习

数据脱敏是一种保护敏感信息的方法&#xff0c;它通过修改或删除数据中的敏感部分&#xff0c;使得数据在保持一定可用性的同时&#xff0c;不再直接关联到个人隐私或重要信息。 自然人指可以直接或间接标识 直接标识&#xff1a;如姓名、身份证号码、家庭住址、电话号码、电…

生命在于折腾——Macbook虚拟机开启360核晶

首先启动PD虚拟机&#xff0c;打开360&#xff0c;发现提示如下&#xff1a; 此时将虚拟机关机。 打开该虚拟机设置&#xff1a; 将虚拟机监控程序改为Parallels&#xff0c;并启动nested虚拟化。 改好后截图如下&#xff1a; 保存设置&#xff0c;开机 此时就可以开启了…

手机恢复已删除数据,3种情况下的解决办法,史诗级教程

手机已经变成了我们生活中的“黑匣子”&#xff0c;记录着我们的通讯录、照片、视频、聊天记录等各种重要数据。然而&#xff0c;由于误删、系统崩溃或其他不可预测的情况&#xff0c;我们可能会面临数据丢失的风险。 本文将为你提供一份史诗级的教程&#xff0c;详细介绍3种不…

10种超强图像特征提取算法Python代码实现

声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类算法的家人&#xff0c;可关注我的VX公众号&#xff1a;python算法小当家&#xff0c;不定期会有很多免费代码分享~ 图像特征提取是计算机视觉和图像处理的关键步骤&#xff0c;因…

零基础STM32单片机编程入门(四)ADC详解及实战含源码视频

文章目录 一.概要二.STM32F103C8T6单片机ADC外设特点三.STM32单片机ADC内部结构图1.ADC相关引脚说明2.ADC通道分类3.触发源4.转换周期5.电压转换计算6.更精确电压转换计算 四.规则通道ADC采集信号流向1.单次转换模式2.连续转换模式 五.CubeMX配置一个ADC采集例程六.CubeMX工程源…

Nginx反向代理实现Vue跨域注意事项

1、通过搜索引擎访问Nginx官网——免费使用——NGINX开源版(免费下载)或者通过以下链接直接访问Nginx下载页面下载对应的版本(下载页面)。以下以1.24.0为例 2、修改nginx的配置文件&#xff0c;在conf文件夹下&#xff0c;文件名为nginx.conf&#xff1b;以下是我修改完的配置…