• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# OTA升级
2
3## 概述
4
5OTA(Over the Air)提供对设备远程升级的能力,可以让您的设备(如IP摄像头等),轻松支持远程升级能力。目前轻量和小型系统仅支持全量包升级,暂不支持差分包升级。全量包升级是将新系统全部内容做成升级包,进行升级;差分包升级是将新老系统的差异内容做成升级包,进行升级。
6
7## 约束与限制
8
9- 支持基于Hi3861/Hi3518EV300/Hi3516DV300芯片的开源套件。
10
11- 对Hi3518EV300/Hi3516DV300开源套件,设备需要支持SD卡(VFAT格式)。
12  > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
13  > 生成升级包需要在linux系统下面执行。
14
15
16## 生成公私钥对
17
181. 准备工作:在Windows PC 上,下载安装[OpenSSL工具](http://slproweb.com/products/Win32OpenSSL.html),并配置环境变量。
19
202. 使用OpenSSL工具生成公私钥对。
21
223. 请妥善保管私钥文件,在升级包制作过程中将私钥文件作为制作命令的参数带入,用于升级包签名,公钥用于升级时对升级包进行签名校验,公钥的放置如下:
23   轻量和小型系统将生成的公钥内容预置在代码中,需要厂商实现 HotaHalGetPubKey 这个接口来获取公钥。标准系统需要将生产的公钥放在 ./device/hisilicon/hi3516dv300/build/updater_config/signing_cert.crt 这个文件中。
24
254. 对使用 Hi3518EV300/Hi3516DV300 套件的轻量和小型系统,在上一步的基础上,还需用public_arr.txt里面的全部内容替换uboot模块device\hisilicon\third_party\uboot\u-boot-2020.01\product\hiupdate\verify\update_public_key.c 中的g_pub_key中的全部内容。
26   示例,uboot模块的公钥:
27
28   ```
29   static unsigned char g_pub_key[PUBKEY_LEN] = {
30       0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01,
31       0x00, 0xBF, 0xAA, 0xA5, 0xB3, 0xC2, 0x78, 0x5E,
32   }
33   ```
34
35
36## 生成升级包
37
38
39### 轻量与小型系统升级包制作
40
411. 创建目标版本(target_package)文件夹,文件格式如下:
42   ```
43    target_package
44    ├── OTA.tag
45    ├── config
46    ├── {component_1}
47    ├── {component_2}
48    ├── ......
49    ├── {component_N}
50    └── updater_config
51        └── updater_specified_config.xml
52   ```
53
542. 将待升级的组件,包括镜像文件(例如:rootfs.img等)等放入目标版本文件夹的根目录下,代替上结构中的{component_N}部分。
55
563. 填写“update_config”文件夹中的“updater_specified_config.xml”组件配置文件。
57   组件配置文件“updater_specified_config.xml”,格式如下:
58
59   ```
60   <?xml version="1.0"?>
61   <package>
62       <head name="Component header information">
63           <info fileVersion="01" prdID="hisi" softVersion="OpenHarmony x.x" date="202x.xx.xx" time="xx:xx:xx">head info</info>
64       </head>
65       <group name="Component information">
66       <component compAddr="ota_tag" compId="27" resType="5" compType="0" compVer="1.0">./OTA.tag</component>
67       <component compAddr="config" compId="23" resType="5" compType="0" compVer="1.0">./config</component>
68       <component compAddr="bootloader" compId="24" resType="5" compType="0" compVer="1.0">./u-boot-xxxx.bin</component>
69       </group>
70   </package>
71   ```
72
73   **表1** 组件配置文件节点说明
74
75   | 信息类别 | 节点名称 | 节点标签 | 是否必填 | 内容说明 |
76   | -------- | -------- | -------- | -------- | -------- |
77   | 头信息(head节点) | info节点 | / | 必填 | 该节点内容配置为:head&nbsp;info。 |
78   | | | fileVersion | 必填 | 保留字段,内容不影响升级包生成。 |
79   | | | prdID | 必填 | 保留字段,内容不影响升级包生成。 |
80   | | | softVersion | 必填 | 软件版本号,即升级包版本号,版本必须在“VERSION.mbn”范围内,否则无法生产升级。 |
81   | | | date | 必填 | 升级包制作日期,保留字段,不影响升级包生成。 |
82   | | | time | 必填 | 升级包制作时间,保留字段,不影响升级包生成。 |
83   | 组件信息(group节点) | component节点 | / | 必填 | 该节点内容配置为:要打入升级包的组件/镜像文件的路径,默认为版本包根路径。 |
84   | | | compAddr | 必填 | 该组件所对应的分区名称,例如:system、vendor等。 |
85   | | | compId | 必填 | 组件Id,不同组件Id不重复。 |
86   | | | resType | 必填 | 保留字段,不影响升级包生成。 |
87   | | | compType | 必填 | 处理方式全量/差分,配置镜像处理方式的,0为全量处理、1为差分处理。 |
88
89   > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
90   > 对轻量系统/小型系统,不支持做差分升级,component标签中,属性compType值,不能配为‘1’,必须全部配置为‘0’。
91   >
92   > 对轻量系统/小型系统,不支持变分区升级包的制作。
93
944. 创建“OTA.tag文件”,内容为OTA升级包的魔数,固定如下:
95   ```
96   package_type:ota1234567890qwertw
97   ```
98
995. 创建“config文件”,内容为设置bootargs以及bootcmd的信息。
100   例如配置如下:
101
102   ```
103   setenv bootargs 'mem=128M console=ttyAMA0,115200 root=/dev/mmcblk0p3 rw rootfstype=ext4 rootwait blkdevparts=mmcblk0:1M
104   (u-boot.bin),9M(kernel.bin),50M(rootfs_ext4.img),50M(userfs.img)' setenv bootcmd 'mmc read 0x0 0x82000000 0x800 0x4800;bootm 0x82000000'
105   ```
106
1076. 执行升级包制作命令。
108   ```
109   python build_update.py ./target_package/ ./output_package/ -pk ./rsa_private_key3072.pem -nz -nl2x
110   ```
111
112   - ./target_package/:指定target_package路径。
113   - ./output_package/:指定升级包输出路径。
114   - -pk ./rsa_private_key3072.pem:指定私钥路径。
115   - -nz:打开not zip模式开关
116   - -nl2:打开非“标准系统”模式开关
117
118
119### 标准系统升级包制作
120
1211. 创建目标版本(target_package)文件夹,文件格式如下:
122
123   ```
124   target_package
125   ├── {component_1}
126   ├── {component_2}
127   ├── ......
128   ├── {component_N}
129   └── updater_config
130           ├── BOARD.list
131           ├── VERSION.mbn
132           └── updater_specified_config.xml
133   ```
134
1352. 将待升级的组件,包括镜像文件(例如:system.img等)等放入目标版本文件夹的根目录下,代替上结构中的{component_N}部分。
136
1373. 填写“update_config”文件夹中的组件配置文件。
138
1394. 配置“update_config”文件夹中当前升级包支持的产品list:**BOARD.list**。
140
141   例如配置如下:
142
143   ```
144   HI3516
145   HI3518
146   ```
147
1485. 配置“update_config”文件夹中当前升级包所支持的版本范围:**VERSION.mbn**。
149
150   版本名称格式:Hi3516DV300-eng 10 QP1A.XXXXXX.{大版本号(6位)}.XXX{小版本号(3位)}。
151
152   例如:Hi3516DV300-eng 10 QP1A.190711.020。名称中“190711”为大版本号,“020”为小版本号。
153
154   例如配置如下:
155
156   ```
157   Hi3516DV300-eng 10 QP1A.190711.001
158   Hi3516DV300-eng 10 QP1A.190711.020
159   Hi3518DV300-eng 10 QP1A.190711.021
160   ```
161
1626. 针对增量(差分)升级包,还需要准备一个源版本(source_package),文件内容格式与目标版本(target_package)相同,需要打包成zip格式,即为:source_package.zip163
1647. 针对变分区升级包,还需要提供分区表文件“partition_file.xml”,partition_file.xml配置节点说明如下,可通过-pf参数指定。
165
166   分区表会随镜像一起生成,格式如下:
167
168   ```
169   <?xml version="1.0" encoding="GB2312" ?>
170   <Partition_Info>
171   <Part Sel="1" PartitionName="镜像名称1" FlashType="flash磁盘类型" FileSystem="文件系统类型" Start="该分区起始地址" Length="该分区大小" SelectFile="实际镜像所在路径"/>
172   <Part Sel="1" PartitionName="镜像名称2" FlashType="flash磁盘类型" FileSystem="文件系统类型" Start="该分区起始地址" Length="该分区大小" SelectFile="实际镜像所在路径"/>
173   </Partition_Info>
174   ```
175
176   **表2** 分区表Part标签说明
177
178   | 标签名称 | 标签说明 |
179   | -------- | -------- |
180   | Sel | 该分区是否生效,1表明生效,0表明不生效。 |
181   | PartitionName | 分区名称,例如:fastboot、boot等。 |
182   | FlashType | flash磁盘类型,例如emmc、ufs等。 |
183   | FileSystem | 文件系统类型,例如ext3/4、f2fs等,也可能为none。 |
184   | Start | 分区起始位置,所有分区最起始为0,单位为兆(M)。 |
185   | Length | 分区占用长度,单位为兆(M)。 |
186   | SelectFile | 实际镜像或文件所在路径。 |
187
1888. 执行升级包制作命令。
189
190   **全量升级包**
191
192   命令如下:
193
194   ```
195   python build_update.py ./target_package/ ./output_package/ -pk ./rsa_private_key3072.pem
196   ```
197
198   - ./target_package/:指定target_package路径。
199   - ./output_package/:指定升级包输出路径。
200   - -pk ./rsa_private_key3072.pem:指定私钥文件路径。
201
202   **增量(差分)升级包**
203
204   命令如下:
205
206   ```
207   python build_update.py ./target_package/ ./output_package/  -s ./source_package.zip  -pk ./rsa_private_key3072.pem
208   ```
209
210   - ./target_package/:指定target_package路径。
211   - ./output_package/:指定升级包输出路径。
212   - -s ./source_package.zip:指定“source_package.zip”路径,当存在镜像需要进行差分处理时,必须使用-s参数指定source版本包。
213   - -pk ./rsa_private_key3072.pem:指定私钥文件路径。
214
215   **变分区升级包**
216
217   命令如下:
218
219   ```
220   python build_update.py  ./target_package/ ./output_package/  -pk ./rsa_private_key3072.pem  -pf ./partition_file.xml
221   ```
222
223   - ./target_package/:指定target_package路径。
224   - ./output_package/:指定升级包路径。
225   - -pk ./rsa_private_key3072.pem:指定私钥文件路径。
226   - -pf ./partition_file.xml:指定分区表文件路径。
227
228
229## 上传升级包
230
231将升级包上传到厂商的OTA服务器。
232
233
234## 下载升级包
235
2361. 厂商应用从OTA服务器下载升级包。
237
2382. 对Hi3518EV300/Hi3516DV300开源套件,需要插入SD卡(容量&gt;100MBytes)。
239
240
241## 厂商应用集成OTA能力
242
2431. 轻量与小型系统
244
245   - 调用OTA模块的动态库libhota.so,对应头文件位于:base\update\ota_lite\interfaces\kits\hota_partition.h&amp;hota_updater.h246   - libhota.so对应的源码路径为base\update\ota_lite\frameworks\source。
247   - API的使用方法,见本文“API应用场景”和API文档的OTA接口章节。
248   - 如果需要适配开发板,请参考HAL层头文件:base\update\ota_lite\hals\hal_hota_board.h249
2502. 标准系统请参考[JS参考规范](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-update.md)指导中的升级接口参考规范。
251
252
253## API应用场景-默认场景
254
255升级包是按照上文“生成公私钥对”和“生成升级包”章节制作的。
256
257
258### 开发指导
259
2601. 应用侧通过下载,获取当前设备升级包后,调用HotaInit接口初始化OTA模块。
261
2622. 调用HotaWrite接口传入升级包数据流,接口内部实现校验、解析及写入升级数据流。
263
2643. 写入完成后,调用HotaRestart接口重启系统,升级过程中,使用HotaCancel接口可以取消升级。
265
266
267### 示例代码
268
269使用OpenHarmony的“升级包格式和校验方法“进行升级。
270```
271int main(int argc, char **argv)
272{
273    printf("this is update print!\r\n");
274    if (HotaInit(NULL, NULL) < 0) {
275        printf("ota update init fail!\r\n");
276        return -1;
277    }
278    int fd = open(OTA_PKG_FILE, O_RDWR, S_IRUSR | S_IWUSR);
279    if (fd < 0) {
280        printf("file open failed, fd = %d\r\n", fd);
281        (void)HotaCancel();
282        return -1;
283    }
284    int offset = 0;
285    int fileLen = lseek(fd, 0, SEEK_END);
286    int leftLen = fileLen;
287    while (leftLen > 0) {
288        if (lseek(fd, offset, SEEK_SET) < 0) {
289            close(fd);
290            printf("lseek fail!\r\n");
291            (void)HotaCancel();
292            return -1;
293        }
294        int tmpLen = leftLen >= READ_BUF_LEN ? READ_BUF_LEN : leftLen;
295        (void)memset_s(g_readBuf, READ_BUF_LEN, 0, READ_BUF_LEN);
296        if (read(fd, g_readBuf, tmpLen) < 0) {
297            close(fd);
298            printf("read fail!\r\n");
299            (void)HotaCancel();
300            return -1;
301        }
302        if (HotaWrite((unsigned char *)g_readBuf, offset, tmpLen) != 0) {
303            printf("ota write fail!\r\n");
304            close(fd);
305            (void)HotaCancel();
306            return -1;
307        }
308        offset += READ_BUF_LEN;
309        leftLen -= tmpLen;
310    }
311    close(fd);
312    printf("ota write finish!\r\n");
313    printf("device will reboot in 10s...\r\n");
314    sleep(10);
315    (void)HotaRestart();
316    return 0;
317}
318```
319
320
321## API应用场景-定制场景
322
323升级包不是按照上文“生成公私钥对”和“生成升级包”章节制作的,是通过其它方式制作的。
324
325
326### 开发指导
327
3281. 应用侧通过下载,获取当前设备升级包后,调用HotaInit接口初始化。
329
3302. 使用HotaSetPackageType接口设置NOT_USE_DEFAULT_PKG,使用"定制"流程。
331
3323. 调用HotaWrite接口传入升级包数据流,写入设备。
333
3344. 写入完成后,调用HotaRead接口读取数据,厂商可以自行校验升级包。
335
3365. 调用HotaSetBootSettings设置启动标记,在重启后需要进入uboot模式时使用(可选)。
337
3386. 调用HotaRestart接口,进行重启,升级过程中,使用HotaCancel接口可以取消升级。
339
340
341### 示例代码
342
343使用非OpenHarmony的“升级包格式和校验方法“进行升级。
344```
345int main(int argc, char **argv)
346{
347    printf("this is update print!\r\n");
348    if (HotaInit(NULL, NULL) < 0) {
349        printf("ota update init fail!\r\n");
350        (void)HotaCancel();
351        return -1;
352    }
353    (void)HotaSetPackageType(NOT_USE_DEFAULT_PKG);
354    int fd = open(OTA_PKG_FILE, O_RDWR, S_IRUSR | S_IWUSR);
355    if (fd < 0) {
356        printf("file open failed, fd = %d\r\n", fd);
357        (void)HotaCancel();
358        return -1;
359    }
360    int offset = 0;
361    int fileLen = lseek(fd, 0, SEEK_END);
362    int leftLen = fileLen;
363    while (leftLen > 0) {
364        if (lseek(fd, offset, SEEK_SET) < 0) {
365            close(fd);
366            printf("lseek fail!\r\n");
367            (void)HotaCancel();
368            return -1;
369        }
370        int tmpLen = leftLen >= READ_BUF_LEN ? READ_BUF_LEN : leftLen;
371        (void)memset_s(g_readBuf, READ_BUF_LEN, 0, READ_BUF_LEN);
372        if (read(fd, g_readBuf, tmpLen) < 0) {
373            close(fd);
374            printf("read fail!\r\n");
375            (void)HotaCancel();
376            return -1;
377        }
378        if (HotaWrite((unsigned char *)g_readBuf, offset, tmpLen) != 0) {
379            printf("ota write fail!\r\n");
380            close(fd);
381            (void)HotaCancel();
382            return -1;
383        }
384        offset += READ_BUF_LEN;
385        leftLen -= tmpLen;
386    }
387    close(fd);
388    printf("ota write finish!\r\n");
389    leftLen = fileLen;
390    while (leftLen > 0) {
391        int tmpLen = leftLen >= READ_BUF_LEN ? READ_BUF_LEN : leftLen;
392        (void)memset_s(g_readBuf, READ_BUF_LEN, 0, READ_BUF_LEN);
393        if (HotaRead(offset, READ_BUF_LEN, (unsigned char *)g_readBuf) != 0) {}
394            printf("ota write fail!\r\n");
395            (void)HotaCancel();
396            return -1;
397        }
398        /* do your verify and parse */
399        offset += READ_BUF_LEN;
400        leftLen -= tmpLen;
401    }
402    /* set your boot settings */
403    (void)HotaSetBootSettings();
404    printf("device will reboot in 10s...\r\n");
405    sleep(10);
406    (void)HotaRestart();
407    return 0;
408}
409```
410
411
412## 系统升级
413
414厂商应用调用OTA模块的API,OTA模块执行升级包的签名验证、版本防回滚、烧写落盘功能,升级完成后自动重启系统。
415
416对于使用Hi3518EV300/Hi3516DV300开源套件的轻量和小型系统,在需要实现防回滚功能的版本中,需要增加LOCAL_VERSION的值,如"ohos default 1.0"-&gt;"ohos default 1.1",LOCAL_VERSION在device\hisilicon\third_party\uboot\u-boot-2020.01\product\hiupdate\ota_update\ota_local_info.c中。
417
418示例,增加版本号。
419```
420const char *get_local_version(void)
421{
422#if defined(CONFIG_TARGET_HI3516EV200) || \
423    defined(CONFIG_TARGET_HI3516DV300) || \
424    defined(CONFIG_TARGET_HI3518EV300)
425#define LOCAL_VERSION "ohos default 1.0" /* increase: default release version */
426```
427