OTA升级开发指导
简介 升级包安装组件运行在updater分区,其功能主要包括读取misc分区信息获取升级包状态,对升级包进行校验,确保升级包合法有效;然后从升级包中解析出升级的可执行程序,创建子进程并启动升级程序。具体升级的动作由升级脚本控制。本文将介绍如何针对OpenHarmony L2场景适配updater模式。 前置条件 参考OpenHarmony官方指导,完成正常系统编译和内核启动,能进入正常模式,且运行
简介
升级包安装组件运行在updater分区,其功能主要包括读取misc分区信息获取升级包状态,对升级包进行校验,确保升级包合法有效;然后从升级包中解析出升级的可执行程序,创建子进程并启动升级程序。具体升级的动作由升级脚本控制。本文将介绍如何针对OpenHarmony L2场景适配updater模式。
前置条件
-
参考OpenHarmony官方指导,完成正常系统编译和内核启动,能进入正常模式,且运行正常。
-
芯片需配置包含updater分区和misc分区的分区表。updater分区大小不小于32M。
1、OTA升级实现原理
1.1 OTA实现主要流程:
1.2 升级服务组件
升级服务组件是一个SA(System Ability), 由OHOS 的init 进程负责启动。
升级服务器引擎主要功能包括:
1、查找可用的升级包
2、下载升级包
3、设置/获取升级策略
4、触发升级
代码目录
base/update/updateservice # 升级服务代码仓目录 ├── interfaces # 升级客户端接口目录 │ ├── kits # 对外接口封装目录 │ │ └── js # 提供给升级客户端应用的JS 接口目录 │ └── inner_api # SA 接口定义和封装目录 ├── frameworks # 部件无独立进程的实现 │ └── js # JS API的实现 │ └── napi # napi代码实现 │ └── client # 升级客户端napi 接口目录 ├── services # 独立进程的实现 │ ├── callback # 提供给升级客户端应用的callback接口目录 │ └── engine # 升级客户端引擎服务目录 │ ├── etc # 升级客户端引擎rc配置文件目录 │ ├── include # 升级客户端引擎头文件目录 │ ├── sa_profile # SA 配置文件目录 │ └── src # 升级客户端引擎源码目录 ├── test # 测试代码目录 │ ├── unittest # 升级客户端UT代码目录 │ └── fuzztest # 升级客户端FT代码目录 ├── BUILD.gn # 编译入口 └── bundle.json # 部件描述文件
JS接口说明
接口 | 说明 |
---|---|
checkNewVersion | 检查是否有可用的升级包版本 |
download() | 下载升级包 |
upgrade() | 将升级命令写入到misc分区,最终调用reboot命令,进入到updater 子系统中。 |
getNewVersionInfo() | 升级完成后,获取升级后的版本信息 |
setUpgradePolicy | 设置升级策略 |
getUpgradePolicy | 获取升级策略 |
使用说明
1,导入updateclient lib
import client from 'libupdateclient.z.so'
2,获取update对象
let updater = client.getUpdater('OTA');
3,获取新版本信息
updater.getNewVersionInfo(info => { info "新版本信息" });
4,检查新版本
updater.checkNewVersion(info => { info "新版本信息" });
5,下载新版本,并监听下载进程
updater.download(); updater.on("downloadProgress", progress => { progress "下载进度信息" });
6,启动升级
updater.upgrade(); updater.on("upgradeProgress", progress => { progress "升级进度信息" });
7,设置升级策略
updater.setUpgradePolicy(result => { result "设置升级策略结果" });
8,查看升级策略
updater.getUpgradePolicy(policy => { policy "升级策略" });
###
1.3 升级包安装组件
升级包安装组件运行在updater分区,其功能主要包括读取misc分区信息获取升级包状态,对升级包进行校验,确保升级包合法有效;然后从升级包中解析出升级的可执行程序,创建子进程并启动升级程序。具体升级的动作由升级脚本控制。
图 1 升级子系统架构图
代码目录
base/update/updater/ ├── resources # 升级子系统用户界面图片资源目录 ├── services # 组件服务层代码目录 │ ├── applypatch # 升级包数据更新代码目录 │ ├── diffpatch # 差分还原代码目录 │ ├── etc # 启动相关配置文件目录 │ ├── flashd # flashd模式镜像写入和升级功代码目录 │ ├── fs_manager # 文件系统和分区管理代码目录 │ ├── hdi # 硬件相关接口定义 │ ├── include # 升级子系统头文件目录 │ ├── log # 升级子系统日志模块目录 │ ├── package # 升级包管理模块目录 │ ├── ptable_parse # 分区表解析代码目录 │ ├── script # 升级脚本管理目录 │ ├── ui # 升级ui界面代码目录 │ └── updater_binary # 升级可执行程序目录 ├── interfaces │ └── kits # 对外模块接口定义 └── utils # 升级子系统通用代码目录 └── include # 升级子系统通用函数头文件目录
使用说明
升级包安装组件运行在updater分区里,需要如下的操作
1、创建updater分区
updater是一个独立的分区,分区大小建议不小于20MB。updater分区镜像是ext4 格式文件系统。确保系统内核ext4 文件系统的config 是打开状态。
2、创建misc分区
misc 分区中存储了升级子系统在升级过程中需要的元数据(metadata),如升级命令,掉电续传记录等。 misc 分区的大小约1MB,是一个裸分区,无需制作文件系统, 升级子系统直接访问。
3、分区配置表
升级包安装组件在运行过程中,需要通过分区配置表操作分区。默认的分区配置表文件名是fstab.updater,在编译的时候,打包到升级包安装组件中。
4、升级包安装组件启动
updater分区的init 进程有单独的配置文件 init.cfg,升级包安装进程启动配置在该文件中。
5、升级包安装组件编译
a、在build/subsystem_config.json文件添加配置。
如下:
"updater": { "project": "hmf/updater", "path": "base/update/updater", "name": "updater", "dir": "base/update" },
b、 产品中添加需要编译的组件
以Hi3516DV300为例,在productdefine/common/products/Hi3516DV300.json 中添加updater:
"updater:updater":{},
6、updater分区镜像编译
编译配置在build仓下,build_updater_image.sh 脚本中,该脚本由OHOS 编译系统调用
1.4 配置MISC分区
OpenHarmony使用MISC分区保存启动时的指令,默认的MISC分区的结构体为:
struct UpdateMessage { char command[32]; char update[1280]; char reserved[736]; };
command为当前的命令,update存放升级包路径,reserved存放保留信息。
1.5 镜像编译
使能镜像编译选项,编译脚本会将out/rk3568/packages/phone/updater文件夹作成updater.img镜像。先使用gzip工具压缩,然后使用cpio工具制作镜像。镜像格式为ASCII cpio archive (SVR4 with no CRC)。updater.img没有内核,以根文件系统挂载。out/rk3568/packages/phone/updater目录结构与根文件系统结构一致。过多添加文件到updater.img会导致镜像超过32M编译失败。
1.6 镜像启动流程
完整的启动流程如下:
1.7 配置uboot和内核
uboot需要读取MISC分区的指令,如果command为updater,uboot能启动到updater模式。内核需要根据uboot的指令加载updater.img。
Updater 子系统与主系统共用同一个内核,但用户态是从不同的分区启动。
Misc 分区是裸盘,是主系统和updater 子系统的一个沟通介质。当主系统OTA service下载到升级包后,会将升级包的位置记录到Misc分区。系统重启后,将从updater 分区启动并进入Updater子系统。
updater模式启动与正常模式启动流程一致。当正常模式调通后,参考正常模式完成updater模式的调试。 updater.img镜像是ramdisk格式且没有内核,需要uboot先拉起内核,然后加载updater.img到内存,作为根文件系统挂载到内核。如果芯片不支持ramdisk格式,需要进一步适配。
如果缺少misc或updater分区是无法升级的,需要将其加上。
1.8 init服务启动
根文件系统挂载完成,会启动init服务,参考内核启动[内核启动]。 init启动引导组件对应的进程为init进程,是内核完成初始化后启动的第一个用户态进程。init进程启动之后,读取init.cfg配置文件,依次启动各关键系统服务进程。updater模式下的init组件功能与正常模式一致,但是updater模式会根据自身业务对配置文件进行精简,只保留必须的命令。 启动配置文件由以下配置文件组成:
-
与产品相关的配置文件 以RK3568为例,updater模式的init.cfg文件位于产品目录device/board/hihope/rk3568/updater下。init.cfg是启动的入口,通过import方式导入其他配置文件。init.rk3568.usb.cfg主要是USB和HDC相关的配置,与产品特性有关。
-
updater_common.cfg updater模式通用的启动,代码目录。updater_common.cfg包含了多个基础服务,这些服务与产品解耦,依赖系统组件。
-
复用正常模式的配置文件 为了降低耦合复用正常模式的配置文件。这部分配置文件适用于正常模式和updater模式,不需要针对性适配。通过BUILD.g设置复制到updater.img,通过import方式调用。 init.usb.cfg:HDC相关的配置 init.usb.configfs.cfg :USB相关的配置 faultloggerd.cfg:faultloggerd服务配置文件,用于捕获updater模式的crash异常 hilogd.cfg:hilogd配置文件,用于打印OpenHarmony所有组件的日志。
配置文件执行顺序:默认依序执行执行pre-init,init,post-init。 常见的设置:
-
ueventd服务:pre-init阶段启动,所有组件的依赖项,不同产品ueventd配置不一样,建议放产品目录
-
软连接:通过软连接方式将产品的路径转换为openharmony的路径。
-
挂载分区:updater模式启动阶段不挂载分区,升级流程中根据业务场景选择性挂载。
-
设置文件权限:如果二进制没有执行权限,服务会无法正常启动,需要在服务启动前设置权限。
-
执行脚本:updater模式部分场景不挂载data分区,出现异常无法保存日志,会调用脚本保存日志。
1.9 升级服务启动
完成配置文件的适配,单板运行时会根据配置文件顺序依次执行配置中的命令。最终拉起升级子系统核心服务updater进程。updater服务启动以后,屏幕会显示UI界面,进行安装包升级,恢厂,重启等功能。升级服务功能如下所示:
初次适配会出现进程功能缺失等情况,参考如下方法进行调试
-
使用ps -A命令查询进程是否启动。
-
使用dmesg查看内核日志。
-
使用hilog和faultlogger查看进程是否出现crash。
-
手动拉起服务,如果服务能启动,检查启动配置文件是否正确。
2、OTA升级适配
正常模式有两个子程序用于操作misc分区。 执行write_updater命令向misc分区的update字段写入指令,指令格式参考参考write_updater源码base/update/updater/utils/write_updater.cpp。 执行reboot updater命令,向misc分区的command写入指令,单板会重新启动,重启过程中uboot读取misc分区的命令,从command命令判断当前要进入updater模式,依次加载内核和updater.img,完成从正常模式到updater模式的启动流程。 updater进程启动后读取update字段的命令,获取升级包的路径,单板进入升级流程,直至升级成功重启。
2.1 配置uboot和内核
uboot需要读取MISC分区的指令,如果command为updater,uboot能启动到updater模式。内核需要根据uboot的指令加载updater.img。
Updater 子系统与主系统共用同一个内核,但用户态是从不同的分区启动。
Misc 分区是裸盘,是主系统和updater 子系统的一个沟通介质。当主系统OTA service下载到升级包后,会将升级包的位置记录到Misc分区。系统重启后,将从updater 分区启动并进入Updater子系统。
updater模式启动与正常模式启动流程一致。当正常模式调通后,参考正常模式完成updater模式的调试。 updater.img镜像是ramdisk格式且没有内核,需要uboot先拉起内核,然后加载updater.img到内存,作为根文件系统挂载到内核。如果芯片不支持ramdisk格式,需要进一步适配。
如果缺少misc或updater分区是无法升级的,需要将其加上。misc分区建议配置大小为1M,updater分区建议配置大小为32M以上。
2.2 升级镜像需要的fstab配置
执行升级的时候,如果没有在该文件中配置对应的镜像,是无法升级成功的。
./device/board/hihope/rk3568/updater/config/fstab.updater
2.3 updater模式界面
正常模式只输入reboot updater命令,进入updater模式界面。此模式可以进行SD卡升级。
3、升级包制作工具
升级包制作工具是使用python开发,运行在PC端用来制作升级包的工具,功能主要包括:全量升级包制作、差分升级包制作以及变分区升级包制作。它首先会打包各个升级镜像,然后对升级包进行签名,同时生成升级包执行脚本,最后制作出升级包。
-
全量升级包制作:升级包中只包括镜像全量升级相关数据,用于镜像全量升级;
-
差分升级包制作:升级包中只包括镜像差分升级相关数据,用于镜像差分升级;
-
变分区升级包:升级包中包括分区表、镜像全量数据,用于变分区处理和变分区后的镜像恢复。
代码目录
/base/update/packaging_tools ├── lib # 制作升级包工具依赖库目录 ├── blocks_manager.py # BlocksManager类定义,用于block块管理 ├── build_update.py # 差分包制作工具入口代码,入口参数定义 ├── build_pkcs7.py # 升级包签名 ├── create_update_package.py # 升级包制作 ├── gigraph_process.py # 生成Stash,重置ActionList的顺序 ├── image_class.py # 全量镜像、稀疏镜像解析处理 ├── log_exception.py # 全局log系统定义,自定义exception ├── patch_package_process.py # 差分镜像处理,Block差分获取patch差异 ├── script_generator.py # 升级脚本生成器 ├── transfers_manager.py # 创建ActionInfo对象 ├── unpack_update_package.py # 升级包反解 ├── update_package.py # 升级包格式管理、升级包写入 ├── utils.py # Options管理,其他相关功能函数定义 └── vendor_script.py # 厂商升级流程脚本扩展
约束
工具运行环境配置:
-
Ubuntu18.04或更高版本系统;
-
python3.5及以上版本;
-
python库xmltodict, 解析xml文件,需要单独安装;
使用说明
-
bsdiff可执行程序,差分计算,比较生成patch;
-
imgdiff可执行程序,差分计算,针对zip、gz、lz4类型的文件,对比生成patch;
-
e2fsdroid可执行程序,差分计算,用于生成镜像的map文件。
工具参数配置说明:
4、 升级包制作流程
4.1 升级包简介
升级包里面有两个文件,包括build_tools.zip 和update.bin。
build_tools.zip:用来辅助升级的工具,包括升级的可执行文件updater_binary和升级脚本,镜像描述
update.bin:TLV编码的文件,所有的升级内容按照TLV格式序列化存储,最终生成update.bin
工具对update.bin 和最终生成的升级包(zip 压缩文件)分别进行签名。
4.2 制作全量升级包
1.首先在base\update\packaging_tools目录下,创建文件夹target_package和output_package。
2.进入 cd target_package文件夹,创建 mkdir updater_config。
3.进入 cd updater_config 文件夹,
从device\board\hisilicon\hispark_taurus\linux\updater\config路径下,拷贝BOARD.list和VERSION.mbn到base\update\packaging_tools\target_package\updater_config。
从device\board\hisilicon\hispark_taurus\linux\system下拷贝updater_specified_config.xml到base\update\packaging_tools\target_package\updater_config。
3.从out\rk3568\packages\phone\images路径所有文件拷贝至base\update\packaging_tools\target_package。
从out\rk3568\packages\phone\system\bin路径下拷贝文件updater_binary 至base\update\target_package。
4.将文件base\update\updater\test\unittest\test_data\src\rsa_private_key2048.pem拷贝至base\update\packaging_tools下
文件说明:
BOARD.list:存放当前升级包支持的产品list
如果是rk3568,请在文件中添加RK3568
VERSION.mbn:存放当前升级包所支持的版本范围
查询当前设备软件版本,rk3568开机后,点击设置,点击关于设备->软件版本,然后添加到文件里面去。
updater_specified_config.xml:分区表文件,结构参考下图
updater_specified_config.xml 组件配置文件节点说明
在base\update\packaging_tools终端执行升级包制作命令: python3 build_update.py ./target_package/ ./output_package/ -pk ./rsa_private_key2048.pem
4.3 手动命令触发全量包升级
-
进入设备:hdc_std shell
-
切换到 data 文件夹:cd data
-
新建 updater 目录:mkdir updater
-
退出设备:exit
-
传输升级包:hdc_std file send + 升级包地址 /data/updater/updater.zip (在设备侧的文件明一定要是updater.zip)
-
进入设备:hdc_std shell
-
输入指令:
write_updater updater /data/updater/updater.zip
-
触发升级:
reboot updater
获取版本号命令:param get hw_sc.build.os.version
升级查看日志文件
-
查看日志文件列表:ls -l data/updater/log
-
打开日志文件:cat data/updater/log/updater_log
-
升级成功标志文件:data/updater/updter_result
4.4 升级包安装
升级包安装是升级子系统的核心功能,主要包括:
1.从misc分区获取升级命令,根据不同的命令执行不同的任务。
2.对升级包进行解压和合法性效验。
3.启动升级进程,并解析出升级脚本。
4.根据升级脚本安装各个组件包。
5.完成升级后,进行后处理。如清理升级包,记录升级状态等。
5、OTA升级UX界面适配
5.1 打开升级界面UI
开关。
// base/update/updater/updater_default_cfg.gni
declare_args() {
updater_cfg_file = ""
updater_ui_support = true
}
5.2 修改产品init编译配置项
需要产品init
编译配置项增加以下配置
// device/board/hihope/rk3568/updater/BUILD.gn
...
updater_usb_init_cfg_path = "//base/startup/init/services/etc/init.usb.cfg"
updater_init_usb_configfs_path_cfg =
"//drivers/peripheral/usb/cfg/init.usb.configfs.cfg"
updater_faultloggerd_cfg =
"//base/hiviewdfx/faultloggerd/services/config/faultloggerd.cfg"
updater_hilog_cfg = "//base/hiviewdfx/hilog/services/hilogd/etc/hilogd.cfg"
ohos_prebuilt_etc("updater_hilog.cfg") {
source = "${updater_hilog_cfg}"
install_images = [ "updater" ]
part_name = "huanglong_sdk"
}
ohos_prebuilt_etc("updater_faultloggerd.cfg") {
source = "${updater_faultloggerd_cfg}"
install_images = [ "updater" ]
part_name = "huanglong_sdk"
}
ohos_prebuilt_etc("updater_init_usb.cfg") {
source = "${updater_usb_init_cfg_path}"
install_images = [ "updater" ]
part_name = "huanglong_sdk"
}
ohos_prebuilt_etc("updater_init_usb_configfs.cfg") {
source = "${updater_init_usb_configfs_path_cfg}"
install_images = [ "updater" ]
part_name = "huanglong_sdk"
}
...
group("init_configs") {
deps = [
":signing_cert.crt",
":init_fstab_ramdisk",
":init_fstab_vendor",
":init_fstab_updater",
":updater_init.cfg",
":updater_init.wudangstick.usb.cfg",
":updater_faultloggerd.cfg",
":updater_hilog.cfg",
":updater_init_usb.cfg",
":updater_init_usb_configfs.cfg"
]
}
5.3 UX界面资源配置项
在`base/update/updater/resources 下配置对应产品的图片资源和界面配置文件。
5.4 更改升级UX界面配置文件名
base/update/updater/resources/rk3568/的目录
pages文件夹下,更改config.json
文件配置。
// base/update/updater/resources/rk3568/pages/config.json
{
"config" : "/resources/pages/rk3568.json" //界面文件
}
5.5 更改base/update/updater/resources 编译配置文件。
// base/update/updater/resources/BUILD.gn
...
if (product_name == "rk3568") { // 更改为对应的产品名称
updater_resources_list += [
...
"${product_name}/pages/config.json",
"${product_name}/pages/rk3568.json", // 更改对应文件名
"${product_name}/pages/confirm.json",
...
]
}
...
6、示例服务器开发概述
## 基本概念
- 搜包服务:升级服务(UpdateService)提供的服务能力之一,依赖支持TCP和SSL协议的服务器。
- 搜包服务器:即支持搜包服务的通过TCP连接并支持SSL协议的服务器,本概述提及的升级服务示例服务器即是符合要求的搜包服务器之一。
- 下载服务器:普通的HTTP服务器即可满足下载服务器的要求。
- update.serverip.search:系统参数,指升级服务(UpdateService)侧配置的搜包服务器IP地址,默认值:127.0.0.1。
## 约束与限制
- 服务器返回报文格式Json示例,注意verifyInfo字段是升级包的sha256值,size字段是升级包的大小,单位为字节。
{
"searchStatus": 0,
"errMsg": "success",
"checkResults": [{
"versionName": "versionNameSample",
"versionCode": "versionCodeSample", 升级包版本号
"verifyInfo": "verifyInfoSHA256Value1234567", 升级包的sha256
"size": 1234567, 升级包大小
"packageType": 1,
"url": "http://serverAddressSample/packageNameSample.fileTypeSample",
"descriptPackageId": "abcdefg1234567ABCDEFG"
}],
"descriptInfo": [{
"descriptPackageId": "abcdefg1234567ABCDEFG",
"content": "This package is used for update."
}]
}
示例服务器部署到设备上,客户端就可以直接通过127.0.0.1访问
-
考虑将服务器生成为一个可执行的二进制文件,我们将模块放到base/update/updater/updateservice下面,制作build.gn文件,需要一些相关依赖。
编译后就会生成二进制文件,可以将文件推到设备上运行。
-
参考下面文档生成服务器对应的crt和pem文件,和测试服务器文件推到开发板同一个目录。
-
使用命令chmod 给二进制文件添加可执行权限。
out目录下编译生成的文件路径:
文档参考目录:
openharmony/docs/zh-cn/application-dev/device/sample-server-guidelines.md
openharmony/docs/zh-cn/application-dev/device/sample-server-overview.md
更多推荐
所有评论(0)