J6X OTA升级端介绍
===================

J6X 对外提供 libupdate.so，其中包含升级所需API， API定义请参考 :doc:`OTA api <../../api/basic_api/api_basic_ota>`

ota_tool 使用
-------------

ota_tool 是使用 libupdate.so API 实现的一个工具，用于板端手动发起OTA升级。ota_tool 可作为 OTA Service 开发时的 Sample 参考，代码位于 hbre/otaupdate/src/ota_tool。

.. code:: bash

   ota_tool Usage:
      -v, --version                      get this library's version, 
                                             system version, 
                                             antirollback version
      -b, --boot                         check ota update status when boot.
      -s, --setpartition [partition]     set A/B slot partition, 0--A; 1--B.
      -g, --getpartition                 get A/B slot partition, 0--A; 1--B.
      -p, --package [package_path]       specify the path of package, the package paths can be relative or absolute, it's length must be smaller than 64 bytes.
      -n, --noreboot                     request ota without reboot.
      -c, --checksign                    signature check.
      -i, --signature                    signature information file.
      -f, --force                        reboot to recovery mode and start force upgrading automatically.
      -h, --help                         Display this help screen.

使用ota_tool进行升级前，需要将OTA升级包上传至板端。

参数介绍：

-  -h 用于获取帮助信息

-  -v 用于获取 libupdate.so 版本、当前系统软件版本、antirollback版本

-  -b 用于启动升级结果检查（系统启动后会自动启动，用户无需关心）

-  -s 设置下次启动 A/B slot

-  -g 获取当前 A/B slot

-  -p 指定升级包

-  -n 升级成功后不自动重启

-  -c 使能签名检查

-  -i 指定签名文件（必须跟在-p后面）

-  -f 强制进入recovery模式升级

举例：

.. code:: c

   ota_tool -p all_in_one_full.zip

ota_tool 实现
-------------

ota_tool 使用C语言实现，源码仅 `otainterface.c` 一个文件。
实现了获取系统软件版本、升级结果检查、设置/获取ab slot、OTA升级、强制升级、OTA包签名校验等功能。

main函数前半部分都在解析参数，如果-f参数传入，则调用 `otarecovery_command_write` 将升级包信息写入文件 `/ota/ota_tool_force_upgrade` 后重启SoC。

若-c参数传入，则使用传入的签名文件对升级包进行签名校验。

最后，调用 `ota_update_all_img` 启动升级。

ota_update_all_img
~~~~~~~~~~~~~~~~~~

.. code:: c

   static int32_t ota_update_all_img(const char *zip_path)
   {
   	int32_t progress = 0;
   
   	uint8_t		    slot = 0;
   	uint8_t		    next_slot = 0;
   	int32_t		    ret = 0;
   	ota_update_result_e result = 0;
   	char		    part_name[ARRAY_32] = { 0 };
   
   	ret = otaGetPartition(&slot);
   	if (ret < 0) {
   		return ret;
   	}
   
   	if (slot == 2) {
   		next_slot = 0;
   		printf("The slot [%d] to be burned\n", next_slot);
   	} else {
   		next_slot = 1 - slot;
   		printf("The slot [%d] to be burned\n", next_slot);
   	}
   
   	ret = otaInitLib();
   	if (ret < 0) {
   		printf("error:init failed!\n");
   		return ret;
   	}
   
   	ret = otaRequestStart(zip_path, OTA_TOOL);
   	if (ret < 0) {
   		printf("error: start ota update failed!\n");
   		ret = -1;
   		goto err;
   	}
   	while (otaGetResult() != OTA_UPGRADE_SUCCESS && otaGetResult() != OTA_UPGRADE_FAILED) {
   		progress = otaGetProgress();
   		result = otaGetResult();
   		otaGetUpdatingImageName(part_name, sizeof(part_name));
   
   		if (result == UPGRADE_FAILED) {
   			printf("error: ota update failed!\n");
   			ret = -1;
   			break;
   		}
   		OTA_show_Process_Bar(part_name, progress,
   				     "OTA is upgrading ...");
   		usleep(100 * 1000);
   	}
   
   err:
   	if (otaGetResult() == OTA_UPGRADE_SUCCESS) {
   		ret = otaSetPartition(next_slot);
   		if (ret < 0) {
   			printf("error: set partition failed!\n");
   			return ret;
   		}
   		if (g_is_reboot == true) {
   			printf("reboot system!\n");
   			ota_system_exe("reboot");
   		} else {
   			printf("ota update success and waiting for reboot!\n");
   		}
   	}
   	otaDeinitLib();
   
   	return ret;
   }

