• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# OTA Update
2
3
4## Introduction
5
6
7### Overview
8
9With the rapid development of device systems, it has become a critical challenge for device vendors to help their users to access system updates in a timely manner to experience the new features and improve the system stability and security
10
11Over the Air (OTA) answers this challenge with the support for remote updating of device systems. By providing unified update APIs externally, the update subsystem shields the differences of underlying chips. After secondary development based on the update APIs, device vendors can easily implement remote updating for their devices, such as IP cameras.
12
13
14### Basic Concepts
15
16- Full package: an update package that packs all images of the target version.
17
18- Differential package: an update package that packs the differential images between the source version and target version.
19
20
21### Principles
22
23To implement an OTA update, you first need to use the packaging tool to pack the build version into an update package and upload the update package to the OTA server. Devices integrating the OTA update capability can then detect the update package and download it to implement a remote update.
24
25<a href="#ab-update">A/B Update</a>: a typical application of OTA update. In this update mode, a device has a backup system B. When system A is running, system B is updated silently. After the update is successful, the device restarts and switches to the new system.
26
27
28### Constraints
29
30- Only the open-source suites for devices powered by Hi3861, Hi3516D V300, and RK3568 are supported.
31
32- Devices developed based on Hi3516D V300 and RK3568 must support the SD card in the Virtual Festival of Aerobatic Teams (VFAT) format.
33
34- Generation of update packages can only be performed on the Linux system.
35
36- Currently, the mini and small systems support update using a full package, but not a differential package or an update package with partitions changed.
37
38- To implement an A/B update, ensure that the devices running the standard system support booting from partitions A and B.
39
40
41## Preparations
42
43- On Windows, download and install the OpenSSL tool and configure environment variables.
44- Prepare the packaging tool.
45- Build version images using the packaging tool.
46
47
48## How to Develop
49
50<a href="#generating-a-public/private-key-pair">1. Use the OpenSSL tool to generate a public/private key pair.
51
52<a href="#making-an-update-package">2. Use the packaging tool to generate an update package.</a>
53
54&ensp;&ensp;<a href="#mini-and-small systems">2.1 Mini and small systems</a>
55
56&ensp;&ensp;<a href="#standard system">2.2 Standard system</a>
57
58<a href="#uploading-the-update package">3. Upload the update package to the vendor's OTA server.</a>
59
60<a href="#downloading-the-update-package">4. Download the update package from the vendor's OTA server.</a>
61
62<a href="#integrating-the-OTA-update-capability">5. Integrate the OTA update capability.
63
64&ensp;&ensp;<a href="#api-application-scenario-default">5.1 API application scenario (default)</a>
65
66&ensp;&ensp;<a href="#api-application-scenario-custom">5.2 API application scenario (custom)</a>
67
68&ensp;&ensp;<a href="#ab-update-scenario">5.3 A/B update scenario</a>
69
70
71## How to Develop
72
73
74### Generating a Public/Private Key Pair
751. Use the OpenSSL tool to generate a public/private key pair.
76
773. Keep the private key file properly as this file stores the private key used to sign the update package. You need to specify the private key file in the command used for preparing the update package. The public key is used to verify the signature of the update package during the update. For the mini and small systems, the generated public key is preset in the code. The vendor needs to implement the **HotaHalGetPubKey** API to obtain the key. For the standard system, the generated public key is stored in the **/hisilicon/hi3516dv300/build/updater\_config/signing\_cert.crt** file in the **device** or **vendor** directory.
78
795. For the mini and small systems that use the Hi3516D V300 suite, use the content in **third\_party\u-boot\u-boot-2020.01\product\hiupdate\verify\update\_public\_key.c** file of the U-Boot module.
80   Example configuration:
81
82   ```c
83   static unsigned char g_pub_key[] = {
84       0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01,
85       0x00, 0xBF, 0xAA, 0xA5, 0xB3, 0xC2, 0x78, 0x5E,
86   }
87   ```
88
89
90### Making an Update Package
91
92
93#### Mini and Small Systems
94
951. Create the **target\_package** folder with the following directory structure:
96
97   OTA.tag and config are not required for lightweight systems and small systems upgraded from AB.
98
99   ```text
100    target_package
101    ├── OTA.tag
102    ├── config
103    ├── {component_1}
104    ├── {component_2}
105    ├── ......
106    ├── {component_N}
107    └── updater_config
108        └── updater_specified_config.xml
109   ```
110
1112. Place the components to be updated, including the image file (for example, **rootfs.img**), as the substitute of **{component\_N}** in the root directory of the **target\_package** folder.
112
1133. Configure the **updater\_specified\_config.xml** file in the **updater_config** folder.
114   Example configuration:
115
116
117   ```xml
118   <?xml version="1.0"?>
119   <package>
120       <head name="Component header information">
121           <info fileVersion="01" prdID="hisi" softVersion="OpenHarmony x.x" date="202x.xx.xx" time="xx:xx:xx">head info</info>
122       </head>
123       <group name="Component information">
124       <component compAddr="ota_tag" compId="27" resType="5" compType="0" compVer="1.0">./OTA.tag</component>
125       <component compAddr="config" compId="23" resType="5" compType="0" compVer="1.0">./config</component>
126       <component compAddr="bootloader" compId="24" resType="5" compType="0" compVer="1.0">./u-boot-xxxx.bin</component>
127       </group>
128   </package>
129   ```
130
131     **Table 1** Description of nodes in the component configuration file
132
133   | Type| Node Name| Node Label| Mandatory| Description|
134   | -------- | -------- | -------- | -------- | -------- |
135   | Header information (head node)| info| / | Yes| Content of this node: head&nbsp;info|
136   | Header information (head node)| info| fileVersion | Yes| This field is reserved and does not affect the generation of the update package.|
137   | Header information (head node)| info| prdID | Yes| This field is reserved and does not affect the generation of the update package.|
138   | Header information (head node)| info| softVersion | Yes| Software version number, that is, the version number of the update package. Ensure that the version number is later than the basic version number and OpenHarmony is not followed by any other letter. Otherwise, the update cannot be performed.|
139   | Header information (head node)| info| *date* | Yes| Date when the update package is generated. This field is reserved and does not affect the generation of the update package.|
140   | Header information (head node)| info| *time* | Yes| Time when the update package is generated. This field is reserved and does not affect the generation of the update package.|
141   | Component information (group node)| component| / | Yes| Content of this node: path of the component or image file to be packed into the update package. It is the root directory of the version package by default.|
142   | Component information (group node)| component| compAddr | Yes| Name of the partition corresponding to the component, for example, **system** or **vendor**.|
143   | Component information (group node)| component| compId | Yes| Component ID, which must be unique.|
144   | Component information (group node)| component| resType | Yes| This field is reserved and does not affect the generation of the update package.|
145   | Component information (group node)| component| compType | Yes| Image type, which can be a full or differential package. The value **0** indicates a full package, and value **1** indicates a differential package.|
146
147   > **NOTE**
148   > As mini and small systems do not support updating with a differential package, **compType** must be set to **0**, other than **1**.
149   >
150   > For mini and small systems, an update package cannot be created by changing partitions.
151
1524. Create the **OTA.tag** file, which contains the magic number of the update package. The magic number is fixed, as shown below:
153
154   ```text
155   package_type:ota1234567890qwertw
156   ```
157
1585. Create the **config** file, and configure the **bootargs** and **bootcmd** information in the file.
159   Example configuration:
160
161
162   ```text
163   setenv bootargs 'mem=128M console=ttyAMA0,115200 root=/dev/mmcblk0p3 rw rootfstype=ext4 rootwait blkdevparts=mmcblk0:1M
164   (u-boot.bin),9M(kernel.bin),50M(rootfs_ext4.img),50M(userfs.img)' setenv bootcmd 'mmc read 0x0 0x82000000 0x800 0x4800;bootm 0x82000000'
165   ```
166
1676. Generate the update package.
168
169   ```text
170   python build_update.py ./target_package/ ./output_package/ -pk ./rsa_private_key3072.pem -nz -nl2
171   ```
172
173   - **./target\_package/**: path of **target\_package**
174   - **./output\_package/**: output path of the update package
175   - -**pk ./rsa\_private\_key3072.pem**: path of the private key file
176   - -**nz**: **not zip** mode
177   - -**nl2**: non-standard system mode
178
179
180#### Standard System
1811. Create the **target\_package** folder with the following directory structure:
182
183
184   ```text
185   target_package
186   ├── {component_1}
187   ├── {component_2}
188   ├── ......
189   ├── {component_N}
190   └── updater_config
191           ├── BOARD.list
192           ├── VERSION.mbn
193           └── updater_specified_config.xml
194   ```
195
1962. Place the components to be updated, including their image file and **updater_binary** file, as the substitute of **{component\_N}** in the root directory of the **target\_package** folder.
197
198   Take RK3568 as an example. Place the image file in the following build directory: out/rk3568/packages/phone/images/.
199
200   Place the **updater_binary** file in the following build directory: out/rk3568/packages/phone/system/bin/.
201
2023. Configure the component configuration file in the **updater\_config** folder.
203
2044. Configure the list of products supported by the current update package in **BOARD.list** in the **updater\_config** folder.
205
206   Example configuration:
207
208
209   ```text
210   HI3516
211   RK3568
212   ```
213
214   Vendors can configure **Local BoardId** by calling **GetLocalBoardId()** in the **base/updater/updater/utils/utils.cpp** file. Ensure that **Local BoardId** configured in the **utils.cpp** file is present in **BOARD.list**. Otherwise, the update cannot be performed.
215
2165. Configure the versions supported by the current update package in **VERSION.mbn** in the **updater\_config** folder.
217
218   Version number format: Hi3516DV300-eng 10 QP1A.XXXXXX.{Major version number (6 digits)}.XXX{Minor version number (3 digits)}
219
220   For example, **Hi3516DV300-eng 10 QP1A.190711.020**, where **190711** is the major version number, and **020** is the minor version number.
221
222   Example configuration:
223
224
225   ```text
226   Hi3516DV300-eng 10 QP1A.190711.001
227   Hi3516DV300-eng 10 QP1A.190711.020
228   ```
229
230   Ensure that the basic version number is contained in **VERSION.mbn**.
231
2326. For update using an incremental (differential) package, also prepare a source version package (source\_package) in the same format as the target version package (target\_package), and then compress it as a **.zip** file, that is, **source\_package.zip**.
233
2347. If you create an update package with partitions changed, also provide the partition table file named **partition\_file.xml**. You can specify the file using the **-pf** parameter. For details about the configuration nodes, see the description below.
235
236   The partition table is generated with the image. The format is as follows:
237
238
239   ```xml
240   <?xml version="1.0" encoding="GB2312" ?>
241   <Partition_Info>
242   <Part Sel="1" PartitionName="Image 1" FlashType="Flash type" FileSystem="File system type" Start="Start address of the partition" Length="Size of the partition" SelectFile="Actual path of the image"/>
243   <Part Sel="1" PartitionName="Image 2" FlashType="Flash type" FileSystem="File system type" Start="Start address of the partition" Length="Size of the partition" SelectFile="Actual path of the image"/>
244   </Partition_Info>
245   ```
246
247   **Table 2** Description of labels in the partition table
248
249     | Name| Description|
250   | -------- | -------- |
251   | Sel | Whether the partition is effective. The value **1** indicates that the partition is effective, and value **0** indicates the opposite.|
252   | PartitionName | Partition name, for example, **fastboot** or **boot**.|
253   | FlashType | Flash type, for example, **emmc** or **ufs**.|
254   | FileSystem | File system type, for example, **ext3/4** or **f2fs**. The value can also be **none**.|
255   | Start | Start address of the partition, in MB. The start address of all partitions is **0**.|
256   | Length | Size of the partition, in MB.|
257   | SelectFile | Actual path of the image or file.|
258
2598. Generate the update package.
260
261   **Full package**
262
263   Run the following command:
264
265
266   ```text
267   python build_update.py ./target_package/ ./output_package/ -pk ./rsa_private_key2048.pem
268   ```
269
270   - **./target\_package/**: path of **target\_package**
271   - **./output\_package/**: output path of the update package
272   - -**pk ./rsa\_private\_key2048.pem**: path of the private key file
273
274   **Incremental (differential) package**
275
276   Run the following command:
277
278
279   ```text
280   python build_update.py ./target_package/ ./output_package/  -s ./source_package.zip  -pk ./rsa_private_key2048.pem
281   ```
282
283   - **./target\_package/**: path of **target\_package**
284   - **./output\_package/**: output path of the update package
285   - -**s ./source\_package.zip**: path of the **source\_package.zip** file. For update using a differential package, use the **-s** parameter to specify the source version package.
286   - -**pk ./rsa\_private\_key2048.pem**: path of the private key file
287
288   **Update package with partitions changed**
289
290   Run the following command:
291
292
293   ```text
294   python build_update.py  ./target_package/ ./output_package/  -pk ./rsa_private_key2048.pem  -pf ./partition_file.xml
295   ```
296
297   - **./target\_package/**: path of **target\_package**
298   - **./output\_package/**: output path of the update package
299   - -**pk ./rsa\_private\_key2048.pem**: path of the private key file
300   - -**pf ./partition\_file.xml**: path of the partition table file
301
302
303### Uploading the Update Package
304
305Upload the update package to the vendor's OTA server.
306
307
308### **Downloading the Update Package**
309
3101. Download the update package from the OTA server.
311
3122. (Optional) Insert an SD card (with a capacity greater than 100 MB) if the device is developed based on Hi3516D V300.
313
314
315### Integrating OTA Update Capabilities
316
3171. For mini and small systems
318
319   - Call the dynamic library **libhota.so**. The corresponding header files **hota\_partition.h** and **hota\_updater.h** are located in **base\update\sys\_installer\_lite\interfaces\kits\**.
320   - The **libhota.so** source code is located in **base\update\sys\_installer\_lite\frameworks\source**.
321   - For details about how to use APIs, see *API Application Scenarios* and update APIs in *API Reference*.
322   - If the development board needs to be adapted, see the **base\update\sys\_installer\_lite\hals\hal\_hota\_board.h** file.
323
3242. For the standard system, see the [JS API Reference](../../application-dev/reference/apis/js-apis-update.md) for details.
325
326
327#### API Application Scenario (Default)
328
329The update package is generated by following the instructions provided in Generating a Public/Private Key Pair and Generating an Update Package.
330
331
332##### How to Develop
333
3341. Download the update package for the current device, and then call the **HotaInit** function to initialize the OTA module.
335
3362. Call the **HotaWrite** function to verify, parse, and write data streams for the update into the device.
337
3383. Call the **HotaRestart** function to restart the system for the update to take effect. Call the **HotaCancel** function if you want to cancel the update.
339
340
341##### Sample Code
342
343  Perform an OTA update using the update package format and verification method provided by OpenHarmony.
344
345```cpp
346int main(int argc, char **argv)
347{
348    printf("this is update print!\r\n");
349    if (HotaInit(NULL, NULL) < 0) {
350        printf("ota update init fail!\r\n");
351        return -1;
352    }
353    int fd = open(OTA_PKG_FILE, O_RDWR, S_IRUSR | S_IWUSR);
354    if (fd < 0) {
355        printf("file open failed, fd = %d\r\n", fd);
356        (void)HotaCancel();
357        return -1;
358    }
359    int offset = 0;
360    int fileLen = lseek(fd, 0, SEEK_END);
361    int leftLen = fileLen;
362    while (leftLen > 0) {
363        if (lseek(fd, offset, SEEK_SET) < 0) {
364            close(fd);
365            printf("lseek fail!\r\n");
366            (void)HotaCancel();
367            return -1;
368        }
369        int tmpLen = leftLen >= READ_BUF_LEN ? READ_BUF_LEN : leftLen;
370        (void)memset_s(g_readBuf, READ_BUF_LEN, 0, READ_BUF_LEN);
371        if (read(fd, g_readBuf, tmpLen) < 0) {
372            close(fd);
373            printf("read fail!\r\n");
374            (void)HotaCancel();
375            return -1;
376        }
377        if (HotaWrite((unsigned char *)g_readBuf, offset, tmpLen) != 0) {
378            printf("ota write fail!\r\n");
379            close(fd);
380            (void)HotaCancel();
381            return -1;
382        }
383        offset += READ_BUF_LEN;
384        leftLen -= tmpLen;
385    }
386    close(fd);
387    printf("ota write finish!\r\n");
388    printf("device will reboot in 10s...\r\n");
389    sleep(10);
390    (void)HotaRestart();
391    return 0;
392}
393```
394
395
396#### API Application Scenario (Custom)
397
398The update package is generated in other ways instead of following the instructions provided in "Generating a Public/Private Key Pair" and "Generating an Update Package."
399
400
401##### **How to Develop**
402
4031. Download the update package for the current device, and then call the **HotaInit** function to initialize the OTA module.
404
4052. Call the **HotaSetPackageType** function to set the package type to **NOT\_USE\_DEFAULT\_PKG**.
406
4073. Call the **HotaWrite** function to write data streams into the device.
408
4094. Call the **HotaRead** function to read data. Vendors can choose whether to verify the data.
410
4115. (Optional) Call the **HotaSetBootSettings** function to set the startup tag used for entering the U-Boot mode during system restarting.
412
4136. Call the **HotaRestart** function to restart the system for the update to take effect. Call the **HotaCancel** function if you want to cancel the update.
414
415
416##### Sample Code
417
418  Perform an OTA update using the update package format and verification method not provided by OpenHarmony.
419
420```cpp
421int main(int argc, char **argv)
422{
423    printf("this is update print!\r\n");
424    if (HotaInit(NULL, NULL) < 0) {
425        printf("ota update init fail!\r\n");
426        (void)HotaCancel();
427        return -1;
428    }
429    (void)HotaSetPackageType(NOT_USE_DEFAULT_PKG);
430    int fd = open(OTA_PKG_FILE, O_RDWR, S_IRUSR | S_IWUSR);
431    if (fd < 0) {
432        printf("file open failed, fd = %d\r\n", fd);
433        (void)HotaCancel();
434        return -1;
435    }
436    int offset = 0;
437    int fileLen = lseek(fd, 0, SEEK_END);
438    int leftLen = fileLen;
439    while (leftLen > 0) {
440        if (lseek(fd, offset, SEEK_SET) < 0) {
441            close(fd);
442            printf("lseek fail!\r\n");
443            (void)HotaCancel();
444            return -1;
445        }
446        int tmpLen = leftLen >= READ_BUF_LEN ? READ_BUF_LEN : leftLen;
447        (void)memset_s(g_readBuf, READ_BUF_LEN, 0, READ_BUF_LEN);
448        if (read(fd, g_readBuf, tmpLen) < 0) {
449            close(fd);
450            printf("read fail!\r\n");
451            (void)HotaCancel();
452            return -1;
453        }
454        if (HotaWrite((unsigned char *)g_readBuf, offset, tmpLen) != 0) {
455            printf("ota write fail!\r\n");
456            close(fd);
457            (void)HotaCancel();
458            return -1;
459        }
460        offset += READ_BUF_LEN;
461        leftLen -= tmpLen;
462    }
463    close(fd);
464    printf("ota write finish!\r\n");
465    leftLen = fileLen;
466    while (leftLen > 0) {
467        int tmpLen = leftLen >= READ_BUF_LEN ? READ_BUF_LEN : leftLen;
468        (void)memset_s(g_readBuf, READ_BUF_LEN, 0, READ_BUF_LEN);
469        if (HotaRead(offset, READ_BUF_LEN, (unsigned char *)g_readBuf) != 0) {
470            printf("ota write fail!\r\n");
471            (void)HotaCancel();
472            return -1;
473        }
474        /* do your verify and parse */
475        offset += READ_BUF_LEN;
476        leftLen -= tmpLen;
477    }
478    /* set your boot settings */
479    (void)HotaSetBootSettings();
480    printf("device will reboot in 10s...\r\n");
481    sleep(10);
482    (void)HotaRestart();
483    return 0;
484}
485```
486
487
488##### Upgrading the System
489
490An application calls APIs of the OTA module to perform functions such as signature verification of the update package, anti-rollback, as well as burning and flushing to disk. After the update is complete, the system automatically restarts.
491
492For the mini and small systems that use the Hi3516D V300 open source suite, add the value of **LOCAL\_VERSION** to the version that needs to implement the anti-rollback function. For example, for **"ohos default 1.0"-&gt;"ohos default 1.1"**, add the value of **LOCAL\_VERSION** in **device\hisilicon\third\_party\uboot\u-boot-2020.01\product\hiupdate\ota\_update\ota\_local_info.c**.
493
494  Example configuration:
495
496```cpp
497const char *get_local_version(void)
498{
499#if defined(CONFIG_TARGET_HI3516EV200) || \
500    defined(CONFIG_TARGET_HI3516DV300)
501#define LOCAL_VERSION "ohos default 1.0" /* increase: default release version */
502```
503
504
505#### A/B Update Scenario
506
507
508##### How to Develop
509
5101. Download the update package through the update application.
5112. Invoke update_service to start the system installation service through SAMGR.
5123. Let the system installation service perform a silent update.
5134. Activate the new version upon restarting.
514
515
516##### How to Develop
517
518- Invoke update_service to call JS APIs to implement the related service logic in an A/B update.
519
520   1. Displaying the update package installation progress:
521   ```cpp
522   on(eventType: "upgradeProgress", callback: UpdateProgressCallback): void;
523   ```
524
525   2. Setting the activation policy (immediate restart, restart at night, and activation on next restart):
526   ```cpp
527   upgrade(apply)
528   ```
529
530
531- Invoke update_service to start the system installation service through SAMGR.
532
533   1. Start the system installation service and set up an IPC connection.
534   ```cpp
535   int SysInstallerInit(void* callback)
536   ```
537
538   2. Install the A/B update package in the specified path.
539   ```cpp
540   int StartUpdatePackageZip(string path)
541   ```
542
543   3. Set the update progress callback.
544   ```cpp
545   int SetUpdateProgressCallback(void* callback)
546   ```
547
548   4. Obtain the installation status of the update package (0: not started; 1: installing; 2: installed).
549   ```cpp
550   int GetUpdateStatus()
551   ```
552
553
554- Use HDI APIs to activate the new version.
555
556   1. Obtain the current boot slot to determine the partition to be updated.
557   ```cpp
558   int GetCurrentSlot()
559   ```
560
561   2. Upon completion of the update, switch the updated slot and restart the system for the new version to take effect.
562   ```cpp
563   int SetActiveBootSlot(int slot)
564   ```
565
566   3. Upon starting of the update, set the slot of the partition to be updated to the **unbootable** state.
567   ```cpp
568   int setSlotUnbootable(int slot)
569   ```
570
571   4. Obtain the number of slots. The value **1** indicates a common update, and the value **2** indicates an A/B update.
572   ```cpp
573   int32 GetSlotNum(void)
574   ```
575
576
577##### FAQs
578
5791. An exception occurs during installation of the update package.
580<br>The system keeps running with the current version. It will attempt a new update in the next package search period.
581
5822. An exception occurs during activation of the new version if the update package is installed in a non-boot partition.
583<br>Perform a rollback and set the partition to the **unbootable** state so that the system does not boot from this partition.
584
585
586##### Verification
587
588In normal cases, the device can download the update package from the OTA server in the background, perform a silent update, and then restart according to the preconfigured activation policy for the new version to take effect.
589