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- Copy the **diff** file in **out/rk3568/clang_x64/updater/updater/** and the **libext2fs.so**, **e2fsdriod**, **libext2_com_err.so**, and **libext2_misc.so** files in **out/rk3568/clang_x64/thirdparty/e2fsprogs** to the **packaging_tools/lib/** directory of the packaging tool. 47 48 49## How to Develop 50 51<a href="#generating-a-public/private-key-pair">1. Use the OpenSSL tool to generate a public/private key pair. 52 53<a href="#making-an-update-package">2. Use the packaging tool to generate an update package.</a> 54 55  <a href="#mini-and-small systems">2.1 Mini and small systems</a> 56 57  <a href="#standard system">2.2 Standard system</a> 58 59<a href="#uploading-the-update package">3. Upload the update package to the vendor's OTA server.</a> 60 61<a href="#downloading-the-update-package">4. Download the update package from the vendor's OTA server.</a> 62 63<a href="#integrating-the-OTA-update-capability">5. Integrate the OTA update capability. 64 65  <a href="#api-application-scenario-default">5.1 API application scenario (default)</a> 66 67  <a href="#api-application-scenario-custom">5.2 API application scenario (custom)</a> 68 69  <a href="#ab-update-scenario">5.3 A/B update scenario</a> 70 71 72## How to Develop 73 74 75### Generating a Public/Private Key Pair 761. Use the OpenSSL tool to generate a public-private key pair. Place the **signing_cert.crt** file in the **packaging_tools/sign_cert/** directory of the packaging tool. 77 783. 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. 79 805. 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. 81 Example configuration: 82 83 ```c 84 static unsigned char g_pub_key[] = { 85 0x30, 0x82, 0x01, 0x0A, 0x02, 0x82, 0x01, 0x01, 86 0x00, 0xBF, 0xAA, 0xA5, 0xB3, 0xC2, 0x78, 0x5E, 87 } 88 ``` 89 90 91### Making an Update Package 92 93 94#### Mini and Small Systems 95 961. Create the **target\_package** folder with the following directory structure: 97 98 OTA.tag and config are not required for lightweight systems and small systems upgraded from AB. 99 100 ```text 101 target_package 102 ├── OTA.tag 103 ├── config 104 ├── {component_1} 105 ├── {component_2} 106 ├── ...... 107 ├── {component_N} 108 └── updater_config 109 └── updater_specified_config.xml 110 ``` 111 1122. 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. 113 1143. Configure the **updater\_specified\_config.xml** file in the **updater_config** folder. 115 Example configuration: 116 117 118 ```xml 119 <?xml version="1.0"?> 120 <package> 121 <head name="Component header information"> 122 <info fileVersion="02" prdID="hisi" softVersion="OpenHarmony x.x" date="202x.xx.xx" time="xx:xx:xx">head info</info> 123 </head> 124 <group name="Component information"> 125 <component compAddr="ota_tag" compId="27" resType="5" compType="0" compVer="1.0">./OTA.tag</component> 126 <component compAddr="config" compId="23" resType="5" compType="0" compVer="1.0">./config</component> 127 <component compAddr="bootloader" compId="24" resType="5" compType="0" compVer="1.0">./u-boot-xxxx.bin</component> 128 </group> 129 </package> 130 ``` 131 132 **Table 1** Description of nodes in the component configuration file 133 134 | Type| Node Name| Node Label| Mandatory| Description| 135 | -------- | -------- | -------- | -------- | -------- | 136 | Header information (head node)| info| / | Yes| Head node information. Set this field to **head info**.| 137 | Header information (head node)| info| fileVersion | Yes| Verification mode of the **update.bin** file. Set this field to **02**.| 138 | Header information (head node)| info| prdID | Yes| Reserved. This field does not affect the generation of the update package.| 139 | 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.| 140 | 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.| 141 | 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.| 142 | 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.| 143 | Component information (group node)| component| compAddr | Yes| Name of the partition corresponding to the component, for example, **system** or **vendor**.| 144 | Component information (group node)| component| compId | Yes| Component ID, which must be unique.| 145 | Component information (group node)| component| resType | Yes| Reserved. This field does not affect the generation of the update package.| 146 | 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.| 147 148 > **NOTE** 149 > As mini and small systems do not support updating with a differential package, **compType** must be set to **0**, other than **1**. 150 > 151 > For mini and small systems, an update package cannot be created by changing partitions. 152 1534. Create the **OTA.tag** file, which contains the magic number of the update package. The magic number is fixed, as shown below: 154 155 ```text 156 package_type:ota1234567890qwertw 157 ``` 158 1595. Create the **config** file, and configure the **bootargs** and **bootcmd** information in the file. 160 Example configuration: 161 162 163 ```text 164 setenv bootargs 'mem=128M console=ttyAMA0,115200 root=/dev/mmcblk0p3 rw rootfstype=ext4 rootwait blkdevparts=mmcblk0:1M 165 (u-boot.bin),9M(kernel.bin),50M(rootfs_ext4.img),50M(userfs.img)' setenv bootcmd 'mmc read 0x0 0x82000000 0x800 0x4800;bootm 0x82000000' 166 ``` 167 1686. Generate the update package. 169 170 ```text 171 python build_update.py ./target_package/ ./output_package/ -pk ./rsa_private_key3072.pem -nz -nl2 172 ``` 173 174 - **./target\_package/**: path of **target\_package** 175 - **./output\_package/**: output path of the update package 176 - -**pk ./rsa\_private\_key3072.pem**: path of the private key file 177 - -**nz**: **not zip** mode 178 - -**nl2**: non-standard system mode 179 180 181#### Standard System 1821. Create the **target\_package** folder with the following directory structure: 183 184 185 ```text 186 target_package 187 ├── {component_1} 188 ├── {component_2} 189 ├── ...... 190 ├── {component_N} 191 └── updater_config 192 ├── BOARD.list 193 ├── VERSION.mbn 194 └── updater_specified_config.xml 195 ``` 196 1972. 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. 198 199 Take RK3568 as an example. Place the image file in the following build directory: out/rk3568/packages/phone/images/. 200 201 Place the **updater_binary** file in the following build directory: out/rk3568/packages/phone/system/bin/. 202 2033. Configure the component configuration file in the **updater\_config** folder. 204 2054. Configure the list of products supported by the current update package in **BOARD.list** in the **updater\_config** folder. 206 207 Example configuration: 208 209 210 ```text 211 HI3516 212 RK3568 213 ``` 214 215 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. 216 2175. Configure the versions supported by the current update package in **VERSION.mbn** in the **updater\_config** folder. 218 219 Version number format: Hi3516DV300-eng 10 QP1A.XXXXXX.{Major version number (6 digits)}.XXX{Minor version number (3 digits)} 220 221 For example, **Hi3516DV300-eng 10 QP1A.190711.020**, where **190711** is the major version number, and **020** is the minor version number. 222 223 Example configuration: 224 225 226 ```text 227 Hi3516DV300-eng 10 QP1A.190711.001 228 Hi3516DV300-eng 10 QP1A.190711.020 229 ``` 230 231 Ensure that the basic version number is contained in **VERSION.mbn**. 232 2336. 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**. 234 2357. 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. 236 237 The partition table is generated with the image. The format is as follows: 238 239 240 ```xml 241 <?xml version="1.0" encoding="GB2312" ?> 242 <Partition_Info> 243 <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"/> 244 <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"/> 245 </Partition_Info> 246 ``` 247 248 **Table 2** Description of labels in the partition table 249 250 | Name| Description| 251 | -------- | -------- | 252 | Sel | Whether the partition is effective. The value **1** indicates that the partition is effective, and value **0** indicates the opposite.| 253 | PartitionName | Partition name, for example, **fastboot** or **boot**.| 254 | FlashType | Flash type, for example, **emmc** or **ufs**.| 255 | FileSystem | File system type, for example, **ext3/4** or **f2fs**. The value can also be **none**.| 256 | Start | Start address of the partition, in MB. The start address of all partitions is **0**.| 257 | Length | Size of the partition, in MB.| 258 | SelectFile | Actual path of the image or file.| 259 2608. Generate the update package. 261 262 **Full package** 263 264 Run the following command: 265 266 267 ```text 268 python build_update.py ./target_package/ ./output_package/ -pk ./rsa_private_key2048.pem 269 ``` 270 271 - **./target\_package/**: path of **target\_package** 272 - **./output\_package/**: output path of the update package 273 - -**pk ./rsa\_private\_key2048.pem**: path of the private key file 274 275 **Incremental (differential) package** 276 277 Run the following command: 278 279 280 ```text 281 python build_update.py ./target_package/ ./output_package/ -s ./source_package.zip -pk ./rsa_private_key2048.pem 282 ``` 283 284 - **./target\_package/**: path of **target\_package** 285 - **./output\_package/**: output path of the update package 286 - -**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. 287 - -**pk ./rsa\_private\_key2048.pem**: path of the private key file 288 289 **Update package with partitions changed** 290 291 Run the following command: 292 293 294 ```text 295 python build_update.py ./target_package/ ./output_package/ -pk ./rsa_private_key2048.pem -pf ./partition_file.xml 296 ``` 297 298 - **./target\_package/**: path of **target\_package** 299 - **./output\_package/**: output path of the update package 300 - -**pk ./rsa\_private\_key2048.pem**: path of the private key file 301 - -**pf ./partition\_file.xml**: path of the partition table file 302 303 304### Uploading the Update Package 305 306Upload the update package to the vendor's OTA server. 307 308 309### **Downloading the Update Package** 310 3111. Download the update package from the OTA server. 312 3132. (Optional) Insert an SD card (with a capacity greater than 100 MB) if the device is developed based on Hi3516D V300. 314 315 316### Integrating OTA Update Capabilities 317 3181. For mini and small systems 319 320 - 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\**. 321 - The **libhota.so** source code is located in **base\update\sys\_installer\_lite\frameworks\source**. 322 - For details about how to use APIs, see *API Application Scenarios* and update APIs in *API Reference*. 323 - If the development board needs to be adapted, see the **base\update\sys\_installer\_lite\hals\hal\_hota\_board.h** file. 324 3252. For the standard system, see the [JS API Reference](../../application-dev/reference/apis/js-apis-update.md) for details. 326 327 328#### API Application Scenario (Default) 329 330The update package is generated by following the instructions provided in Generating a Public/Private Key Pair and Generating an Update Package. 331 332 333##### **How to Develop** 334 3351. Download the update package for the current device, and then call the **HotaInit** function to initialize the OTA module. 336 3372. Call the **HotaWrite** function to verify, parse, and write data streams for the update into the device. 338 3393. 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. 340 341 342##### Sample Code 343 344 Perform an OTA update using the update package format and verification method provided by OpenHarmony. 345 346```cpp 347int main(int argc, char **argv) 348{ 349 printf("this is update print!\r\n"); 350 if (HotaInit(NULL, NULL) < 0) { 351 printf("ota update init fail!\r\n"); 352 return -1; 353 } 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 printf("device will reboot in 10s...\r\n"); 390 sleep(10); 391 (void)HotaRestart(); 392 return 0; 393} 394``` 395 396 397#### API Application Scenario (Custom) 398 399The 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." 400 401 402##### **How to Develop** 403 4041. Download the update package for the current device, and then call the **HotaInit** function to initialize the OTA module. 405 4062. Call the **HotaSetPackageType** function to set the package type to **NOT\_USE\_DEFAULT\_PKG**. 407 4083. Call the **HotaWrite** function to write data streams into the device. 409 4104. Call the **HotaRead** function to read data. Vendors can choose whether to verify the data. 411 4125. (Optional) Call the **HotaSetBootSettings** function to set the startup tag used for entering the U-Boot mode during system restarting. 413 4146. 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. 415 416 417##### Sample Code 418 419 Perform an OTA update using the update package format and verification method not provided by OpenHarmony. 420 421```cpp 422int main(int argc, char **argv) 423{ 424 printf("this is update print!\r\n"); 425 if (HotaInit(NULL, NULL) < 0) { 426 printf("ota update init fail!\r\n"); 427 (void)HotaCancel(); 428 return -1; 429 } 430 (void)HotaSetPackageType(NOT_USE_DEFAULT_PKG); 431 int fd = open(OTA_PKG_FILE, O_RDWR, S_IRUSR | S_IWUSR); 432 if (fd < 0) { 433 printf("file open failed, fd = %d\r\n", fd); 434 (void)HotaCancel(); 435 return -1; 436 } 437 int offset = 0; 438 int fileLen = lseek(fd, 0, SEEK_END); 439 int leftLen = fileLen; 440 while (leftLen > 0) { 441 if (lseek(fd, offset, SEEK_SET) < 0) { 442 close(fd); 443 printf("lseek fail!\r\n"); 444 (void)HotaCancel(); 445 return -1; 446 } 447 int tmpLen = leftLen >= READ_BUF_LEN ? READ_BUF_LEN : leftLen; 448 (void)memset_s(g_readBuf, READ_BUF_LEN, 0, READ_BUF_LEN); 449 if (read(fd, g_readBuf, tmpLen) < 0) { 450 close(fd); 451 printf("read fail!\r\n"); 452 (void)HotaCancel(); 453 return -1; 454 } 455 if (HotaWrite((unsigned char *)g_readBuf, offset, tmpLen) != 0) { 456 printf("ota write fail!\r\n"); 457 close(fd); 458 (void)HotaCancel(); 459 return -1; 460 } 461 offset += READ_BUF_LEN; 462 leftLen -= tmpLen; 463 } 464 close(fd); 465 printf("ota write finish!\r\n"); 466 leftLen = fileLen; 467 while (leftLen > 0) { 468 int tmpLen = leftLen >= READ_BUF_LEN ? READ_BUF_LEN : leftLen; 469 (void)memset_s(g_readBuf, READ_BUF_LEN, 0, READ_BUF_LEN); 470 if (HotaRead(offset, READ_BUF_LEN, (unsigned char *)g_readBuf) != 0) { 471 printf("ota write fail!\r\n"); 472 (void)HotaCancel(); 473 return -1; 474 } 475 /* do your verify and parse */ 476 offset += READ_BUF_LEN; 477 leftLen -= tmpLen; 478 } 479 /* set your boot settings */ 480 (void)HotaSetBootSettings(); 481 printf("device will reboot in 10s...\r\n"); 482 sleep(10); 483 (void)HotaRestart(); 484 return 0; 485} 486``` 487 488 489##### Upgrading the System 490 491An 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. 492 493For 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"->"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**. 494 495 Example configuration: 496 497```cpp 498const char *get_local_version(void) 499{ 500#if defined(CONFIG_TARGET_HI3516EV200) || \ 501 defined(CONFIG_TARGET_HI3516DV300) 502#define LOCAL_VERSION "ohos default 1.0" /* increase: default release version */ 503``` 504 505 506#### A/B Update Scenario 507 508 509##### How to Develop 510 5111. Download the update package through the update application. 5122. Invoke update_service to start the system installation service through SAMGR. 5133. Let the system installation service perform a silent update. 5144. Activate the new version upon restarting. 515 516 517##### How to Develop 518 519- Invoke update_service to call JS APIs to implement the related service logic in an A/B update. 520 521 1. Displaying the update package installation progress: 522 ```cpp 523 on(eventType: "upgradeProgress", callback: UpdateProgressCallback): void; 524 ``` 525 526 2. Setting the activation policy (immediate restart, restart at night, and activation on next restart): 527 ```cpp 528 upgrade(apply) 529 ``` 530 531 532- Invoke update_service to start the system installation service through SAMGR. 533 534 1. Start the system installation service and set up an IPC connection. 535 ```cpp 536 int SysInstallerInit(void* callback) 537 ``` 538 539 2. Install the A/B update package in the specified path. 540 ```cpp 541 int StartUpdatePackageZip(string path) 542 ``` 543 544 3. Set the update progress callback. 545 ```cpp 546 int SetUpdateProgressCallback(void* callback) 547 ``` 548 549 4. Obtain the installation status of the update package (0: not started; 1: installing; 2: installed). 550 ```cpp 551 int GetUpdateStatus() 552 ``` 553 554 555- Use HDI APIs to activate the new version. 556 557 1. Obtain the current boot slot to determine the partition to be updated. 558 ```cpp 559 int GetCurrentSlot() 560 ``` 561 562 2. Upon completion of the update, switch the updated slot and restart the system for the new version to take effect. 563 ```cpp 564 int SetActiveBootSlot(int slot) 565 ``` 566 567 3. Upon starting of the update, set the slot of the partition to be updated to the **unbootable** state. 568 ```cpp 569 int setSlotUnbootable(int slot) 570 ``` 571 572 4. Obtain the number of slots. The value **1** indicates a common update, and the value **2** indicates an A/B update. 573 ```cpp 574 int32 GetSlotNum(void) 575 ``` 576 577 578##### FAQs 579 5801. An exception occurs during installation of the update package. 581<br>The system keeps running with the current version. It will attempt a new update in the next package search period. 582 5832. An exception occurs during activation of the new version if the update package is installed in a non-boot partition. 584<br>Perform a rollback and set the partition to the **unbootable** state so that the system does not boot from this partition. 585 586 587##### Verification 588 589In 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. 590