1. 调用 `otaGetPartition` 获取当前所在 ab slot

2. 调用 `otaInitLib` 初始化 libupdate.so

3. 调用 `otaRequestStart` 并传入升级包和owner(OTA_TOOL)，开始升级

4. 等待 `otaGetResult` 的结果为 `OTA_UPGRADE_SUCCESS` 或 `OTA_UPGRADE_FAILED` 。等待过程中，调用 `otaGetProgress` 、 `otaGetResult` 、 `otaGetUpdatingImageName` 获取升级进度、升级结果、正在升级的镜像，并调用 `OTA_show_Process_Bar` 打印到控制台

5. 若升级结果 `otaGetResult` 为 `OTA_UPGRADE_SUCCESS` ，则认为升级成功，调用 `otaSetPartition` 设置 ab slot 到对向 slot ，然后重启 SoC

.. image:: media/otatool-ota_update_all_img.png
   :align: center
   :alt: Framework

升级流程结束重启后，应启动 `ota_tool -b` 对升级结果进行检查校验，并进行后续操作。

ota_boot_check
~~~~~~~~~~~~~~

J6 启动后，会启动一个 `hobot-otatool.service` 服务，该服务调用了 `ota_tool -b` ，该选项会检查 `/ota/ota_tool_force_upgrade` 文件是否存在，若存在，则进入升级流程（该进程会重新调用升级命令）。
若该文件不存在，则进入升级校验流程 `ota_boot_check`

.. code:: c
   
   int32_t ota_boot_check(void)
   {
   	int32_t		      ret = 0;
   	enum ota_update_owner owner = 0;
   
   	if ((ret = otaInitLib()) != 0) {
   		printf("error: init failed!\n");
   		goto exit;
   	}
   
   	if ((ret = otaGetOwnerFlag(&owner)) != 0) {
   		printf("error: Get owner flag failed!\n");
   		goto exit;
   	}
   
   	if (owner == NORMAL_BOOT) {
   		printf("Normal boot\n");
   		if ((ret = otaMarkOTASuccessful()) != 0) {
   			printf("error: mark boot success failed\n");
   		}
   		return ret;
   	}
   
   	if (owner != OTA_TOOL) {
   		printf("ota_tool is not owner, owner is [%d]\n", owner);
   		return 0;
   	}
   
   	if ((ret = otaCheckUpdate()) != 0) {
   		printf("error: boot check failed\n");
   		goto exit;
   	}
   
   	if ((ret = otaMarkOTASuccessful()) != 0) {
   		printf("error: mark boot success failed\n");
   		goto exit;
   	}
   
   	if ((ret = otaPartitionSync()) != 0) {
   		printf("error: partition sync failed\n");
   		goto exit;
   	}
   
   	ret = otaDeinitLib();
   
   exit:
   	otaClearFlags();
   	return ret;
   }

1. 调用 `otaInitLib`

2. 调用 `otaGetOwnerFlag` 获取升级owner

3. 若 owner 为 `NORMAL_BOOT` ，则调用 `otaMarkOTASuccessful` 标记启动成功，然后退出。

4. 若 owner 不为 `OTA_TOOL` ，则正常退出。

5. 调用 `otaCheckUpdate` 获取升级结果。若升级结果异常，则调用 `otaClearFlags` 清除 OTA 标记，终止OTA流程。

6. 调用 `otaMarkOTASuccessful` 标记启动成功。

7. 调用 `otaPartitionSync` 进行 AB 分区、 BAK 分区同步。

.. image:: media/otatool-ota_boot_check.png
   :align: center
   :alt: Framework
