From 73e015c4de555da881c77167deb0682d879789f8 Mon Sep 17 00:00:00 2001 From: mamingshuai Date: Wed, 2 Jun 2021 00:04:26 +0800 Subject: [PATCH] update OpenHarmony 2.0 Canary --- .gitattributes | 0 LICENSE | 177 ++++ README.en.md | 36 - README.md | 172 +++- README_zh.md | 159 +++ callback/include/update_callback.h | 43 + callback/include/update_callback_proxy.h | 41 + callback/include/update_callback_stub.h | 33 + callback/src/update_callback.cpp | 51 + callback/src/update_callback_proxy.cpp | 76 ++ callback/src/update_callback_stub.cpp | 53 + client/BUILD.gn | 65 ++ client/update_client.cpp | 910 ++++++++++++++++++ client/update_client.h | 241 +++++ client/update_module.cpp | 278 ++++++ client/update_session.cpp | 232 +++++ client/update_session.h | 180 ++++ engine/BUILD.gn | 83 ++ engine/etc/update_config.xml | 17 + engine/etc/updater_sa.rc | 21 + engine/include/progress_thread.h | 109 +++ engine/include/update_service.h | 101 ++ engine/include/update_service_proxy.h | 56 ++ engine/include/update_service_stub.h | 40 + engine/sa_profile/3006.xml | 24 + engine/sa_profile/BUILD.gn | 20 + engine/src/progress_thread.cpp | 208 ++++ engine/src/update_helper.cpp | 289 ++++++ engine/src/update_service.cpp | 528 ++++++++++ engine/src/update_service_stub.cpp | 177 ++++ interfaces/innerkits/engine/BUILD.gn | 64 ++ .../engine/update_service_kits_impl.cpp | 232 +++++ .../innerkits/engine/update_service_proxy.cpp | 213 ++++ .../innerkits/include/iupdate_callback.h | 45 + .../innerkits/include/iupdate_service.h | 73 ++ interfaces/innerkits/include/update_helper.h | 220 +++++ .../innerkits/include/update_service_kits.h | 64 ++ .../include/update_service_kits_impl.h | 96 ++ .../kits/js/declaration/@ohos.update.d.ts | 439 +++++++++ 39 files changed, 5805 insertions(+), 61 deletions(-) create mode 100644 .gitattributes create mode 100644 LICENSE delete mode 100644 README.en.md mode change 100644 => 100755 README.md create mode 100755 README_zh.md create mode 100755 callback/include/update_callback.h create mode 100755 callback/include/update_callback_proxy.h create mode 100755 callback/include/update_callback_stub.h create mode 100755 callback/src/update_callback.cpp create mode 100755 callback/src/update_callback_proxy.cpp create mode 100644 callback/src/update_callback_stub.cpp create mode 100755 client/BUILD.gn create mode 100644 client/update_client.cpp create mode 100644 client/update_client.h create mode 100644 client/update_module.cpp create mode 100644 client/update_session.cpp create mode 100644 client/update_session.h create mode 100755 engine/BUILD.gn create mode 100644 engine/etc/update_config.xml create mode 100755 engine/etc/updater_sa.rc create mode 100755 engine/include/progress_thread.h create mode 100755 engine/include/update_service.h create mode 100755 engine/include/update_service_proxy.h create mode 100755 engine/include/update_service_stub.h create mode 100755 engine/sa_profile/3006.xml create mode 100755 engine/sa_profile/BUILD.gn create mode 100755 engine/src/progress_thread.cpp create mode 100755 engine/src/update_helper.cpp create mode 100644 engine/src/update_service.cpp create mode 100755 engine/src/update_service_stub.cpp create mode 100755 interfaces/innerkits/engine/BUILD.gn create mode 100755 interfaces/innerkits/engine/update_service_kits_impl.cpp create mode 100755 interfaces/innerkits/engine/update_service_proxy.cpp create mode 100755 interfaces/innerkits/include/iupdate_callback.h create mode 100755 interfaces/innerkits/include/iupdate_service.h create mode 100755 interfaces/innerkits/include/update_helper.h create mode 100755 interfaces/innerkits/include/update_service_kits.h create mode 100755 interfaces/innerkits/include/update_service_kits_impl.h create mode 100644 interfaces/kits/js/declaration/@ohos.update.d.ts diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e69de29 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f433b1a --- /dev/null +++ b/LICENSE @@ -0,0 +1,177 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS diff --git a/README.en.md b/README.en.md deleted file mode 100644 index 185a744..0000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# update_updateservice - -#### Description -Update service module | 升级服务层组件 - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 32242f1..07b23bd --- a/README.md +++ b/README.md @@ -1,37 +1,159 @@ -# update_updateservice +# Update Service -#### 介绍 -Update service module | 升级服务层组件 +- [Introduction](#section184mcpsimp) +- [Directory Structure](#section193mcpsimp) +- [Description](#section208mcpsimp) + - [JS APIs](#section210mcpsimp) + - [Usage](#section253mcpsimp) -#### 软件架构 -软件架构说明 +- [Repositories Involved](#section366mcpsimp) +## Introduction -#### 安装教程 +The update service is a system ability \(SA\) started by the init process of OHOS to implement an update. -1. xxxx -2. xxxx -3. xxxx +The update service provides the following functions: -#### 使用说明 +1. Searching for available update packages -1. xxxx -2. xxxx -3. xxxx +2. Downloading update packages -#### 参与贡献 +3. Setting and obtaining the update policy -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +4. Triggering an update +## Directory Structure -#### 特技 +``` +base/update/updateservice # Update service code +├── client # NAPI-based update client +├── engine # Update client engine +│ ├── etc # rc configuration files for the update client engine +│ ├── include # Header files for the update client engine +│ ├── sa_profile # SA profiles +│ └── src # Source code of the update client engine +├── interfaces # Update client APIs +│ └── innerkits # SA APIs +├── kits # External APIs +│ └── js # JS APIs for the update app +└── tests # Test code + └── unittest # Unit test code for the update client +``` + +## Description + +### JS APIs + + + + + + + + + + + + + + + + + + + + + + + + +

API

+

Description

+

checkNewVersion

+

Checks whether a new update package is available.

+

download()

+

Downloads the update package.

+

upgrade()

+

Writes the update command to the misc partition and runs the reboot command to access the updater.

+

getNewVersionInfo()

+

Obtains the version information after a version update.

+

setUpdatePolicy

+

Sets the update policy.

+

getUpdatePolicy

+

Obtains the update policy.

+
+ +### Usage + +1. Import **libupdateclient**. + +``` +import client from 'libupdateclient.z.so' +``` + +2. Obtain the **Updater** object. + +``` +let updater = client.getUpdater('OTA'); +``` + +3. Obtain the new version information. + +``` +updater.getNewVersionInfo(info => { + info "New version information" +}); +``` + +4. Checks for a new version. + +``` +updater.checkNewVersion(info => { + info "New version information" +}); +``` + +5. Download the new version and monitor the download process. + +``` +updater.download(); +updater.on("downloadProgress", progress => { + progress "Download progress information" +}); +``` + +6. Start the update. + +``` +updater.upgrade(); +updater.on("upgradeProgress", progress => { + progress "Update progress information" +}); +``` + +7. Set the update policy. + +``` +updater.setUpdatePolicy(result => { + result "Update policy setting result" +}); +``` + +8. Check the update policy. + +``` +updater.getUpdatePolicy(policy => { + policy "Update policy" +}); +``` + +## Repositories Involved + +Update subsystem + +update\_app + +**update\_updateservice** + +update\_updater -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README_zh.md b/README_zh.md new file mode 100755 index 0000000..06374d0 --- /dev/null +++ b/README_zh.md @@ -0,0 +1,159 @@ +# 升级服务组件 + +- [简介](#section184mcpsimp) +- [目录](#section193mcpsimp) +- [说明](#section208mcpsimp) + - [JS接口说明](#section210mcpsimp) + - [使用说明](#section253mcpsimp) + +- [相关仓](#section366mcpsimp) + +## 简介 + +升级服务组件是一个SA\(System Ability\), 由OHOS 的init 进程负责启动。 + +升级服务器引擎主要功能包括: + +1、查找可用的升级包 + +2、下载升级包 + +3、设置/获取升级策略 + +4、触发升级 + +## 目录 + +``` +base/update/updateservice # 升级服务代码仓目录 +├── client # 升级客户端napi 接口目录 +├── engine # 升级客户端引擎服务目录 +│ ├── etc # 升级客户端引擎rc配置文件目录 +│ ├── include # 升级客户端引擎头文件目录 +│ ├── sa_profile # SA 配置文件目录 +│ └── src # 升级客户端引擎源码目录 +├── interfaces # 升级客户端接口目录 +│ └── innerkits # SA 接口定义和封装目录 +├── kits # 对外接口封装目录 +│ └── js # 提供给升级客户端应用的JS 接口目录 +└── tests # 测试代码目录 + └── unittest # 升级客户端UT代码目录 +``` + +## 说明 + +### JS接口说明 + + + + + + + + + + + + + + + + + + + + + + + + +

接口

+

说明

+

checkNewVersion

+

检查是否有可用的升级包版本

+

download()

+

下载升级包

+

upgrade()

+

将升级命令写入到misc分区,最终调用reboot命令,进入到updater 子系统中。

+

getNewVersionInfo()

+

升级完成后,获取升级后的版本信息

+

setUpdatePolicy

+

设置升级策略

+

getUpdatePolicy

+

获取升级策略

+
+ +### 使用说明 + +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.setUpdatePolicy(result => { + result "设置升级策略结果" +}); +``` + +8,查看升级策略 + +``` +updater.getUpdatePolicy(policy => { + policy "升级策略" +}); +``` + +## 相关仓 + +升级子系统 + +update\_app + +**update\_updateservice** + +update\_updater + diff --git a/callback/include/update_callback.h b/callback/include/update_callback.h new file mode 100755 index 0000000..64e16ec --- /dev/null +++ b/callback/include/update_callback.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UPDATER_CALLBACK_H +#define UPDATER_CALLBACK_H + +#include "if_system_ability_manager.h" +#include "ipc_skeleton.h" +#include "iremote_stub.h" +#include "iupdate_callback.h" +#include "update_callback_stub.h" +#include "update_helper.h" +#include "system_ability.h" + +namespace OHOS { +namespace update_engine { +class UpdateCallback : public UpdateCallbackStub { +public: + explicit UpdateCallback() = default; + + ~UpdateCallback() = default; + + void OnCheckVersionDone(const VersionInfo &info) override; + + void OnDownloadProgress(const Progress &progress) override; + + void OnUpgradeProgress(const Progress &progress) override; +}; +} +} // namespace OHOS +#endif // UPDATER_CALLBACK_H \ No newline at end of file diff --git a/callback/include/update_callback_proxy.h b/callback/include/update_callback_proxy.h new file mode 100755 index 0000000..2dda345 --- /dev/null +++ b/callback/include/update_callback_proxy.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UPDATER_CALLBACK_PROXY_H +#define UPDATER_CALLBACK_PROXY_H + +#include "iremote_proxy.h" +#include "iupdate_service.h" + +namespace OHOS { +namespace update_engine { +class UpdateCallbackProxy : public IRemoteProxy { +public: + explicit UpdateCallbackProxy(const sptr& impl) : IRemoteProxy(impl) {} + + virtual ~UpdateCallbackProxy() = default; + + void OnCheckVersionDone(const VersionInfo &info) override; + + void OnDownloadProgress(const Progress &progress) override; + + void OnUpgradeProgress(const Progress &progress) override; + +private: + static inline BrokerDelegator delegator_; +}; +} +} // namespace OHOS +#endif // UPDATER_CALLBACK_PROXY_H \ No newline at end of file diff --git a/callback/include/update_callback_stub.h b/callback/include/update_callback_stub.h new file mode 100755 index 0000000..33d4ece --- /dev/null +++ b/callback/include/update_callback_stub.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UPDATE_CALLBACK_STUB_H_ +#define UPDATE_CALLBACK_STUB_H_ + +#include "iremote_stub.h" +#include "iupdate_callback.h" +#include "message_parcel.h" +#include "parcel.h" + +namespace OHOS { +namespace update_engine { +class UpdateCallbackStub : public IRemoteStub { +public: + int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, + MessageOption &option) override; +}; +} +} +#endif // !defined(UPDATE_CALLBACK_STUB_H_) diff --git a/callback/src/update_callback.cpp b/callback/src/update_callback.cpp new file mode 100755 index 0000000..478b44b --- /dev/null +++ b/callback/src/update_callback.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "update_callback.h" +#include +#include +#include +#include +#include +#include +#include "iservice_registry.h" +#include "parameters.h" +#include "securec.h" +#include "system_ability_definition.h" +#include "update_helper.h" + +namespace OHOS { +namespace update_engine { +void UpdateCallback::OnCheckVersionDone(const VersionInfo &info) +{ + ENGINE_LOGI("OnCheckVersionDone VersionInfo status %d", info.status); + ENGINE_LOGI("OnCheckVersionDone VersionInfo errMsg %s", info.errMsg.c_str()); + ENGINE_LOGI("OnCheckVersionDone VersionInfo versionName : %s", info.result[0].versionName.c_str()); + ENGINE_LOGI("OnCheckVersionDone VersionInfo versionCode : %s", info.result[0].versionCode.c_str()); + ENGINE_LOGI("OnCheckVersionDone VersionInfo verifyInfo : %s", info.result[0].verifyInfo.c_str()); + ENGINE_LOGI("OnCheckVersionDone VersionInfo size : %zu", info.result[0].size); +} + +void UpdateCallback::OnDownloadProgress(const Progress &progress) +{ + ENGINE_LOGI("OnDownloadProgress progress %u %d", progress.percent, progress.status); +} + +void UpdateCallback::OnUpgradeProgress(const Progress &progress) +{ + ENGINE_LOGI("OnUpgradeProgress progress %u %d", progress.percent, progress.status); +} +} +} // namespace OHOS diff --git a/callback/src/update_callback_proxy.cpp b/callback/src/update_callback_proxy.cpp new file mode 100755 index 0000000..9fd6f01 --- /dev/null +++ b/callback/src/update_callback_proxy.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "update_callback_proxy.h" +#include "securec.h" +#include "update_helper.h" + +namespace OHOS { +namespace update_engine { +void UpdateCallbackProxy::OnCheckVersionDone(const VersionInfo &info) +{ + ENGINE_LOGI("UpdateCallbackProxy::OnCheckVersionDone"); + MessageParcel data; + MessageParcel reply; + MessageOption option { MessageOption::TF_SYNC }; + + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return, "Can not get remote"); + + int32_t result = UpdateHelper::WriteVersionInfo(data, info); + ENGINE_CHECK(result == 0, return, "Can not WriteVersionInfo"); + + result = remote->SendRequest(CHECK_VERSION, data, reply, option); + ENGINE_CHECK(result == ERR_OK, return, "Can not SendRequest"); + return; +} + +void UpdateCallbackProxy::OnDownloadProgress(const Progress &progress) +{ + ENGINE_LOGI("UpdateCallbackProxy::OnDownloadProgress"); + MessageParcel data; + MessageParcel reply; + MessageOption option { MessageOption::TF_SYNC }; + + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return, "Can not get remote"); + + int32_t result = UpdateHelper::WriteUpdateProgress(data, progress); + ENGINE_CHECK(result == 0, return, "Can not WriteUpdateProgress"); + + result = remote->SendRequest(DOWNLOAD, data, reply, option); + ENGINE_CHECK(result == ERR_OK, return, "Can not SendRequest %d", result); + return; +} + +void UpdateCallbackProxy::OnUpgradeProgress(const Progress &progress) +{ + ENGINE_LOGI("UpdateCallbackProxy::OnUpgradeProgress"); + MessageParcel data; + MessageParcel reply; + MessageOption option { MessageOption::TF_SYNC }; + + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return, "Can not get remote"); + + int32_t result = UpdateHelper::WriteUpdateProgress(data, progress); + ENGINE_CHECK(result == 0, return, "Can not WriteUpdateProgress"); + + result = remote->SendRequest(UPGRADE, data, reply, option); + ENGINE_CHECK(result == ERR_OK, return, "Can not SendRequest"); + return; +} +} +} // namespace OHOS diff --git a/callback/src/update_callback_stub.cpp b/callback/src/update_callback_stub.cpp new file mode 100644 index 0000000..844e7df --- /dev/null +++ b/callback/src/update_callback_stub.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "update_callback_stub.h" +#include "securec.h" +#include "update_helper.h" + +using namespace std; + +namespace OHOS { +namespace update_engine { +int32_t UpdateCallbackStub::OnRemoteRequest(uint32_t code, + MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ + switch (code) { + case CHECK_VERSION: { + VersionInfo info; + UpdateHelper::ReadVersionInfo(data, info); + OnCheckVersionDone(info); + break; + } + case DOWNLOAD: { + Progress info; + UpdateHelper::ReadUpdateProgress(data, info); + OnDownloadProgress(info); + break; + } + case UPGRADE: { + Progress info; + UpdateHelper::ReadUpdateProgress(data, info); + OnUpgradeProgress(info); + break; + } + default: { + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); + } + } + return 0; +} +} +} diff --git a/client/BUILD.gn b/client/BUILD.gn new file mode 100755 index 0000000..5c44c0a --- /dev/null +++ b/client/BUILD.gn @@ -0,0 +1,65 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") + +ohos_shared_library("update") { + sources = [ + "//base/update/updateservice/client/update_client.cpp", + "//base/update/updateservice/client/update_module.cpp", + "//base/update/updateservice/client/update_session.cpp", + ] + + include_dirs = [ + "//base/update/updater/interfaces/kits/include", + "//base/update/updater/services/include", + "//base/update/updater/utils/include", + "//third_party/node/src", + "//foundation/ace/napi/interfaces/kits", + "//utils/native/base/include", + "//utils/system/safwk/native/include", + "//base/update/updateservice/interfaces/innerkits/include", + "//base/update/updateservice/client", + "//base/startup/syspara_lite/adapter/native/syspara/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/distributedschedule/safwk/services/safwk/include", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + ] + + deps = [ + "//base/update/updater/interfaces/kits/misc_info:libmiscinfo", + "//base/update/updater/interfaces/kits/packages:libpackageExt", + "//base/update/updater/services/log:libupdaterlog", + "//base/update/updater/utils:libutils", + "//base/update/updateservice/interfaces/innerkits/engine:updateservicekits", + "//foundation/ace/napi:ace_napi", + "//third_party/bounds_checking_function:libsec_static", + "//third_party/openssl:crypto_source", + "//third_party/openssl:ssl_source", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_L2:samgr_proxy", + "startup_l2:syspara", + ] + + install_enable = true + relative_install_dir = "module" + part_name = "updater" +} diff --git a/client/update_client.cpp b/client/update_client.cpp new file mode 100644 index 0000000..a8390c8 --- /dev/null +++ b/client/update_client.cpp @@ -0,0 +1,910 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "update_client.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "iupdate_service.h" +#include "misc_info/misc_info.h" +#include "node_api.h" +#include "node_api_types.h" +#include "package/package.h" +#include "securec.h" +#include "update_helper.h" +#include "update_service_kits.h" +#include "update_session.h" + +using namespace std; +using namespace OHOS::update_engine; + +namespace updateClient { +const int32_t MAX_ARGC = 3; +const int32_t DEVICE_ID_INDEX = 1; +const int32_t MID_ARGC = 2; +const int32_t CLIENT_STRING_MAX_LENGTH = 200; +constexpr int PROGRESS_DOWNLOAD_FINISH = 100; +const std::string MISC_FILE = "/dev/block/platform/soc/10100000.himci.eMMC/by-name/misc"; +const std::string UPDATER_PKG_NAME = "/data/updater/updater.zip"; + +UpdateClient::UpdateClient(napi_env env, napi_value thisVar) +{ + thisReference_ = nullptr; + env_ = env; + napi_create_reference(env, thisVar, 1, &thisReference_); + context_.type = "OTA"; + context_.upgradeDevId = "local"; + context_.controlDevId = "local"; + context_.upgradeApp = "updateclient"; + context_.upgradeFile = UPDATER_PKG_NAME; +} + +UpdateClient::~UpdateClient() +{ + sessions_.clear(); + if (thisReference_ != nullptr) { + napi_delete_reference(env_, thisReference_); + } +} + +UpdateSession *UpdateClient::RemoveSession(uint32_t sessionId) +{ + CLIENT_LOGI("RemoveSession sess"); + std::lock_guard guard(sessionMutex_); + UpdateSession *sess = nullptr; + auto iter = sessions_.find(sessionId); + if (iter != sessions_.end()) { + sess = iter->second.get(); + sessions_.erase(iter); + } + return sess; +} + +void UpdateClient::AddSession(std::shared_ptr session) +{ + CLIENT_CHECK(session != nullptr, return, "Invalid param"); + std::lock_guard guard(sessionMutex_); + sessions_.insert(make_pair(session->GetSessionId(), session)); +} + +napi_value UpdateClient::GetUpdaterForOther(napi_env env, napi_callback_info info) +{ + size_t argc = MAX_ARGC; + napi_value args[MAX_ARGC] = {0}; + napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info"); + CLIENT_CHECK_NAPI_CALL(env, argc >= MID_ARGC, return nullptr, "Invalid param"); + + // Get the devid. + int ret = GetStringValue(env, args[1], context_.upgradeDevId); + CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Error get type"); + return GetUpdater(env, info, DEVICE_ID_INDEX + 1); +} + +napi_value UpdateClient::GetUpdaterFromOther(napi_env env, napi_callback_info info) +{ + size_t argc = MAX_ARGC; + napi_value args[MAX_ARGC] = {0}; + napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info"); + CLIENT_CHECK_NAPI_CALL(env, argc >= MID_ARGC, return nullptr, "Invalid param"); + + // Get the devid. + int ret = GetStringValue(env, args[1], context_.controlDevId); + CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Error get type"); + return GetUpdater(env, info, DEVICE_ID_INDEX + 1); +} + +bool UpdateClient::CheckUpgradeType(const std::string &type) +{ + std::vector upgradeTypes = { + "ota", "patch" + }; + std::string upgradeType = type; + upgradeType.erase(0, upgradeType.find_first_not_of(" ")); + upgradeType.erase(upgradeType.find_last_not_of(" ") + 1); + std::transform(upgradeType.begin(), upgradeType.end(), upgradeType.begin(), ::tolower); + for (auto inter = upgradeTypes.cbegin(); inter != upgradeTypes.cend(); inter++) { + if ((*inter).compare(upgradeType) == 0) { + return true; + } + } + return false; +} + +bool UpdateClient::CheckUpgradeFile(const std::string &upgradeFile) +{ + if (upgradeFile.empty()) { + return false; + } + std::string file = upgradeFile; + file.erase(0, file.find_first_not_of(" ")); + file.erase(file.find_last_not_of(" ") + 1); + int32_t pos = file.find_first_of('/'); + if (pos != 0) { + return false; + } + pos = file.find_last_of('.'); + if (pos < 0) { + return false; + } + std::string postfix = file.substr(pos + 1, -1); + std::transform(postfix.begin(), postfix.end(), postfix.begin(), ::tolower); + if (postfix.compare("bin") == 0) { + return true; + } else if (postfix.compare("zip") == 0) { + return true; + } else if (postfix.compare("lz4") == 0) { + return true; + } else if (postfix.compare("gz") == 0) { + return true; + } + return false; +} + +napi_value UpdateClient::GetUpdater(napi_env env, napi_callback_info info, int32_t typeIndex) +{ + napi_value result; + napi_create_int32(env, 0, &result); + size_t argc = MAX_ARGC; + napi_value args[MAX_ARGC] = {0}; + napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info"); + CLIENT_CHECK_NAPI_CALL(env, argc >= 1, return nullptr, "Invalid param"); + CLIENT_CHECK_NAPI_CALL(env, !isInit, return nullptr, "Has beed init"); + + int ret = GetStringValue(env, args[0], context_.upgradeFile); + CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok && CheckUpgradeFile(context_.upgradeFile), + return nullptr, "Invalid upgradeFile"); + ret = GetStringValue(env, args[typeIndex], context_.type); + if (ret == napi_ok) { + CLIENT_CHECK_NAPI_CALL(env, CheckUpgradeType(context_.type), return nullptr, "Error get upgradeType"); + } else { + context_.type = "OTA"; + } + CLIENT_LOGE("GetUpdater argc %s", context_.type.c_str()); + UpdateCallbackInfo callback { + [&](const VersionInfo &info) { + this->NotifyCheckVersionDone(info); + }, + [&](const Progress &info) { + this->NotifyDownloadProgress(info); + }, + [&](const Progress &info) { + this->NotifyUpgradeProgresss(info); + }, + }; + UpdateServiceKits::GetInstance().RegisterUpdateCallback(context_, callback); + isInit = true; + return nullptr; +} + +napi_value UpdateClient::StartSession(napi_env env, + napi_callback_info info, int32_t type, size_t callbackStartIndex, DoWorkFunction function) +{ + size_t argc = MAX_ARGC; + napi_value args[MAX_ARGC] = {0}; + napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info"); + + CLIENT_LOGE("StartSession type %d argc %zu callbackStartIndex %d", type, argc, callbackStartIndex); + std::shared_ptr sess = nullptr; + if (argc > callbackStartIndex) { + sess = std::make_shared(this, type, argc, 1); + } else { + sess = std::make_shared(this, type, argc, 0); + } + CLIENT_CHECK_NAPI_CALL(env, sess != nullptr, return nullptr, "Failed to create update session"); + AddSession(sess); + napi_value retValue = sess->StartWork(env, callbackStartIndex, args, function, nullptr); + CLIENT_CHECK(retValue != nullptr, RemoveSession(sess->GetSessionId()); return nullptr, "Failed to start worker."); + + return retValue; +} + +napi_value UpdateClient::CheckNewVersion(napi_env env, napi_callback_info info) +{ + versionInfo_.status = SYSTEM_ERROR; + napi_value ret = StartSession(env, info, SESSION_CHECK_VERSION, 0, + [&](int32_t type, void *context) -> int { + return UpdateServiceKits::GetInstance().CheckNewVersion(); + }); + CLIENT_CHECK(ret != nullptr, return nullptr, "Failed to start worker."); + return ret; +} + +napi_value UpdateClient::CancelUpgrade(napi_env env, napi_callback_info info) +{ + size_t argc = MAX_ARGC; + napi_value args[MAX_ARGC] = {0}; + napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info"); + CLIENT_LOGE("CancelUpgrade"); + std::shared_ptr sess = nullptr; + sess = std::make_shared(this, SESSION_CANCEL_UPGRADE, argc, 0); + CLIENT_CHECK_NAPI_CALL(env, sess != nullptr, return nullptr, "Failed to create update session"); + AddSession(sess); + napi_value retValue = sess->StartWork(env, 0, args, + [&](int32_t type, void *context) -> int { + return UpdateServiceKits::GetInstance().Cancel(IUpdateService::DOWNLOAD); + }, nullptr); + CLIENT_CHECK(retValue != nullptr, RemoveSession(sess->GetSessionId()); return nullptr, "Failed to start worker."); + return retValue; +} + +napi_value UpdateClient::DownloadVersion(napi_env env, napi_callback_info info) +{ + size_t argc = MAX_ARGC; + napi_value args[MAX_ARGC] = {0}; + napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info"); + CLIENT_LOGE("DownloadVersion"); + std::shared_ptr sess = nullptr; + sess = std::make_shared(this, SESSION_DOWNLOAD, argc, 0); + CLIENT_CHECK_NAPI_CALL(env, sess != nullptr, return nullptr, "Failed to create update session"); + AddSession(sess); + napi_value retValue = sess->StartWork(env, 0, args, + [&](int32_t type, void *context) -> int { + return UpdateServiceKits::GetInstance().DownloadVersion(); + }, nullptr); + CLIENT_CHECK(retValue != nullptr, RemoveSession(sess->GetSessionId()); return nullptr, "Failed to start worker."); + return retValue; +} + +napi_value UpdateClient::UpgradeVersion(napi_env env, napi_callback_info info) +{ + size_t argc = MAX_ARGC; + napi_value args[MAX_ARGC] = {0}; + napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info"); + std::shared_ptr sess = nullptr; + sess = std::make_shared(this, SESSION_UPGRADE, argc, 0); + CLIENT_CHECK_NAPI_CALL(env, sess != nullptr, return nullptr, "Failed to create update session"); + AddSession(sess); + napi_value retValue = sess->StartWork(env, 0, args, + [&](int32_t type, void *context) -> int { +#ifndef UPDATER_API_TEST + return UpdateServiceKits::GetInstance().DoUpdate(); +#else + return 0; +#endif + }, nullptr); + CLIENT_CHECK(retValue != nullptr, RemoveSession(sess->GetSessionId()); return nullptr, "Failed to start worker."); + return retValue; +} + +napi_value UpdateClient::SetUpdatePolicy(napi_env env, napi_callback_info info) +{ + size_t argc = MAX_ARGC; + napi_value args[MAX_ARGC] = {0}; + napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info"); + + int ret = GetUpdatePolicyFromArg(env, args[0], updatePolicy_); + CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Failed to get policy para"); + + std::shared_ptr sess = nullptr; + if (argc >= MID_ARGC) { + sess = std::make_shared(this, SESSION_SET_POLICY, argc, 1); + } else { + sess = std::make_shared(this, SESSION_SET_POLICY, argc, 0); + } + CLIENT_CHECK_NAPI_CALL(env, sess != nullptr, return nullptr, "Failed to create update session"); + AddSession(sess); + napi_value retValue = sess->StartWork(env, 1, args, + [&](int32_t type, void *context) -> int { + result_ = UpdateServiceKits::GetInstance().SetUpdatePolicy(updatePolicy_); + return result_; + }, nullptr); + CLIENT_CHECK(retValue != nullptr, RemoveSession(sess->GetSessionId()); + return nullptr, "Failed to SetUpdatePolicy."); + return retValue; +} + +napi_value UpdateClient::GetUpdatePolicy(napi_env env, napi_callback_info info) +{ + napi_value retValue = StartSession(env, info, SESSION_GET_POLICY, 0, + [&](int32_t type, void *context) -> int { + return UpdateServiceKits::GetInstance().GetUpdatePolicy(updatePolicy_); + }); + CLIENT_CHECK(retValue != nullptr, return nullptr, "Failed to UpgradeVersion."); + return retValue; +} + +napi_value UpdateClient::GetNewVersionInfo(napi_env env, napi_callback_info info) +{ + napi_value retValue = StartSession(env, info, SESSION_GET_NEW_VERSION, 0, + [&](int32_t type, void *context) -> int { + return UpdateServiceKits::GetInstance().GetNewVersion(versionInfo_); + }); + CLIENT_CHECK(retValue != nullptr, return nullptr, "Failed to GetNewVersionInfo."); + return retValue; +} + +napi_value UpdateClient::GetUpgradeStatus(napi_env env, napi_callback_info info) +{ + napi_value retValue = StartSession(env, info, SESSION_GET_STATUS, 0, + [&](int32_t type, void *context) -> int { + return UpdateServiceKits::GetInstance().GetUpgradeStatus(upgradeInfo_); + }); + CLIENT_CHECK(retValue != nullptr, return nullptr, "Failed to GetUpgradeStatus."); + return retValue; +} + +napi_value UpdateClient::ApplyNewVersion(napi_env env, napi_callback_info info) +{ + napi_value retValue = StartSession(env, info, SESSION_APPLY_NEW_VERSION, 0, + [&](int32_t type, void *context) -> int { + result_ = UpdateServiceKits::GetInstance().RebootAndInstall(MISC_FILE, UPDATER_PKG_NAME); + return result_; + }); + CLIENT_CHECK(retValue != nullptr, return nullptr, "Failed to GetNewVersionInfo."); + return retValue; +} + +napi_value UpdateClient::RebootAndClean(napi_env env, napi_callback_info info) +{ + napi_value retValue = StartSession(env, info, SESSION_REBOOT_AND_CLEAN, 0, + [&](int32_t type, void *context) -> int { + result_ = UpdateServiceKits::GetInstance().RebootAndClean(MISC_FILE, UPDATER_PKG_NAME); + return result_; + }); + CLIENT_CHECK(retValue != nullptr, return nullptr, "Failed to GetNewVersionInfo."); + return retValue; +} + +napi_value UpdateClient::VerifyUpdatePackage(napi_env env, napi_callback_info info) +{ + size_t argc = MAX_ARGC; + napi_value args[MAX_ARGC] = {0}; + napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info"); + CLIENT_CHECK_NAPI_CALL(env, argc >= MID_ARGC, return nullptr, "Error get cb info"); + + int ret = GetStringValue(env, args[0], upgradeFile_); + CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Error get upgradeType"); + ret = GetStringValue(env, args[1], certsFile_); + CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Error get certsFile"); + + CLIENT_LOGE("VerifyUpdatePackage"); + std::shared_ptr sess = nullptr; + sess = std::make_shared(this, SESSION_VERIFY_PACKAGE, argc, 0); + CLIENT_CHECK_NAPI_CALL(env, sess != nullptr, return nullptr, "Fail to create update session"); + AddSession(sess); + size_t startIndex = 2; + napi_value retValue = sess->StartWork(env, startIndex, args, + [&](int32_t type, void *context) -> int { + CLIENT_LOGE("StartWork VerifyUpdatePackage"); + result_ = VerifyPackageWithCallback(upgradeFile_, certsFile_, + [&](int32_t result, uint32_t percent) { NotifyVerifyProgresss(result, percent); }); + return result_; + }, + nullptr); + CLIENT_CHECK(retValue != nullptr, RemoveSession(sess->GetSessionId()); return nullptr, "Failed to start worker."); + return retValue; +} + +napi_value UpdateClient::SubscribeEvent(napi_env env, napi_callback_info info) +{ + size_t argc = MAX_ARGC; + napi_value args[MAX_ARGC] = {0}; + napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info"); + // Two arguments are required: type + callback. + CLIENT_CHECK_NAPI_CALL(env, argc >= MID_ARGC, return nullptr, "Invalid param"); + + std::string eventType; + int ret = UpdateClient::GetStringValue(env, args[0], eventType); + CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Failed to get event type"); + CLIENT_CHECK(FindSessionByHandle(env, eventType, args[1]) == nullptr, return nullptr, "Handle has been sub"); + + std::shared_ptr sess = std::make_shared(this, SESSION_SUBSCRIBE, argc, 1, false); + CLIENT_CHECK_NAPI_CALL(env, sess != nullptr, return nullptr, "Failed to create listener"); + AddSession(sess); + napi_value retValue = sess->StartWork(env, 1, args, + [&](int32_t type, void *context) -> int { + return 0; + }, nullptr); + CLIENT_CHECK(retValue != nullptr, RemoveSession(sess->GetSessionId()); return nullptr, "Failed to SubscribeEvent."); + return retValue; +} + +napi_value UpdateClient::UnsubscribeEvent(napi_env env, napi_callback_info info) +{ + size_t argc = MAX_ARGC; + napi_value args[MAX_ARGC] = {0}; + napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get cb info"); + + std::string eventType; + int ret = UpdateClient::GetStringValue(env, args[0], eventType); + CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Failed to get event type"); + + CLIENT_LOGI("UnsubscribeEvent %s argc %d", eventType.c_str(), argc); + if (argc >= MID_ARGC) { + napi_valuetype valuetype; + napi_status status = napi_typeof(env, args[1], &valuetype); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to napi_typeof"); + CLIENT_CHECK_NAPI_CALL(env, valuetype == napi_function, return nullptr, "Invalid callback type"); + } + ret = ProcessUnsubscribe(eventType, argc, args[1]); + napi_value result; + napi_create_int32(env, ret, &result); + return result; +} + +int32_t UpdateClient::ProcessUnsubscribe(const std::string &eventType, size_t argc, napi_value arg) +{ + napi_handle_scope scope; + napi_status status = napi_open_handle_scope(env_, &scope); + CLIENT_CHECK(status == napi_ok, return -1, "Error open handle"); + + uint32_t nextSessId = 0; + bool hasNext = GetFirstSessionId(nextSessId); + while (hasNext) { + uint32_t currSessId = nextSessId; + auto iter = sessions_.find(currSessId); + if (iter == sessions_.end()) { + break; + } + hasNext = GetNextSessionId(nextSessId); + + UpdateListener *listener = static_cast(iter->second.get()); + if (listener->GetType() != SESSION_SUBSCRIBE + || eventType.compare(listener->GetEventType()) != 0) { + continue; + } + CLIENT_LOGI("ProcessUnsubscribe remove session"); + if (argc == 1) { + listener->RemoveHandlerRef(env_); + RemoveSession(currSessId); + } else if (listener->CheckEqual(env_, arg, eventType)) { + listener->RemoveHandlerRef(env_); + RemoveSession(currSessId); + break; + } + } + napi_close_handle_scope(env_, scope); + return 0; +} + +UpdateSession *UpdateClient::FindSessionByHandle(napi_env env, const std::string &eventType, napi_value arg) +{ + uint32_t nextSessId = 0; + bool hasNext = GetFirstSessionId(nextSessId); + while (hasNext) { + uint32_t currSessId = nextSessId; + auto iter = sessions_.find(currSessId); + if (iter == sessions_.end()) { + break; + } + hasNext = GetNextSessionId(nextSessId); + + UpdateListener *listener = static_cast(iter->second.get()); + if (listener->GetType() != SESSION_SUBSCRIBE) { + continue; + } + if ((eventType.compare(listener->GetEventType()) == 0) && listener->CheckEqual(env_, arg, eventType)) { + return listener; + } + } + return nullptr; +} + +bool UpdateClient::GetNextSessionId(uint32_t &sessionId) +{ + std::lock_guard guard(sessionMutex_); + { + auto iter = sessions_.find(sessionId); + if (iter == sessions_.end()) { + return false; + } + iter++; + if (iter == sessions_.end()) { + return false; + } + sessionId = iter->second->GetSessionId(); + } + return true; +} + +bool UpdateClient::GetFirstSessionId(uint32_t &sessionId) +{ + std::lock_guard guard(sessionMutex_); + { + if (sessions_.empty()) { + return false; + } + sessionId = sessions_.begin()->second->GetSessionId(); + return true; + } +} + +void UpdateClient::Emit(const std::string &type, int32_t retcode, const UpdateResult &result) +{ + napi_handle_scope scope; + napi_status status = napi_open_handle_scope(env_, &scope); + CLIENT_CHECK_NAPI_CALL(env_, status == napi_ok, return, "Error open_handle_scope"); + napi_value thisVar = nullptr; + status = napi_get_reference_value(env_, thisReference_, &thisVar); + CLIENT_CHECK_NAPI_CALL(env_, status == napi_ok, return, "Error get_reference"); + + uint32_t nextSessId = 0; + bool hasNext = GetFirstSessionId(nextSessId); + while (hasNext) { + uint32_t currSessId = nextSessId; + auto iter = sessions_.find(currSessId); + if (iter == sessions_.end()) { + break; + } + hasNext = GetNextSessionId(nextSessId); + UpdateListener *listener = static_cast((iter->second).get()); + if ((listener->GetType() != SESSION_SUBSCRIBE) || (type.compare(listener->GetEventType()) != 0)) { + continue; + } + listener->NotifyJS(env_, thisVar, retcode, result); + iter = sessions_.find(currSessId); + if (iter == sessions_.end()) { + continue; + } + listener = static_cast((iter->second).get()); + if (listener->IsOnce()) { + listener->RemoveHandlerRef(env_); + RemoveSession(currSessId); + } + } + napi_close_handle_scope(env_, scope); +} + +void UpdateClient::NotifyDownloadProgress(const Progress &progress) +{ + CLIENT_LOGI("NotifyDownloadProgress status %d %d", progress.status, progress.percent); + if (progress.percent == PROGRESS_DOWNLOAD_FINISH && progress.status == UPDATE_STATE_DOWNLOAD_ON) { + return; + } + progress_.percent = progress.percent; + progress_.status = progress.status; + progress_.endReason = progress.endReason; + UpdateResult result; + result.type = SESSION_DOWNLOAD; + result.result.progress = &progress_; + result.buildJSObject = BuildProgress; + int32_t fail = (progress_.status == UPDATE_STATE_DOWNLOAD_FAIL || progress_.status == UPDATE_STATE_VERIFY_FAIL) ? + progress_.status : 0; + Emit("downloadProgress", fail, result); +} + +void UpdateClient::NotifyUpgradeProgresss(const Progress &progress) +{ + CLIENT_LOGI("NotifyUpgradeProgresss status %d %d", progress.status, progress.percent); + progress_.percent = progress.percent; + progress_.status = progress.status; + + UpdateResult result; + result.type = SESSION_UPGRADE; + result.result.progress = &progress_; + result.buildJSObject = BuildProgress; + int32_t fail = (progress_.status == UPDATE_STATE_DOWNLOAD_FAIL) ? progress_.status : 0; + Emit("upgradeProgress", fail, result); +} + +void UpdateClient::NotifyVerifyProgresss(int32_t retCode, uint32_t percent) +{ + verifyProgress_.status = (retCode == 0) ? UPDATE_STATE_VERIFY_SUCCESS : UPDATE_STATE_VERIFY_FAIL; + verifyProgress_.percent = percent; + + UpdateResult result; + result.type = SESSION_VERIFY_PACKAGE; + result.result.progress = &verifyProgress_; + result.buildJSObject = BuildProgress; + Emit("verifyProgress", retCode, result); +} + +void UpdateClient::NotifyCheckVersionDone(const VersionInfo &info) +{ + CLIENT_LOGE("NotifyCheckVersionDone status %d", info.status); + CLIENT_LOGE("NotifyCheckVersionDone errMsg %s", info.errMsg.c_str()); + CLIENT_LOGE("NotifyCheckVersionDone versionName : %s", info.result[0].versionName.c_str()); + CLIENT_LOGE("NotifyCheckVersionDone versionCode : %s", info.result[0].versionCode.c_str()); + CLIENT_LOGE("NotifyCheckVersionDone verifyInfo : %s", info.result[0].verifyInfo.c_str()); + CLIENT_LOGE("NotifyCheckVersionDone size : %zu", info.result[0].size); + CLIENT_LOGE("NotifyCheckVersionDone content : %s", info.descriptInfo[0].content.c_str()); + + UpdateHelper::CopyVersionInfo(info, versionInfo_); +} + +int32_t UpdateClient::GetInt32(napi_env env, napi_value arg, const std::string &attrName, int32_t &intValue) +{ + bool result = false; + napi_status status = napi_has_named_property(env, arg, attrName.c_str(), &result); + if (result && (status == napi_ok)) { + napi_value value; + napi_get_named_property(env, arg, attrName.c_str(), &value); + napi_get_value_int32(env, value, &intValue); + } + return CLIENT_SUCCESS; +} + +int32_t UpdateClient::GetBool(napi_env env, napi_value arg, const std::string &attrName, bool &value) +{ + bool result = false; + napi_status status = napi_has_named_property(env, arg, attrName.c_str(), &result); + if (result && (status == napi_ok)) { + napi_value obj; + napi_get_named_property(env, arg, attrName.c_str(), &obj); + napi_get_value_bool(env, obj, &value); + } + return CLIENT_SUCCESS; +} + +int32_t UpdateClient::GetStringValue(napi_env env, napi_value arg, std::string &strValue) +{ + napi_valuetype valuetype; + napi_status status = napi_typeof(env, arg, &valuetype); + CLIENT_CHECK(status == napi_ok, return status, "Failed to napi_typeof"); + CLIENT_CHECK(valuetype == napi_string, return CLIENT_INVALID_TYPE, "Invalid type"); + std::vector buff(CLIENT_STRING_MAX_LENGTH); + size_t copied; + status = napi_get_value_string_utf8(env, arg, (char*)buff.data(), CLIENT_STRING_MAX_LENGTH, &copied); + CLIENT_CHECK(status == napi_ok, return CLIENT_INVALID_TYPE, "Error get string"); + strValue.assign(buff.data(), copied); + return napi_ok; +} + +int32_t UpdateClient::SetString(napi_env env, napi_value arg, const std::string &attrName, const std::string &string) +{ + napi_value value; + napi_create_string_utf8(env, string.c_str(), string.length(), &value); + napi_set_named_property(env, arg, attrName.c_str(), value); + return CLIENT_SUCCESS; +} + +int32_t UpdateClient::SetInt32(napi_env env, napi_value arg, const std::string &attrName, int32_t intValue) +{ + napi_value infoStatus; + napi_create_int32(env, intValue, &infoStatus); + napi_set_named_property(env, arg, attrName.c_str(), infoStatus); + return CLIENT_SUCCESS; +} + +int32_t UpdateClient::SetBool(napi_env env, napi_value arg, const std::string &attrName, bool value) +{ + napi_value infoStatus; + napi_create_int32(env, value, &infoStatus); + napi_set_named_property(env, arg, attrName.c_str(), infoStatus); + return CLIENT_SUCCESS; +} + +int32_t UpdateClient::SetInt64(napi_env env, napi_value arg, const std::string &attrName, int64_t intValue) +{ + napi_value infoStatus; + napi_create_int64(env, intValue, &infoStatus); + napi_set_named_property(env, arg, attrName.c_str(), infoStatus); + return CLIENT_SUCCESS; +} + +int32_t UpdateClient::GetUpdatePolicyFromArg(napi_env env, + const napi_value arg, UpdatePolicy &updatePolicy) const +{ + napi_valuetype type = napi_undefined; + napi_status status = napi_typeof(env, arg, &type); + CLIENT_CHECK(status == napi_ok, return CLIENT_INVALID_TYPE, "Invlid argc %d", static_cast(status)); + CLIENT_CHECK(type == napi_object, return CLIENT_INVALID_TYPE, "Invlid argc %d", static_cast(type)); + + // updatePolicy + int32_t tmpValue = 0; + int32_t ret = GetBool(env, arg, "autoDownload", updatePolicy.autoDownload); + ret |= GetBool(env, arg, "autoDownloadNet", updatePolicy.autoDownloadNet); + ret |= GetInt32(env, arg, "mode", tmpValue); + updatePolicy.mode = static_cast(tmpValue); + CLIENT_CHECK(ret == 0, return CLIENT_INVALID_TYPE, "Failed to get attr "); + + // Get the array. + bool result = false; + status = napi_has_named_property(env, arg, "autoUpgradeInterval", &result); + if (result && (status == napi_ok)) { + napi_value value; + status = napi_get_named_property(env, arg, "autoUpgradeInterval", &value); + CLIENT_CHECK(status == napi_ok, return CLIENT_FAIL, "Failed to get attr autoUpgradeInterval"); + status = napi_is_array(env, value, &result); + CLIENT_CHECK(status == napi_ok, return CLIENT_FAIL, "napi_is_array failed"); + uint32_t count = 0; + status = napi_get_array_length(env, value, &count); + CLIENT_CHECK(status == napi_ok, return CLIENT_FAIL, "napi_get_array_length failed"); + uint32_t i = 0; + do { + napi_value element; + ret = napi_get_element(env, value, i, &element); + ret = napi_get_value_uint32(env, element, &updatePolicy.autoUpgradeInterval[i]); + CLIENT_LOGI("updatePolicy autoUpgradeInterval:%u ", updatePolicy.autoUpgradeInterval[i]); + if (i >= sizeof(updatePolicy.autoUpgradeInterval) / sizeof(updatePolicy.autoUpgradeInterval[0])) { + break; + } + i++; + } while (i < count); + } + ret |= GetInt32(env, arg, "autoUpgradeCondition", tmpValue); + CLIENT_CHECK(ret == 0, return CLIENT_INVALID_TYPE, "Failed to get attr autoUpgradeCondition"); + updatePolicy.autoUpgradeCondition = static_cast(tmpValue); + CLIENT_LOGI("updatePolicy autoDownload:%d autoDownloadNet:%d mode:%d autoUpgradeCondition:%d", + static_cast(updatePolicy.autoDownload), + static_cast(updatePolicy.autoDownloadNet), + static_cast(updatePolicy.mode), + static_cast(updatePolicy.autoUpgradeCondition)); + return CLIENT_SUCCESS; +} + +int32_t UpdateClient::BuildCheckVersionResult(napi_env env, napi_value &obj, const UpdateResult &result) +{ + CLIENT_CHECK(result.type == SESSION_CHECK_VERSION || result.type == SESSION_GET_NEW_VERSION, + return CLIENT_INVALID_TYPE, "invalid type %d", result.type); + napi_status status = napi_create_object(env, &obj); + CLIENT_CHECK(status == napi_ok, return CLIENT_INVALID_TYPE, + "Failed to create napi_create_object %d", static_cast(status)); + VersionInfo *info = result.result.versionInfo; + + // Add the result. + int32_t ret = SetInt32(env, obj, "status", info->status); + if (info->status == SERVER_BUSY || info->status == SYSTEM_ERROR) { + ret = SetString(env, obj, "errMsg", info->errMsg); + return ret; + } + napi_value checkResults; + napi_create_array_with_length(env, sizeof(info->result) / sizeof(info->result[0]), &checkResults); + for (size_t i = 0; i < sizeof(info->result) / sizeof(info->result[0]); i++) { + napi_value result; + status = napi_create_object(env, &result); + + ret |= SetString(env, result, "versionName", info->result[i].versionName); + ret |= SetString(env, result, "versionCode", info->result[i].versionCode); + ret |= SetString(env, result, "verifyInfo", info->result[i].verifyInfo); + ret |= SetString(env, result, "descriptionId", info->result[i].descriptPackageId); + ret |= SetInt64(env, result, "size", info->result[i].size); + ret |= SetInt32(env, result, "packageType", info->result[i].packageType); + napi_set_element(env, checkResults, i, result); + } + napi_set_named_property(env, obj, "checkResults", checkResults); + + napi_value descriptInfos; + napi_create_array_with_length(env, sizeof(info->descriptInfo) / sizeof(info->descriptInfo[0]), &descriptInfos); + for (size_t i = 0; i < sizeof(info->descriptInfo) / sizeof(info->descriptInfo[0]); i++) { + napi_value descriptInfo; + status = napi_create_object(env, &descriptInfo); + ret |= SetString(env, descriptInfo, "descriptionId", info->descriptInfo[i].descriptPackageId); + ret |= SetString(env, descriptInfo, "content", info->descriptInfo[i].content); + napi_set_element(env, descriptInfos, i, descriptInfo); + } + napi_set_named_property(env, obj, "descriptionInfo", descriptInfos); + return CLIENT_SUCCESS; +} + +int32_t UpdateClient::BuildProgress(napi_env env, napi_value &obj, const UpdateResult &result) +{ + napi_status status = napi_create_object(env, &obj); + CLIENT_CHECK(status == napi_ok, return CLIENT_INVALID_TYPE, + "Failed to create napi_create_object %d", static_cast(status)); + int32_t ret = SetInt32(env, obj, "status", result.result.progress->status); + ret |= SetInt32(env, obj, "percent", result.result.progress->percent); + ret |= SetString(env, obj, "endReason", result.result.progress->endReason); + return CLIENT_SUCCESS; +} + +int32_t UpdateClient::BuildErrorResult(napi_env env, napi_value &obj, int32_t result) +{ + napi_status status = napi_create_object(env, &obj); + CLIENT_CHECK(status == napi_ok, return CLIENT_INVALID_TYPE, + "Failed to create napi_create_object %d", static_cast(status)); + return SetInt32(env, obj, "code", result); +} + +int32_t UpdateClient::BuildInt32Status(napi_env env, napi_value &obj, const UpdateResult &result) +{ + return napi_create_int32(env, result.result.status, &obj); +} + +int32_t UpdateClient::BuildUpdatePolicy(napi_env env, napi_value &obj, const UpdateResult &result) +{ + CLIENT_CHECK(result.type == SESSION_GET_POLICY || result.type == SESSION_SET_POLICY, + return CLIENT_INVALID_TYPE, "invalid type %d", result.type); + napi_status status = napi_create_object(env, &obj); + CLIENT_CHECK(status == napi_ok, return status, "Failed to create napi_create_object %d", status); + UpdatePolicy &updatePolicy = *result.result.updatePolicy; + + // Add the result. + int32_t ret = SetBool(env, obj, "autoDownload", updatePolicy.autoDownload); + ret |= SetBool(env, obj, "autoDownloadNet", updatePolicy.autoDownloadNet); + ret |= SetInt32(env, obj, "mode", static_cast(updatePolicy.mode)); + CLIENT_CHECK(ret == napi_ok, return ret, "Failed to add value %d", ret); + + napi_value autoUpgradeInterval; + size_t count = sizeof(updatePolicy.autoUpgradeInterval) / sizeof(updatePolicy.autoUpgradeInterval[0]); + status = napi_create_array_with_length(env, count, &autoUpgradeInterval); + CLIENT_CHECK(status == napi_ok, return status, "Failed to create array for interval %d", status); + for (size_t i = 0; i < count; i++) { + napi_value interval; + status = napi_create_uint32(env, updatePolicy.autoUpgradeInterval[i], &interval); + status = napi_set_element(env, autoUpgradeInterval, i, interval); + CLIENT_CHECK(status == napi_ok, return status, "Failed to add interval to array %d", status); + } + status = napi_set_named_property(env, obj, "autoUpgradeInterval", autoUpgradeInterval); + CLIENT_CHECK(status == napi_ok, return status, "Failed to add autoUpgradeInterval %d", status); + ret |= SetInt32(env, obj, "autoUpgradeCondition", static_cast(updatePolicy.autoUpgradeCondition)); + CLIENT_CHECK(ret == napi_ok, return ret, "Failed to add autoUpgradeCondition %d", ret); + return napi_ok; +} + +int32_t UpdateClient::GetUpdateResult(int type, UpdateResult &result, int32_t &fail) +{ + fail = 0; + result.type = type; + switch (type) { + case SESSION_CHECK_VERSION: + case SESSION_GET_NEW_VERSION: { + fail = (versionInfo_.status == SYSTEM_ERROR) ? versionInfo_.status : 0; + result.result.versionInfo = &versionInfo_; + result.buildJSObject = BuildCheckVersionResult; + break; + } + case SESSION_DOWNLOAD: { + fail = (progress_.status == UPDATE_STATE_DOWNLOAD_FAIL || progress_.status == UPDATE_STATE_VERIFY_FAIL) ? + progress_.status : 0; + result.result.progress = &progress_; + result.buildJSObject = BuildProgress; + break; + } + case SESSION_UPGRADE: { + fail = (progress_.status == UPDATE_STATE_DOWNLOAD_FAIL) ? progress_.status : 0; + result.result.progress = &progress_; + result.buildJSObject = BuildProgress; + break; + } + case SESSION_VERIFY_PACKAGE: { + fail = (verifyProgress_.status == UPDATE_STATE_VERIFY_FAIL) ? verifyProgress_.status : 0; + result.result.progress = &verifyProgress_; + result.buildJSObject = BuildProgress; + break; + } + case SESSION_GET_POLICY: { + result.result.updatePolicy = &updatePolicy_; + result.buildJSObject = BuildUpdatePolicy; + break; + } + case SESSION_GET_STATUS: { + result.result.status = upgradeInfo_.status; + result.buildJSObject = BuildInt32Status; + break; + } + default:{ + fail = result_; + result.result.status = result_; + result.buildJSObject = BuildInt32Status; + break; + } + } + return napi_ok; +} +} // namespace updateClient diff --git a/client/update_client.h b/client/update_client.h new file mode 100644 index 0000000..07abab0 --- /dev/null +++ b/client/update_client.h @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UPDATE_CLIENT_H +#define UPDATE_CLIENT_H + +#include +#include +#include +#include +#include +#include +#include + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "node_api.h" +#include "node_api_types.h" +#include "update_helper.h" +#include "update_service_kits.h" + +static constexpr OHOS::HiviewDFX::HiLogLabel UPDATE_CLIENT = {LOG_CORE, 0, "UPDATE_CLIENT"}; +#define CLIENT_LOGE(format, ...) \ + OHOS::update_engine::UpdateHelper::Logger(__FILE__, (__LINE__), format, ##__VA_ARGS__); \ + OHOS::HiviewDFX::HiLog::Error(UPDATE_CLIENT, "[%{public}s(%{public}d)] " format, \ + OHOS::update_engine::UpdateHelper::GetBriefFileName(std::string(__FILE__)).c_str(), __LINE__, ##__VA_ARGS__) + +#define CLIENT_LOGI(format, ...) \ + OHOS::update_engine::UpdateHelper::Logger(__FILE__, (__LINE__), format, ##__VA_ARGS__); \ + OHOS::HiviewDFX::HiLog::Info(UPDATE_CLIENT, "[%{public}s(%{public}d)] " format, \ + OHOS::update_engine::UpdateHelper::GetBriefFileName(std::string(__FILE__)).c_str(), __LINE__, ##__VA_ARGS__) + +#define CLIENT_CHECK(retCode, exper, ...) \ + if (!(retCode)) { \ + CLIENT_LOGE(__VA_ARGS__); \ + exper; \ + } + +#define CLIENT_CHECK_NAPI_CALL(env, assertion, exper, message) \ + if (!(assertion)) { \ + CLIENT_LOGE(message); \ + exper; \ + } + +namespace updateClient { +// Update status +enum ClientStatus { + CLIENT_SUCCESS = 0, + CLIENT_INVALID_PARAM = 1000, + CLIENT_INVALID_TYPE, + CLIENT_REPEAT_REQ, + CLIENT_FAIL, + CLIENT_CHECK_NEW_FIRST, +}; + +enum SessionType { + SESSION_CHECK_VERSION = 0, + SESSION_DOWNLOAD, + SESSION_UPGRADE, + SESSION_SET_POLICY, + SESSION_GET_POLICY, + SESSION_GET_NEW_VERSION, + SESSION_GET_STATUS, + SESSION_SUBSCRIBE, + SESSION_UNSUBSCRIBE, + SESSION_GET_UPDATER, + SESSION_APPLY_NEW_VERSION, + SESSION_REBOOT_AND_CLEAN, + SESSION_VERIFY_PACKAGE, + SESSION_CANCEL_UPGRADE, + SESSION_MAX +}; + +struct UpdateResult { + using BuildJSObject = std::function; + int32_t type; + union { + OHOS::update_engine::UpdatePolicy *updatePolicy; + OHOS::update_engine::Progress *progress; + OHOS::update_engine::VersionInfo *versionInfo; + int32_t status; + } result; + + BuildJSObject buildJSObject; +}; + + +class UpdateSession; +class UpdateClient { +public: + using DoWorkFunction = std::function; + + UpdateClient(napi_env env, napi_value thisVar); + ~UpdateClient(); + + // Obtain the updater engine and return it through the sync API. + napi_value GetUpdater(napi_env env, napi_callback_info info, int32_t index); + napi_value GetUpdaterForOther(napi_env env, napi_callback_info info); + napi_value GetUpdaterFromOther(napi_env env, napi_callback_info info); + + // Asynchronous API + napi_value CheckNewVersion(napi_env env, napi_callback_info info); + napi_value SetUpdatePolicy(napi_env env, napi_callback_info info); + napi_value GetUpdatePolicy(napi_env env, napi_callback_info info); + napi_value GetNewVersionInfo(napi_env env, napi_callback_info info); + napi_value GetUpgradeStatus(napi_env env, napi_callback_info info); + napi_value ApplyNewVersion(napi_env env, napi_callback_info info); + napi_value RebootAndClean(napi_env env, napi_callback_info info); + + // Event mode, which is used to send the result to the JS. + napi_value CancelUpgrade(napi_env env, napi_callback_info info); + napi_value DownloadVersion(napi_env env, napi_callback_info info); + napi_value UpgradeVersion(napi_env env, napi_callback_info info); + napi_value VerifyUpdatePackage(napi_env env, napi_callback_info info); + + // Subscription + napi_value SubscribeEvent(napi_env env, napi_callback_info info); + napi_value UnsubscribeEvent(napi_env env, napi_callback_info info); + + int32_t GetUpdateResult(int type, UpdateResult &result, int32_t &isFail); + + UpdateSession *RemoveSession(uint32_t sessionId); + void AddSession(std::shared_ptr session); + + void Emit(const std::string &type, int32_t retCode, const UpdateResult &result); + + static int32_t GetStringValue(napi_env env, napi_value arg, std::string &strValue); + static int32_t BuildErrorResult(napi_env env, napi_value &obj, int32_t result); + + // Notify the session. + void NotifyCheckVersionDone(const OHOS::update_engine::VersionInfo &info); + void NotifyDownloadProgress(const OHOS::update_engine::Progress &progress); + void NotifyUpgradeProgresss(const OHOS::update_engine::Progress &progress); + void NotifyVerifyProgresss(int32_t result, uint32_t percent); + + #ifdef UPDATER_UT + UpdateSession *GetUpdateSession(uint32_t sessId) + { + std::lock_guard guard(sessionMutex_); + auto iter = sessions_.find(sessId); + if (iter != sessions_.end()) { + return iter->second.get(); + } + return nullptr; + } + #endif +private: + napi_value StartSession(napi_env env, + napi_callback_info info, int32_t type, size_t startIndex, DoWorkFunction function); + int32_t GetNewVersion(bool isCheck); + bool GetNextSessionId(uint32_t &sessionId); + bool GetFirstSessionId(uint32_t &sessionId); + bool CheckUpgradeType(const std::string &type); + bool CheckUpgradeFile(const std::string &upgradeFile); + int32_t ProcessUnsubscribe(const std::string &eventType, size_t argc, napi_value arg); + UpdateSession *FindSessionByHandle(napi_env env, const std::string &eventType, napi_value arg); + + // Verify the version and parameters. + std::vector HexToDegist(const std::string &str) const; + bool VerifyDownloadPkg(); + std::vector SplitString(const std::string &str, const std::string &delimiter = ".") const; + int32_t CompareVersion(const std::string &version1, const std::string &version2) const; + + int32_t GetUpdatePolicyFromArg(napi_env env, + const napi_value arg, OHOS::update_engine::UpdatePolicy &updatePolicy) const; + + void GetEnginContext(OHOS::update_engine::UpdateContext &context) const; + void GetEnginPkgInfo(OHOS::update_engine::CheckResult &info) const; + + // Parse input parameters. + static int32_t GetInt32(napi_env env, napi_value arg, const std::string &attrName, int32_t &intValue); + static int32_t GetInt64(napi_env env, napi_value arg, const std::string &attrName, int64_t &intValue); + static int32_t GetBool(napi_env env, napi_value arg, const std::string &attrName, bool &value); + + static int32_t SetString(napi_env env, napi_value arg, const std::string &attrName, const std::string &string); + static int32_t SetInt32(napi_env env, napi_value arg, const std::string &attrName, int32_t intValue); + static int32_t SetInt64(napi_env env, napi_value arg, const std::string &attrName, int64_t intValue); + static int32_t SetBool(napi_env env, napi_value arg, const std::string &attrName, bool value); + + // Construct output parameters. + static int32_t BuildCheckVersionResult(napi_env env, napi_value &obj, const UpdateResult &result); + static int32_t BuildProgress(napi_env env, napi_value &obj, const UpdateResult &result); + static int32_t BuildUpdatePolicy(napi_env env, napi_value &obj, const UpdateResult &result); + static int32_t BuildInt32Status(napi_env env, napi_value &obj, const UpdateResult &result); +private: + napi_env env_ {}; + napi_ref thisReference_ {}; + std::map> sessions_ {}; + std::mutex sessionMutex_; + bool isInit = false; + int32_t result_ = 0; + std::string upgradeFile_; + std::string certsFile_; + OHOS::update_engine::UpdateContext context_ {}; + OHOS::update_engine::UpdatePolicy updatePolicy_ {}; + OHOS::update_engine::Progress progress_ {}; + OHOS::update_engine::Progress verifyProgress_ {}; + OHOS::update_engine::VersionInfo versionInfo_ {}; + OHOS::update_engine::UpgradeInfo upgradeInfo_ {}; +}; + +// Obtain the updater engine and return it through the synchronous API. +napi_value GetUpdater(napi_env env, napi_callback_info info); +napi_value GetUpdaterForOther(napi_env env, napi_callback_info info); +napi_value GetUpdaterFromOther(napi_env env, napi_callback_info info); + +// Asynchronous API +napi_value CheckNewVersion(napi_env env, napi_callback_info info); +napi_value SetUpdatePolicy(napi_env env, napi_callback_info info); +napi_value GetUpdatePolicy(napi_env env, napi_callback_info info); +napi_value GetNewVersionInfo(napi_env env, napi_callback_info info); +napi_value GetUpgradeStatus(napi_env env, napi_callback_info info); +napi_value ApplyNewVersion(napi_env env, napi_callback_info info); +napi_value RebootAndClean(napi_env env, napi_callback_info info); + +// Event mode, which is used to send the result to the JS. +napi_value CancelUpgrade(napi_env env, napi_callback_info info); +napi_value DownloadVersion(napi_env env, napi_callback_info info); +napi_value UpgradeVersion(napi_env env, napi_callback_info info); +napi_value VerifyUpdatePackage(napi_env env, napi_callback_info info); + +napi_value SubscribeEvent(napi_env env, napi_callback_info info); +napi_value UnsubscribeEvent(napi_env env, napi_callback_info info); + +#ifdef UPDATER_UT +napi_value UpdateClientInit(napi_env env, napi_value exports); +#endif +} // namespace updateClient +#endif // UPDATE_CLIENT_H \ No newline at end of file diff --git a/client/update_module.cpp b/client/update_module.cpp new file mode 100644 index 0000000..af302cc --- /dev/null +++ b/client/update_module.cpp @@ -0,0 +1,278 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "update_client.h" + +namespace updateClient { +const std::string CLASS_NAME = "UpdateClient"; +constexpr int32_t REF_COUNT = 20; +napi_ref g_reference = nullptr; + +napi_value UpdateClientJSConstructor(napi_env env, napi_callback_info info) +{ + // Count of argument is 1 + size_t argc = 1; + // Set second argument + napi_value args[1] = {0}; + napi_value thisVar = nullptr; + void* data = nullptr; + napi_get_cb_info(env, info, &argc, args, &thisVar, &data); + UpdateClient* client = new UpdateClient(env, thisVar); + napi_wrap(env, thisVar, client, + [](napi_env env, void* data, void* hint) { + CLIENT_LOGI("UpdateClient Destructor"); + UpdateClient* client = (UpdateClient*)data; + delete client; + client = nullptr; + }, + nullptr, nullptr); + return thisVar; +} + +UpdateClient *GetAndCreateJsUpdateClient(napi_env env, napi_callback_info info, napi_value &obj) +{ + napi_value constructor = nullptr; + UpdateClient *client = nullptr; + napi_status status = napi_get_reference_value(env, g_reference, &constructor); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get client"); + status = napi_new_instance(env, constructor, 0, nullptr, &obj); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Error get client"); + + napi_unwrap(env, obj, (void**)&client); + return client; +} + +UpdateClient *GetUpdateClient(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value argv[1] = {0}; + napi_value thisVar = nullptr; + void* data = nullptr; + napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); + + UpdateClient *client = nullptr; + napi_unwrap(env, thisVar, (void**)&client); + return client; +} + +napi_value GetUpdater(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + if (client != nullptr) { + return client->GetUpdater(env, info, 1); + } + napi_value obj = nullptr; + client = GetAndCreateJsUpdateClient(env, info, obj); + if (client != nullptr) { + napi_value result = client->GetUpdater(env, info, 1); + if (result != nullptr) { + return obj; + } + } + return obj; +} + +napi_value GetUpdaterForOther(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + if (client != nullptr) { + return client->GetUpdaterForOther(env, info); + } + napi_value obj = nullptr; + client = GetAndCreateJsUpdateClient(env, info, obj); + if (client != nullptr) { + client->GetUpdaterForOther(env, info); + } + return obj; +} + +napi_value GetUpdaterFromOther(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + if (client != nullptr) { + return client->GetUpdaterFromOther(env, info); + } + napi_value obj = nullptr; + client = GetAndCreateJsUpdateClient(env, info, obj); + if (client != nullptr) { + client->GetUpdaterFromOther(env, info); + } + return obj; +} + +napi_value CheckNewVersion(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + CLIENT_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client"); + return client->CheckNewVersion(env, info); +} + +napi_value SetUpdatePolicy(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + CLIENT_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client"); + return client->SetUpdatePolicy(env, info); +} + +napi_value GetUpdatePolicy(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + CLIENT_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client"); + return client->GetUpdatePolicy(env, info); +} + +napi_value DownloadVersion(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + CLIENT_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client"); + return client->DownloadVersion(env, info); +} + +napi_value CancelUpgrade(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + CLIENT_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client"); + return client->CancelUpgrade(env, info); +} + +napi_value UpgradeVersion(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + CLIENT_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client"); + return client->UpgradeVersion(env, info); +} + +napi_value GetNewVersionInfo(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + CLIENT_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client"); + return client->GetNewVersionInfo(env, info); +} + +napi_value GetUpgradeStatus(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + CLIENT_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client"); + return client->GetUpgradeStatus(env, info); +} + +napi_value UnsubscribeEvent(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + CLIENT_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client"); + return client->UnsubscribeEvent(env, info); +} + +napi_value SubscribeEvent(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + CLIENT_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client"); + return client->SubscribeEvent(env, info); +} + +napi_value ApplyNewVersion(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + CLIENT_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client"); + return client->ApplyNewVersion(env, info); +} + +napi_value RebootAndClean(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + CLIENT_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client"); + return client->RebootAndClean(env, info); +} + +napi_value VerifyUpdatePackage(napi_env env, napi_callback_info info) +{ + UpdateClient* client = GetUpdateClient(env, info); + CLIENT_CHECK_NAPI_CALL(env, client != nullptr, return nullptr, "Error get client"); + return client->VerifyUpdatePackage(env, info); +} + +#ifdef UPDATER_UT +napi_value UpdateClientInit(napi_env env, napi_value exports) +#else +static napi_value UpdateClientInit(napi_env env, napi_value exports) +#endif +{ + CLIENT_LOGI("UpdateClientInit"); + // Registration function + napi_property_descriptor desc[] = { + DECLARE_NAPI_FUNCTION("getUpdater", GetUpdater), + DECLARE_NAPI_FUNCTION("getUpdaterForOther", GetUpdaterForOther), + DECLARE_NAPI_FUNCTION("getUpdaterFromOther", GetUpdaterFromOther), + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + + // Registration object + napi_property_descriptor descriptors[] = { + DECLARE_NAPI_FUNCTION("getUpdater", GetUpdater), + DECLARE_NAPI_FUNCTION("getUpdaterForOther", GetUpdaterForOther), + DECLARE_NAPI_FUNCTION("getUpdaterFromOther", GetUpdaterFromOther), + + DECLARE_NAPI_FUNCTION("checkNewVersion", CheckNewVersion), + DECLARE_NAPI_FUNCTION("getNewVersionInfo", GetNewVersionInfo), + + DECLARE_NAPI_FUNCTION("setUpdatePolicy", SetUpdatePolicy), + DECLARE_NAPI_FUNCTION("getUpdatePolicy", GetUpdatePolicy), + DECLARE_NAPI_FUNCTION("getUpgradeStatus", GetUpgradeStatus), + + DECLARE_NAPI_FUNCTION("cancelUpgrade", CancelUpgrade), + DECLARE_NAPI_FUNCTION("download", DownloadVersion), + DECLARE_NAPI_FUNCTION("upgrade", UpgradeVersion), + + DECLARE_NAPI_FUNCTION("applyNewVersion", ApplyNewVersion), + DECLARE_NAPI_FUNCTION("rebootAndCleanUserData", RebootAndClean), + DECLARE_NAPI_FUNCTION("verifyUpdatePackage", VerifyUpdatePackage), + + DECLARE_NAPI_FUNCTION("on", SubscribeEvent), + DECLARE_NAPI_FUNCTION("off", UnsubscribeEvent) + }; + + napi_value result = nullptr; + napi_define_class(env, CLASS_NAME.c_str(), CLASS_NAME.size(), UpdateClientJSConstructor, + nullptr, sizeof(descriptors) / sizeof(*descriptors), descriptors, &result); + napi_set_named_property(env, exports, CLASS_NAME.c_str(), result); + napi_status status = napi_create_reference(env, result, REF_COUNT, &g_reference); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to create_reference"); + + return exports; +} + +/* + * Module definition + */ +static napi_module g_module = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = UpdateClientInit, + .nm_modname = "libupdate.z.so", + .nm_priv = ((void*)0), + .reserved = { 0 } +}; + +/* + * Module registration function + */ +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&g_module); +} +} diff --git a/client/update_session.cpp b/client/update_session.cpp new file mode 100644 index 0000000..e15b427 --- /dev/null +++ b/client/update_session.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "update_session.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "node_api.h" +#include "update_client.h" +#include "update_helper.h" +#include "package/package.h" +#include "securec.h" + +using namespace std; +using namespace OHOS::update_engine; + +namespace updateClient { +const int32_t RESULT_ARGC = 2; + +uint32_t g_sessionId = 0; +UpdateSession::UpdateSession(UpdateClient *client, int32_t type, size_t argc, size_t callbackNumber) + : sessionId(++g_sessionId), client_(client), type_(type), totalArgc_(argc), callbackNumber_(callbackNumber) {} + +int32_t UpdateSession::CreateReference(napi_env env, napi_value arg, uint32_t refcount, + napi_ref &reference) const +{ + napi_valuetype valuetype; + napi_status status = napi_typeof(env, arg, &valuetype); + CLIENT_CHECK(status == napi_ok, return status, "Failed to napi_typeof"); + CLIENT_CHECK(valuetype == napi_function, return status, "Invalid callback type"); + + status = napi_create_reference(env, arg, refcount, &reference); + CLIENT_CHECK(status == napi_ok, return status, "Failed to create reference"); + return status; +} + +napi_value UpdateSession::CreateWorkerName(napi_env env) const +{ + napi_value workName; + std::string name = "Async Work" + std::to_string(sessionId); + napi_status status = napi_create_string_utf8(env, name.c_str(), NAPI_AUTO_LENGTH, &workName); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to worker name"); + return workName; +} + +napi_value UpdateSession::StartWork(napi_env env, + size_t startIndex, const napi_value *args, UpdateClient::DoWorkFunction worker, void *context) +{ + static std::string sessName[SESSION_MAX] = { + "check version", "download", "upgrade", "set policy", "get policy", + "get new version", "get upgrade status", "subscribe", "unsubscribe", "get update", + "apply new version", "reboot and clean", "verify package", "Cancel Upgrade" + }; + + CLIENT_LOGI("StartWork type: %s", sessName[type_].c_str()); + doWorker_ = worker; + context_ = context; + return StartWork(env, startIndex, args); +} + +void UpdateSession::ExecuteWork(napi_env env) +{ + if (doWorker_ != nullptr) { +#ifndef UPDATER_UT + int32_t ret = doWorker_(type_, context_); + CLIENT_CHECK_NAPI_CALL(env, ret == 0, return, "execute work"); +#else + doWorker_(type_, context_); +#endif + } + return; +} + +napi_value UpdateAsyncession::StartWork(napi_env env, size_t startIndex, const napi_value *args) +{ + CLIENT_LOGI("UpdateAsyncession::StartWork startIndex: %zu", startIndex); + CLIENT_LOGI("UpdateAsyncession::totalArgc_ %zu callbackNumber_: %zu", totalArgc_, callbackNumber_); + CLIENT_CHECK_NAPI_CALL(env, args != nullptr && totalArgc_ >= startIndex, return nullptr, "Invalid para"); + napi_value workName = CreateWorkerName(env); + CLIENT_CHECK_NAPI_CALL(env, workName != nullptr, return nullptr, "Failed to worker name"); + + // Check whether a callback exists. Only one callback is allowed. + for (size_t i = 0; (i < (totalArgc_ - startIndex)) && (i < callbackNumber_); i++) { + CLIENT_LOGI("CreateReference index:%u", i + startIndex); + int32_t ret = CreateReference(env, args[i + startIndex], 1, callbackRef_[i]); + CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Failed to create reference"); + } + + // Create an asynchronous call. + napi_status status = napi_create_async_work(env, nullptr, workName, UpdateSession::ExecuteWork, + UpdateSession::CompleteWork, this, &(worker_)); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to create worker"); + + // Put the thread in the task execution queue. + status = napi_queue_async_work(env, worker_); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to queue worker"); + napi_value result; + napi_create_int32(env, 0, &result); + return result; +} + +void UpdateAsyncession::CompleteWork(napi_env env, napi_status status) +{ + CLIENT_LOGI("UpdateAsyncession::CompleteWork callbackNumber_: %d", static_cast(callbackNumber_)); + napi_value callback; + napi_value undefined; + napi_value callResult; + napi_get_undefined(env, &undefined); + napi_value retArgs[RESULT_ARGC] = { 0 }; + + UpdateResult result; + int32_t fail = 0; + client_->GetUpdateResult(type_, result, fail); + int ret = UpdateClient::BuildErrorResult(env, retArgs[0], fail); + ret |= result.buildJSObject(env, retArgs[1], result); + CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return, "Failed to build json"); + + status = napi_get_reference_value(env, callbackRef_[0], &callback); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return, "Failed to get reference"); + const int callBackNumber = 2; + status = napi_call_function(env, undefined, callback, callBackNumber, retArgs, &callResult); + // Release resources. + for (size_t i = 0; i < callbackNumber_; i++) { + napi_delete_reference(env, callbackRef_[i]); + callbackRef_[i] = nullptr; + } + napi_delete_async_work(env, worker_); + worker_ = nullptr; +} + +void UpdateAsyncessionNoCallback::CompleteWork(napi_env env, napi_status status) +{ + CLIENT_LOGI("UpdateAsyncessionNoCallback::CompleteWork callbackNumber_: %d", + static_cast(callbackNumber_)); +} + +napi_value UpdatePromiseSession::StartWork(napi_env env, size_t startIndex, const napi_value *args) +{ + CLIENT_LOGI("UpdatePromiseSession::StartWork"); + CLIENT_CHECK_NAPI_CALL(env, args != nullptr, return nullptr, "Invalid para"); + napi_value workName = CreateWorkerName(env); + CLIENT_CHECK_NAPI_CALL(env, workName != nullptr, return nullptr, "Failed to worker name"); + + napi_value promise; + napi_status status = napi_create_promise(env, &deferred_, &promise); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to napi_create_promise"); + + // Create an asynchronous call. + status = napi_create_async_work(env, nullptr, workName, UpdateSession::ExecuteWork, + UpdateSession::CompleteWork, this, &(worker_)); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to napi_create_async_work"); + // Put the thread in the task execution queue. + status = napi_queue_async_work(env, worker_); + CLIENT_CHECK_NAPI_CALL(env, status == napi_ok, return nullptr, "Failed to napi_queue_async_work"); + return promise; +} + +void UpdatePromiseSession::CompleteWork(napi_env env, napi_status status) +{ + CLIENT_LOGI("UpdatePromiseSession::CompleteWork status: %d", static_cast(status)); + // Get the return result. + napi_value processResult; + UpdateResult result; + int32_t fail = 0; + client_->GetUpdateResult(type_, result, fail); + if (fail == 0) { + result.buildJSObject(env, processResult, result); + napi_resolve_deferred(env, deferred_, processResult); + } else { + UpdateClient::BuildErrorResult(env, processResult, fail); + napi_reject_deferred(env, deferred_, processResult); + } + napi_delete_async_work(env, worker_); + worker_ = nullptr; +} + +napi_value UpdateListener::StartWork(napi_env env, size_t startIndex, const napi_value *args) +{ + CLIENT_LOGI("UpdateListener::StartWork"); + CLIENT_CHECK_NAPI_CALL(env, args != nullptr && totalArgc_ > startIndex, return nullptr, "Invalid para"); + int ret = UpdateClient::GetStringValue(env, args[0], eventType_); + CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Failed to get event type"); + + // reference count is 1 + ret = CreateReference(env, args[startIndex], 1, handlerRef_); + CLIENT_CHECK_NAPI_CALL(env, ret == napi_ok, return nullptr, "Failed to create reference"); + napi_value result; + napi_create_int32(env, 0, &result); + return result; +} + +void UpdateListener::NotifyJS(napi_env env, napi_value thisVar, int32_t retcode, const UpdateResult &result) const +{ + CLIENT_LOGI("NotifyJS retcode:%d", retcode); + napi_value jsEvent; + result.buildJSObject(env, jsEvent, result); + napi_value handler = nullptr; + napi_value callResult; + napi_get_reference_value(env, handlerRef_, &handler); + napi_call_function(env, thisVar, handler, 1, &jsEvent, &callResult); +} + +bool UpdateListener::CheckEqual(napi_env env, napi_value handler, const std::string &type) const +{ + bool isEquals = false; + napi_value handlerTemp = nullptr; + napi_get_reference_value(env, handlerRef_, &handlerTemp); + napi_strict_equals(env, handler, handlerTemp, &isEquals); + return isEquals && (type.compare(eventType_) == 0); +} +} // namespace updateClient diff --git a/client/update_session.h b/client/update_session.h new file mode 100644 index 0000000..99d92ec --- /dev/null +++ b/client/update_session.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UPDATE_SESSION_H +#define UPDATE_SESSION_H + +#include +#include +#include +#include +#include + +#include "iupdate_service.h" +#include "napi/native_api.h" +#include "napi/native_node_api.h" +#include "node_api.h" +#include "node_api_types.h" +#include "update_client.h" +#include "update_helper.h" + +namespace updateClient { +class UpdateSession { +public: + UpdateSession() = default; + + UpdateSession(UpdateClient *client, int32_t type, size_t argc, size_t callbackNumber); + + virtual ~UpdateSession() {}; + + napi_value StartWork(napi_env env, size_t startIndex, + const napi_value *args, UpdateClient::DoWorkFunction worker, void *context); + + UpdateClient* GetUpdateClient() const + { + return client_; + } + + int32_t GetType() const + { + return type_; + } + + uint32_t GetSessionId() const + { + return sessionId; + } + + virtual void CompleteWork(napi_env env, napi_status status) {} + virtual void ExecuteWork(napi_env env); + virtual napi_value StartWork(napi_env env, size_t startIndex, const napi_value *args) = 0; + virtual void NotifyJS(napi_env env, napi_value thisVar, int32_t retcode, const UpdateResult &result) const + { + return; + } + + // JS thread, which is used to notify the JS page upon completion of the operation. + static void CompleteWork(napi_env env, napi_status status, void *data) + { + auto sess = reinterpret_cast(data); + CLIENT_CHECK(sess != nullptr && sess->GetUpdateClient() != nullptr, return, "Session is null pointer"); + sess->CompleteWork(env, status); + // If the share ptr is used, you can directly remove the share ptr. + UpdateClient *client = sess->GetUpdateClient(); + if (client != nullptr) { + client->RemoveSession(sess->GetSessionId()); + } + } + + // The C++ thread executes the synchronization operation. After the synchronization is complete, + // the CompleteWork is called to notify the JS page of the completion of the operation. + static void ExecuteWork(napi_env env, void* data) + { + auto sess = reinterpret_cast(data); + CLIENT_CHECK(sess != nullptr, return, "sess is null"); + sess->ExecuteWork(env); + } +protected: + napi_value CreateWorkerName(napi_env env) const; + int32_t CreateReference(napi_env env, napi_value arg, uint32_t refcount, napi_ref &reference) const; + +protected: + uint32_t sessionId {0}; + UpdateClient *client_ = nullptr; + int32_t type_ {}; + size_t totalArgc_ = 0; + size_t callbackNumber_ = 0; + void* context_ {}; + UpdateClient::DoWorkFunction doWorker_ {}; +}; + +class UpdateAsyncession : public UpdateSession { +public: + UpdateAsyncession(UpdateClient *client, int32_t type, size_t argc, size_t callbackNumber) : + UpdateSession(client, type, argc, callbackNumber) + { + callbackRef_.resize(callbackNumber); + } + + ~UpdateAsyncession() override + { + callbackRef_.clear(); + } + + void CompleteWork(napi_env env, napi_status status) override; + napi_value StartWork(napi_env env, size_t startIndex, const napi_value *args) override; +private: + napi_async_work worker_ = nullptr; + std::vector callbackRef_ = {0}; +}; + +class UpdateAsyncessionNoCallback : public UpdateAsyncession { +public: + UpdateAsyncessionNoCallback(UpdateClient *client, int32_t type, size_t argc, size_t callbackNumber) : + UpdateAsyncession(client, type, argc, callbackNumber) {} + + ~UpdateAsyncessionNoCallback() override { } + + void CompleteWork(napi_env env, napi_status status) override; +}; + +class UpdatePromiseSession : public UpdateSession { +public: + UpdatePromiseSession(UpdateClient *client, int32_t type, size_t argc, size_t callbackNumber) : + UpdateSession(client, type, argc, callbackNumber) {} + + ~UpdatePromiseSession() override {} + + void CompleteWork(napi_env env, napi_status status) override; + napi_value StartWork(napi_env env, size_t startIndex, const napi_value *args) override; +private: + napi_async_work worker_ = nullptr; + napi_deferred deferred_ = nullptr; +}; + +class UpdateListener : public UpdateSession { +public: + UpdateListener(UpdateClient *client, int32_t type, size_t argc, size_t callbackNumber, bool isOnce) : + UpdateSession(client, type, argc, callbackNumber), isOnce_(isOnce) {} + + ~UpdateListener() override {} + + napi_value StartWork(napi_env env, size_t startIndex, const napi_value *args) override; + + void NotifyJS(napi_env env, napi_value thisVar, int32_t retcode, const UpdateResult &result) const override; + + bool IsOnce() const + { + return isOnce_; + } + + std::string GetEventType() const + { + return eventType_; + } + + bool CheckEqual(napi_env env, napi_value handler, const std::string &type) const; + + void RemoveHandlerRef(napi_env env) + { + napi_delete_reference(env, handlerRef_); + } +private: + bool isOnce_ = false; + std::string eventType_; + napi_ref handlerRef_ = nullptr; +}; +} // namespace updateClient +#endif // UPDATE_SESSION_H diff --git a/engine/BUILD.gn b/engine/BUILD.gn new file mode 100755 index 0000000..27e8ee5 --- /dev/null +++ b/engine/BUILD.gn @@ -0,0 +1,83 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") + +ohos_prebuilt_etc("updater_sa.rc") { + source = "etc/updater_sa.rc" + relative_install_dir = "init" + part_name = "updater" +} + +ohos_shared_library("updateservice") { + defines = [ + "DUAL_ADAPTER", + "UPDATE_SERVICE", + ] + sources = [ + "//base/update/updateservice/callback/src/update_callback.cpp", + "//base/update/updateservice/callback/src/update_callback_proxy.cpp", + "//base/update/updateservice/callback/src/update_callback_stub.cpp", + "//base/update/updateservice/engine/src/progress_thread.cpp", + "//base/update/updateservice/engine/src/update_helper.cpp", + "//base/update/updateservice/engine/src/update_service.cpp", + "//base/update/updateservice/engine/src/update_service_stub.cpp", + ] + + include_dirs = [ + "//base/update/updater/services/include", + "//base/update/updater/utils/include", + "//base/update/updater/interfaces/kits/include", + "//utils/native/base/include", + "//utils/system/safwk/native/include", + "//base/update/updateservice/interfaces/innerkits/include", + "//base/update/updateservice/engine/include", + "//base/update/updateservice/callback/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/distributedschedule/safwk/services/safwk/include", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//third_party/cJSON", + "//third_party/libxml2/include", + "//third_party/curl/include", + "//third_party/openssl/include", + "//third_party/bounds_checking_function/include", + ] + + deps = [ + "//base/startup/syspara_lite/interfaces/innerkits/native/syspara:syspara", + "//base/update/updater/interfaces/kits/misc_info:libmiscinfo", + "//base/update/updater/interfaces/kits/packages:libpackageExt", + "//base/update/updater/interfaces/kits/updaterkits:libupdaterkits", + "//base/update/updater/services/log:libupdaterlog", + "//base/update/updater/utils:libutils", + "//third_party/bounds_checking_function:libsec_static", + "//third_party/cJSON:cjson_static", + "//third_party/curl:curl", + "//third_party/libxml2:xml2", + "//third_party/openssl:crypto_source", + "//third_party/openssl:ssl_source", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_L2:samgr_proxy", + "startup_l2:syspara", + ] + + part_name = "updater" +} diff --git a/engine/etc/update_config.xml b/engine/etc/update_config.xml new file mode 100644 index 0000000..eb846d9 --- /dev/null +++ b/engine/etc/update_config.xml @@ -0,0 +1,17 @@ + + + + 127.0.0.1 + \ No newline at end of file diff --git a/engine/etc/updater_sa.rc b/engine/etc/updater_sa.rc new file mode 100755 index 0000000..af84314 --- /dev/null +++ b/engine/etc/updater_sa.rc @@ -0,0 +1,21 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +service updater_sa /system/bin/sa_main /system/profile/updater_sa.xml +class z_core +user system +group system shell +seclabel u:r:updater_sa:s0 + +on boot + start updater_sa + diff --git a/engine/include/progress_thread.h b/engine/include/progress_thread.h new file mode 100755 index 0000000..19d5e52 --- /dev/null +++ b/engine/include/progress_thread.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef UPDATER_THREAD_H +#define UPDATER_THREAD_H + +#include +#include +#include +#include +#include "cJSON.h" +#include "curl/curl.h" +#include "curl/easy.h" +#include "if_system_ability_manager.h" +#include "ipc_skeleton.h" +#include "iremote_stub.h" +#include "iupdate_service.h" +#include "openssl/err.h" +#include "openssl/ssl.h" +#include "system_ability.h" +#include "update_service_stub.h" + +#define ENGINE_CHECK_NO_LOG(retCode, exper) \ + if (!(retCode)) { \ + exper; \ + } + +namespace OHOS { +namespace update_engine { +constexpr uint32_t DOWNLOAD_FINISH_PERCENT = 100; +constexpr uint32_t DOWNLOAD_PERIOD_PERCENT = 5; +constexpr int32_t TIMEOUT_FOR_DOWNLOAD = 600; +#ifndef UPDATER_UT +constexpr int32_t TIMEOUT_FOR_CONNECT = 10; +#else +constexpr int32_t TIMEOUT_FOR_CONNECT = 1; +#endif + +class ProgressThread { +public: + ProgressThread() = default; + virtual ~ProgressThread() + { + StopProgress(); + } + +protected: + int32_t StartProgress(); + void StopProgress(); + void ExecuteThreadFunc(); + + virtual bool ProcessThreadExecute() = 0; + virtual void ProcessThreadExit() = 0; + +private: + std::thread *pDealThread_ { nullptr }; + std::mutex mutex_; + std::condition_variable condition_; + bool isWake_ = false; + bool isExitThread_ = false; +}; + +class DownloadThread : public ProgressThread { +public: + using ProgressCallback = std::function; + DownloadThread(ProgressCallback callback) : ProgressThread(), callback_(callback) {} + ~DownloadThread() override {} + + int32_t StartDownload(const std::string &fileName, const std::string &url); + void StopDownload(); + + static size_t GetLocalFileLength(const std::string &fileName); + static size_t WriteFunc(void *ptr, size_t size, size_t nmemb, const void *stream); + static int32_t DownloadProgress(const void *localData, + double dlTotal, double dlNow, double ulTotal, double ulNow); + + double GetPackageSize() + { + return static_cast(packageSize_); + }; +protected: + bool ProcessThreadExecute() override; + void ProcessThreadExit() override; + int32_t DownloadCallback(uint32_t percent, UpgradeStatus status, const std::string &error); + +private: + Progress downloadProgress_ {}; + ProgressCallback callback_; + CURL *downloadHandle_ { nullptr }; + FILE *downloadFile_ { nullptr }; + std::string serverUrl_; + std::atomic exitDownload_ { false }; + size_t packageSize_ { 1 }; + std::string downloadFileName_; +}; +} +} // namespace OHOS +#endif // UPDATER_THREAD_H \ No newline at end of file diff --git a/engine/include/update_service.h b/engine/include/update_service.h new file mode 100755 index 0000000..563b038 --- /dev/null +++ b/engine/include/update_service.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef UPDATER_SERVICE_H +#define UPDATER_SERVICE_H + +#include +#include +#include "cJSON.h" +#include "if_system_ability_manager.h" +#include "ipc_skeleton.h" +#include "iremote_stub.h" +#include "iupdate_service.h" +#include "openssl/err.h" +#include "openssl/ssl.h" +#include "progress_thread.h" +#include "system_ability.h" +#include "update_service_stub.h" + +namespace OHOS { +namespace update_engine { +class UpdateService : public SystemAbility, public UpdateServiceStub { +public: + DECLARE_SYSTEM_ABILITY(UpdateService); + DISALLOW_COPY_AND_MOVE(UpdateService); + explicit UpdateService(int32_t systemAbilityId, bool runOnCreate = true); + ~UpdateService() override; + + int32_t RegisterUpdateCallback(const UpdateContext &ctx, const sptr &updateCallback) override; + + int32_t UnregisterUpdateCallback() override; + + int32_t CheckNewVersion() override; + + int32_t DownloadVersion() override; + + int32_t DoUpdate() override; + + int32_t GetNewVersion(VersionInfo &versionInfo) override; + + int32_t GetUpgradeStatus (UpgradeInfo &info) override; + + int32_t SetUpdatePolicy(const UpdatePolicy &policy) override; + + int32_t GetUpdatePolicy(UpdatePolicy &policy) override; + + int32_t Cancel(int32_t service) override; + + int32_t RebootAndClean(const std::string &miscFile, const std::string &cmd) override; + + int32_t RebootAndInstall(const std::string &miscFile, const std::string &packageName) override; + static int32_t ParseJsonFile(const std::vector &buffer, VersionInfo &info); + static int32_t ReadCheckVersionResult(const cJSON* results, VersionInfo &info); + static int32_t ReadCheckVersiondescriptInfo(const cJSON *descriptInfo, VersionInfo &info); + static void GetServerIp(std::string &ip); +#ifndef UPDATER_UT +protected: +#else +public: +#endif + void OnStart() override; + void OnStop() override; +private: + void SearchCallback(const std::string &msg, SearchStatus status); + void DownloadCallback(const std::string &fileName, const Progress &progress); + void UpgradeCallback(const Progress &progress); + bool VerifyDownloadPkg(const std::string &pkgName, Progress &progress); + std::string GetDownloadServerUrl() const; + void InitVersionInfo(VersionInfo &versionInfo) const; +#ifndef UPDATER_UT +private: +#else +public: +#endif + void ReadDataFromSSL(int32_t engineSocket); +private: + std::string serverAddr_; + UpdatePolicy policy_ = { + 1, 1, INSTALLMODE_AUTO, AUTOUPGRADECONDITION_IDLE, { 10, 20 } + }; + UpgradeStatus upgradeStatus_ = UPDATE_STATE_INIT; + VersionInfo versionInfo_ {}; + + sptr updateCallback_ { nullptr }; + DownloadThread *downloadThread_ { nullptr }; + UpdateContext updateContext_ {}; +}; +} +} // namespace OHOS +#endif // UPDATER_SERVICE_H \ No newline at end of file diff --git a/engine/include/update_service_proxy.h b/engine/include/update_service_proxy.h new file mode 100755 index 0000000..35d97ca --- /dev/null +++ b/engine/include/update_service_proxy.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UPDATER_PROXY_H +#define UPDATER_PROXY_H + +#include "iremote_proxy.h" +#include "iupdate_service.h" + +namespace OHOS { +namespace update_engine { +class UpdateServiceProxy : public IRemoteProxy { +public: + explicit UpdateServiceProxy(const sptr& impl) : IRemoteProxy(impl) {} + + int32_t RegisterUpdateCallback(const UpdateContext &ctx, const sptr& updateCallback) override; + + int32_t UnregisterUpdateCallback() override; + + int32_t CheckNewVersion() override; + + int32_t DownloadVersion() override; + + int32_t DoUpdate() override; + + int32_t GetNewVersion(VersionInfo &versionInfo) override; + + int32_t GetUpgradeStatus (UpgradeInfo &info) override; + + int32_t SetUpdatePolicy(const UpdatePolicy &policy) override; + + int32_t GetUpdatePolicy(UpdatePolicy &policy) override; + + int32_t Cancel(int32_t service) override; + + int32_t RebootAndClean(const std::string &miscFile, const std::string &cmd) override; + + int32_t RebootAndInstall(const std::string &miscFile, const std::string &packageName) override; +private: + static inline BrokerDelegator delegator_; +}; +} +} // namespace OHOS +#endif // UPDATER_PROXY_H \ No newline at end of file diff --git a/engine/include/update_service_stub.h b/engine/include/update_service_stub.h new file mode 100755 index 0000000..3647888 --- /dev/null +++ b/engine/include/update_service_stub.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UPDATE_SERVICE_STUB_H_ +#define UPDATE_SERVICE_STUB_H_ + +#include +#include +#include +#include "iremote_stub.h" +#include "iupdate_service.h" +#include "message_parcel.h" +#include "parcel.h" + +namespace OHOS { +namespace update_engine { +class UpdateServiceStub : public IRemoteStub { +public: + int32_t OnRemoteRequest(uint32_t code, MessageParcel& data, MessageParcel& reply, + MessageOption &option) override; + + using UpdateServiceStubPtr = UpdateServiceStub *; + using RequestFuncType = std::function; +}; +} +} +#endif // UPDATE_SERVICE_STUB_H_ \ No newline at end of file diff --git a/engine/sa_profile/3006.xml b/engine/sa_profile/3006.xml new file mode 100755 index 0000000..68df2f0 --- /dev/null +++ b/engine/sa_profile/3006.xml @@ -0,0 +1,24 @@ + + + + updater_sa + + 3006 + libupdateservice.z.so + true + false + 1 + + diff --git a/engine/sa_profile/BUILD.gn b/engine/sa_profile/BUILD.gn new file mode 100755 index 0000000..ed848f6 --- /dev/null +++ b/engine/sa_profile/BUILD.gn @@ -0,0 +1,20 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos/sa_profile/sa_profile.gni") + +ohos_sa_profile("updater_sa_profile") { + sources = [ "3006.xml" ] + + part_name = "updater" +} diff --git a/engine/src/progress_thread.cpp b/engine/src/progress_thread.cpp new file mode 100755 index 0000000..316dce8 --- /dev/null +++ b/engine/src/progress_thread.cpp @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "progress_thread.h" +#include +#include "curl/curl.h" +#include "curl/easy.h" +#include "securec.h" +#include "update_helper.h" + +namespace OHOS { +namespace update_engine { +int32_t ProgressThread::StartProgress() +{ + if (pDealThread_ == nullptr) { + pDealThread_ = new (std::nothrow)std::thread(&ProgressThread::ExecuteThreadFunc, this); + ENGINE_CHECK(pDealThread_ != nullptr, return -1, "Failed to create thread"); + } + ENGINE_LOGI("StartProgress"); + std::unique_lock lock(mutex_); + isWake_ = true; + condition_.notify_one(); + return 0; +} + +void ProgressThread::StopProgress() +{ + { + std::unique_lock lock(mutex_); + isWake_ = true; + isExitThread_ = true; + condition_.notify_one(); + } + + if (pDealThread_ != nullptr) { + pDealThread_->join(); + delete pDealThread_; + pDealThread_ = nullptr; + } +} + +void ProgressThread::ExecuteThreadFunc() +{ + while (1) { + { + std::unique_lock lock(mutex_); + while (!isWake_) { + ENGINE_LOGI("ExecuteThreadFunc wait"); + condition_.wait(lock); + } + if (isExitThread_) { + break; + } + isWake_ = false; + } + bool isExit = ProcessThreadExecute(); + if (isExit) { + break; + } + } + // thread exit and release resource + ProcessThreadExit(); +} + +int32_t DownloadThread::StartDownload(const std::string &fileName, const std::string &url) +{ + downloadFileName_ = fileName; + serverUrl_ = url; + exitDownload_ = false; + curl_global_init(CURL_GLOBAL_ALL); + return StartProgress(); +} + +void DownloadThread::StopDownload() +{ + ENGINE_LOGI("StopDownload "); + exitDownload_ = true; + StopProgress(); + curl_global_cleanup(); +} + +bool DownloadThread::ProcessThreadExecute() +{ + packageSize_ = GetLocalFileLength(downloadFileName_); + ENGINE_LOGI("download packageSize_: %zu ", packageSize_); + + downloadFile_ = fopen(downloadFileName_.c_str(), "ab+"); + ENGINE_CHECK(downloadFile_ != nullptr, + DownloadCallback(0, UPDATE_STATE_DOWNLOAD_FAIL, "Failed ot open file"); + return true, "Failed to open file %s", downloadFileName_.c_str()); + + downloadHandle_ = curl_easy_init(); + ENGINE_CHECK(downloadHandle_ != nullptr, + ProcessThreadExit(); + DownloadCallback(0, UPDATE_STATE_DOWNLOAD_FAIL, "Failed to init curl"); + return true, "Failed to init curl"); + + curl_easy_setopt(downloadHandle_, CURLOPT_TIMEOUT, TIMEOUT_FOR_DOWNLOAD); + curl_easy_setopt(downloadHandle_, CURLOPT_CONNECTTIMEOUT, TIMEOUT_FOR_CONNECT); + curl_easy_setopt(downloadHandle_, CURLOPT_URL, serverUrl_.c_str()); + curl_easy_setopt(downloadHandle_, CURLOPT_WRITEDATA, downloadFile_); + curl_easy_setopt(downloadHandle_, CURLOPT_WRITEFUNCTION, WriteFunc); + if (packageSize_ > 0) { + curl_easy_setopt(downloadHandle_, CURLOPT_RESUME_FROM_LARGE, static_cast(packageSize_)); + } + curl_easy_setopt(downloadHandle_, CURLOPT_NOPROGRESS, 0L); + curl_easy_setopt(downloadHandle_, CURLOPT_PROGRESSDATA, this); + curl_easy_setopt(downloadHandle_, CURLOPT_PROGRESSFUNCTION, DownloadProgress); + CURLcode res = curl_easy_perform(downloadHandle_); + if (res != CURLE_OK) { + ProcessThreadExit(); + ENGINE_LOGI("Failed to download %s res %s", serverUrl_.c_str(), curl_easy_strerror(res)); + if (res != CURLE_ABORTED_BY_CALLBACK) { // cancel by user, do not callback + DownloadCallback(0, UPDATE_STATE_DOWNLOAD_FAIL, curl_easy_strerror(res)); + } + } else { + ProcessThreadExit(); + ENGINE_LOGI("Success to download %s", serverUrl_.c_str()); + DownloadCallback(DOWNLOAD_FINISH_PERCENT, UPDATE_STATE_DOWNLOAD_SUCCESS, ""); + } + // clear up + downloadProgress_.endReason = ""; + downloadProgress_.percent = 0; + downloadProgress_.status = UPDATE_STATE_DOWNLOAD_ON; + return false; +} + +void DownloadThread::ProcessThreadExit() +{ + ENGINE_LOGI("ProcessThreadExit"); + if (downloadHandle_ != nullptr) { + curl_easy_cleanup(downloadHandle_); + } + downloadHandle_ = nullptr; + if (downloadFile_ != nullptr) { + fclose(downloadFile_); + } + downloadFile_ = nullptr; +} + +int32_t DownloadThread::DownloadCallback(uint32_t percent, UpgradeStatus status, const std::string &error) +{ + if (exitDownload_) { + ENGINE_LOGI("StopDownlDownloadCallbackoad"); + return -1; + } + if (status == UPDATE_STATE_DOWNLOAD_FAIL) { + if (access(downloadFileName_.c_str(), 0) == 0) { + unlink(downloadFileName_.c_str()); + } + } else if (percent != DOWNLOAD_FINISH_PERCENT + && (percent < (downloadProgress_.percent + DOWNLOAD_PERIOD_PERCENT))) { + return 0; + } + + // wait until the download is complete, and then make a notification + if (percent == DOWNLOAD_FINISH_PERCENT + && status == UPDATE_STATE_DOWNLOAD_ON) { + return 0; + } + downloadProgress_.endReason = error; + downloadProgress_.percent = percent; + downloadProgress_.status = status; + if (callback_ != nullptr) { + callback_(downloadFileName_, downloadProgress_); + } + return 0; +} + +int32_t DownloadThread::DownloadProgress(const void *localData, + double dlTotal, double dlNow, double ulTotal, double ulNow) +{ + ENGINE_CHECK_NO_LOG(dlTotal > 0, return 0); + auto engine = reinterpret_cast(const_cast(localData)); + ENGINE_CHECK(engine != nullptr, return -1, "Can not find engine"); + double curr = engine->GetPackageSize(); + unsigned int percent = (dlNow + curr) / (curr + dlTotal) * DOWNLOAD_FINISH_PERCENT; + return engine->DownloadCallback(percent, UPDATE_STATE_DOWNLOAD_ON, ""); +} + +size_t DownloadThread::WriteFunc(void *ptr, size_t size, size_t nmemb, const void *stream) +{ + return fwrite(ptr, size, nmemb, reinterpret_cast(const_cast(stream))); +} + +size_t DownloadThread::GetLocalFileLength(const std::string &fileName) +{ + FILE* fp = fopen(fileName.c_str(), "r"); + ENGINE_CHECK_NO_LOG(fp != nullptr, return 0); + fseek(fp, 0, SEEK_END); + size_t length = ftell(fp); + fclose(fp); + return length; +} +} +} // namespace OHOS \ No newline at end of file diff --git a/engine/src/update_helper.cpp b/engine/src/update_helper.cpp new file mode 100755 index 0000000..9a2587a --- /dev/null +++ b/engine/src/update_helper.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "update_helper.h" + +#include +#include +#include +#include +#include + +#include "hilog/log.h" +#include "parcel.h" +#include "securec.h" + +namespace OHOS { +namespace update_engine { +#ifdef UPDATE_SERVICE +const std::string LOG_LABEL = "update_engine"; +const std::string LOG_NAME = "/data/update_service_log.txt"; +#else +const std::string LOG_LABEL = "update_engine"; +const std::string LOG_NAME = "/data/update_client.log.txt"; +#endif +constexpr int VECTOR_MAX_BUF_SIZE = 1024; +constexpr int MAX_TIME_SIZE = 20; +constexpr int HEX_DIGEST_NUM = 2; +constexpr int HEX_DIGEST_BASE = 16; + +UpdateLogLevel UpdateHelper::level_ = UpdateLogLevel::UPDATE_INFO; + +int32_t UpdateHelper::WriteUpdateContext(MessageParcel &data, const UpdateContext &info) +{ + data.WriteString16(Str8ToStr16(info.upgradeDevId)); + data.WriteString16(Str8ToStr16(info.controlDevId)); + data.WriteString16(Str8ToStr16(info.upgradeApp)); + data.WriteString16(Str8ToStr16(info.upgradeFile)); + data.WriteString16(Str8ToStr16(info.type)); + return 0; +} + +int32_t UpdateHelper::ReadUpdateContext(MessageParcel &reply, UpdateContext &info) +{ + info.upgradeDevId = Str16ToStr8(reply.ReadString16()); + info.controlDevId = Str16ToStr8(reply.ReadString16()); + info.upgradeApp = Str16ToStr8(reply.ReadString16()); + info.upgradeFile = Str16ToStr8(reply.ReadString16()); + info.type = Str16ToStr8(reply.ReadString16()); + return 0; +} + +int32_t UpdateHelper::WriteVersionInfo(MessageParcel &data, const VersionInfo &info) +{ + data.WriteInt32(static_cast(info.status)); + data.WriteString16(Str8ToStr16(info.errMsg)); + data.WriteInt32(static_cast(sizeof(info.result) / sizeof(info.result[0]))); + for (size_t i = 0; i < sizeof(info.result) / sizeof(info.result[0]); i++) { + data.WriteUint64(static_cast(info.result[i].size)); + data.WriteInt32(static_cast(info.result[i].packageType)); + + data.WriteString16(Str8ToStr16(info.result[i].versionName)); + data.WriteString16(Str8ToStr16(info.result[i].versionCode)); + data.WriteString16(Str8ToStr16(info.result[i].verifyInfo)); + data.WriteString16(Str8ToStr16(info.result[i].descriptPackageId)); + } + data.WriteInt32(static_cast(sizeof(info.descriptInfo) / sizeof(info.descriptInfo[0]))); + for (size_t i = 0; i < sizeof(info.descriptInfo) / sizeof(info.descriptInfo[0]); i++) { + data.WriteString16(Str8ToStr16(info.descriptInfo[i].descriptPackageId)); + data.WriteString16(Str8ToStr16(info.descriptInfo[i].content)); + } + return 0; +} + +int32_t UpdateHelper::ReadVersionInfo(MessageParcel &reply, VersionInfo &info) +{ + info.status = static_cast(reply.ReadInt32()); + info.errMsg = Str16ToStr8(reply.ReadString16()); + + int32_t count = reply.ReadInt32(); + for (size_t i = 0; (i < static_cast(count)) && (i < sizeof(info.result) / sizeof(info.result[0])); i++) { + uint64_t uint64 = reply.ReadUint64(); + info.result[i].size = static_cast(uint64); + info.result[i].packageType = static_cast(reply.ReadInt32()); + + info.result[i].versionName = Str16ToStr8(reply.ReadString16()); + info.result[i].versionCode = Str16ToStr8(reply.ReadString16()); + info.result[i].verifyInfo = Str16ToStr8(reply.ReadString16()); + info.result[i].descriptPackageId = Str16ToStr8(reply.ReadString16()); + } + count = reply.ReadInt32(); + for (size_t i = 0; (i < static_cast(count)) + && (i < sizeof(info.descriptInfo) / sizeof(info.descriptInfo[0])); i++) { + info.descriptInfo[i].descriptPackageId = Str16ToStr8(reply.ReadString16()); + info.descriptInfo[i].content = Str16ToStr8(reply.ReadString16()); + } + return 0; +} + +int32_t UpdateHelper::WriteUpdatePolicy(MessageParcel &data, const UpdatePolicy &policy) +{ + data.WriteBool(policy.autoDownload); + data.WriteBool(policy.autoDownloadNet); + data.WriteInt32(static_cast(policy.mode)); + data.WriteInt32(static_cast(policy.autoUpgradeCondition)); + data.WriteInt32(static_cast(sizeof(policy.autoUpgradeInterval) / sizeof(policy.autoUpgradeInterval[0]))); + for (size_t i = 0; i < sizeof(policy.autoUpgradeInterval) / sizeof(policy.autoUpgradeInterval[0]); i++) { + data.WriteUint32(policy.autoUpgradeInterval[i]); + } + return 0; +} + +int32_t UpdateHelper::ReadUpdatePolicy(MessageParcel &data, UpdatePolicy &policy) +{ + policy.autoDownload = static_cast(data.ReadBool()); + policy.autoDownloadNet = static_cast(data.ReadBool()); + policy.mode = static_cast(data.ReadInt32()); + policy.autoUpgradeCondition = static_cast(data.ReadInt32()); + int32_t count = data.ReadInt32(); + for (size_t i = 0; (i < static_cast(count)) && (i < + sizeof(policy.autoUpgradeInterval) / sizeof(policy.autoUpgradeInterval[0])); i++) { + policy.autoUpgradeInterval[i] = data.ReadUint32(); + } + return 0; +} + +int32_t UpdateHelper::ReadUpgradeInfo(MessageParcel &reply, UpgradeInfo &info) +{ + info.status = static_cast(reply.ReadInt32()); + return 0; +} + +int32_t UpdateHelper::WriteUpgradeInfo(MessageParcel &data, const UpgradeInfo &info) +{ + data.WriteInt32(info.status); + return 0; +} + +int32_t UpdateHelper::ReadUpdateProgress(MessageParcel &reply, Progress &info) +{ + info.percent = static_cast(reply.ReadUint32()); + info.status = static_cast(reply.ReadInt32()); + info.endReason = Str16ToStr8(reply.ReadString16()); + return 0; +} + +int32_t UpdateHelper::WriteUpdateProgress(MessageParcel &data, const Progress &info) +{ + data.WriteUint32(info.percent); + data.WriteInt32(static_cast(info.status)); + data.WriteString16(Str8ToStr16(info.endReason)); + return 0; +} + +int32_t UpdateHelper::CopyVersionInfo(const VersionInfo &srcInfo, VersionInfo &dstInfo) +{ + dstInfo.status = srcInfo.status; + dstInfo.errMsg = srcInfo.errMsg; + for (size_t i = 0; i < sizeof(dstInfo.result) / sizeof(dstInfo.result[0]); i++) { + dstInfo.result[i].size = srcInfo.result[i].size; + dstInfo.result[i].packageType = srcInfo.result[i].packageType; + dstInfo.result[i].versionName = srcInfo.result[i].versionName; + dstInfo.result[i].versionCode = srcInfo.result[i].versionCode; + dstInfo.result[i].verifyInfo = srcInfo.result[i].verifyInfo; + dstInfo.result[i].descriptPackageId = srcInfo.result[i].descriptPackageId; + } + for (size_t i = 0; i < sizeof(dstInfo.descriptInfo) / sizeof(dstInfo.descriptInfo[0]); i++) { + dstInfo.descriptInfo[i].content = srcInfo.descriptInfo[i].content; + dstInfo.descriptInfo[i].descriptPackageId = srcInfo.descriptInfo[i].descriptPackageId; + } + return 0; +} + +int32_t UpdateHelper::CopyUpdatePolicy(const UpdatePolicy &srcInfo, UpdatePolicy &dstInfo) +{ + dstInfo.autoDownload = srcInfo.autoDownload; + dstInfo.autoDownloadNet = srcInfo.autoDownloadNet; + dstInfo.mode = srcInfo.mode; + dstInfo.autoUpgradeCondition = srcInfo.autoUpgradeCondition; + for (size_t i = 0; i < sizeof(dstInfo.autoUpgradeInterval) / sizeof(dstInfo.autoUpgradeInterval[0]); i++) { + dstInfo.autoUpgradeInterval[i] = srcInfo.autoUpgradeInterval[i]; + } + return 0; +} + +void UpdateHelper::Logger(const std::string &fileName, int32_t line, const char *format, ...) +{ + std::string name = UpdateHelper::GetBriefFileName(fileName); + std::ofstream logStream(LOG_NAME, std::ios::app | std::ios::out); + static std::vector buff(VECTOR_MAX_BUF_SIZE); + va_list list; + va_start(list, format); + int size = vsnprintf_s(reinterpret_cast(buff.data()), buff.capacity(), buff.capacity(), format, list); + ENGINE_CHECK(size != -1, return, ""); + va_end(list); + std::string str(buff.data(), size); + char realTime[MAX_TIME_SIZE]; + auto sysTime = std::chrono::system_clock::now(); + auto currentTime = std::chrono::system_clock::to_time_t(sysTime); + std::strftime(realTime, sizeof(realTime), "%Y-%m-%d %H:%M:%S", std::localtime(¤tTime)); + logStream << realTime << "[" << LOG_LABEL << "]" << name << " " << line << " : " << str << std::endl; + std::cout << realTime << "[" << LOG_LABEL << "]" << name << " " << line << " : " << str << std::endl; + logStream.close(); +} + +bool UpdateHelper::JudgeLevel(const UpdateLogLevel& level) +{ + const UpdateLogLevel& curLevel = UpdateHelper::GetLogLevel(); + if (level <= curLevel) { + return true; + } + return true; +} + +std::string UpdateHelper::GetBriefFileName(const std::string &file) +{ + auto pos = file.find_last_of("/"); + if (pos != std::string::npos) { + return file.substr(pos + 1); + } + + pos = file.find_last_of("\\"); + if (pos != std::string::npos) { + return file.substr(pos + 1); + } + + return file; +} + +std::vector UpdateHelper::SplitString(const std::string &str, const std::string &delimiter) +{ + std::vector result; + ENGINE_CHECK(!str.empty(), return result, "string is empty"); + + size_t found = std::string::npos; + size_t start = 0; + while (true) { + found = str.find_first_of(delimiter, start); + result.push_back(str.substr(start, found - start)); + if (found == std::string::npos) { + break; + } + start = found + 1; + } + return result; +} + +int32_t UpdateHelper::CompareVersion(const std::string &version1, const std::string &version2) +{ + std::vector result1 = SplitString(version1, "."); + std::vector result2 = SplitString(version2, "."); + if (result1.size() != result2.size()) { + return ((result1.size() > result2.size()) ? -1 : 1); + } + + for (size_t i = 1; i < result1.size(); i++) { + long long ver1 = std::stoll(result1[i]); + long long ver2 = std::stoll(result2[i]); + if (ver1 == ver2) { + continue; + } + return ((ver1 > ver2) ? 1 : -1); + } + return 0; +} + +std::vector UpdateHelper::HexToDegist(const std::string &str) +{ + std::vector result; + for (size_t i = 0; i < str.length(); i += HEX_DIGEST_NUM) { + std::string byte = str.substr(i, HEX_DIGEST_NUM); + auto chr = static_cast(static_cast(strtol(byte.c_str(), nullptr, HEX_DIGEST_BASE))); + result.push_back(chr); + } + return result; +} +} +} // namespace OHOS \ No newline at end of file diff --git a/engine/src/update_service.cpp b/engine/src/update_service.cpp new file mode 100644 index 0000000..5c848a2 --- /dev/null +++ b/engine/src/update_service.cpp @@ -0,0 +1,528 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "update_service.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cJSON.h" +#include "iservice_registry.h" +#include "libxml/parser.h" +#include "libxml/tree.h" +#include "misc_info/misc_info.h" +#include "openssl/err.h" +#include "openssl/ssl.h" +#include "package/package.h" +#include "parameters.h" +#include "progress_thread.h" +#include "securec.h" +#include "system_ability_definition.h" +#include "update_helper.h" +#include "updaterkits/updaterkits.h" +#include "utils.h" + +namespace OHOS { +namespace update_engine { +REGISTER_SYSTEM_ABILITY_BY_ID(UpdateService, UPDATE_DISTRIBUTED_SERVICE_ID, true) + +constexpr int32_t PORT_NUMBER = 5022; +constexpr int32_t JSON_MAX_SIZE = 4096; +const mode_t MKDIR_MODE = 0777; + +const std::string MISC_FILE = "/dev/block/platform/soc/10100000.himci.eMMC/by-name/misc"; +const std::string BASE_PATH = "/data/updater"; +#ifndef UPDATER_UT +const std::string SIGNING_CERT_NAME = "/data/update_sa/signing_cert.crt"; +#else +const std::string SIGNING_CERT_NAME = "/data/updater/src/signing_cert.crt"; +#endif + +UpdateService::UpdateService(int32_t systemAbilityId, bool runOnCreate) + : SystemAbility(systemAbilityId, runOnCreate) +{ + GetServerIp(serverAddr_); + ENGINE_LOGI("UpdateService serverAddr: %s ", serverAddr_.c_str()); + InitVersionInfo(versionInfo_); +} + +UpdateService::~UpdateService() +{ + ENGINE_LOGE("UpdateServerTest free %p", this); + if (downloadThread_ != nullptr) { + downloadThread_->StopDownload(); + delete downloadThread_; + downloadThread_ = nullptr; + } +} + +int32_t UpdateService::RegisterUpdateCallback(const UpdateContext &ctx, + const sptr &updateCallback) +{ + ENGINE_CHECK(updateCallback != nullptr, return -1, "Invalid callback"); + updateCallback_ = updateCallback; + updateContext_.upgradeDevId = ctx.upgradeDevId; + updateContext_.controlDevId = ctx.controlDevId; + updateContext_.upgradeApp = ctx.upgradeApp; + updateContext_.type = ctx.type; + updateContext_.upgradeFile = ctx.upgradeFile; + return 0; +} + +int32_t UpdateService::UnregisterUpdateCallback() +{ + updateCallback_ = nullptr; + return 0; +} + +int32_t UpdateService::GetNewVersion(VersionInfo &versionInfo) +{ + InitVersionInfo(versionInfo); + return 0; +} + +int32_t UpdateService::GetUpgradeStatus(UpgradeInfo &info) +{ + info.status = upgradeStatus_; + return 0; +} + +int32_t UpdateService::SetUpdatePolicy(const UpdatePolicy &policy) +{ + return UpdateHelper::CopyUpdatePolicy(policy, policy_); +} + +int32_t UpdateService::GetUpdatePolicy(UpdatePolicy &policy) +{ + return UpdateHelper::CopyUpdatePolicy(policy_, policy); +} + +int32_t UpdateService::CheckNewVersion() +{ + upgradeStatus_ = UPDATE_STATE_CHECK_VERSION_ON; + int32_t engineSocket = socket(AF_INET, SOCK_STREAM, 0); + ENGINE_CHECK(engineSocket >= 0, SearchCallback("socket error !", SERVER_BUSY); return 1, "socket error !"); + + sockaddr_in engineSin {}; + engineSin.sin_family = AF_INET; + engineSin.sin_port = htons(PORT_NUMBER); + int32_t ret = inet_pton(AF_INET, serverAddr_.c_str(), &engineSin.sin_addr); + ENGINE_CHECK(ret > 0, close(engineSocket); SearchCallback("Invalid ip!", SERVER_BUSY); return 1, "socket error"); + + struct timeval tv = {TIMEOUT_FOR_CONNECT, 0}; + setsockopt(engineSocket, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval)); + ret = connect(engineSocket, reinterpret_cast(&engineSin), sizeof(engineSin)); + ENGINE_CHECK(ret == 0, +#ifndef UPDATER_UT + SearchCallback("Connect error !", SERVER_BUSY); + close(engineSocket); +#else + SearchCallback("update service test connect error !", HAS_NEW_VERSION); + close(engineSocket); +#endif + return 1, "connect error"); + ReadDataFromSSL(engineSocket); + return 0; +} + +int32_t UpdateService::DownloadVersion() +{ + if (access(BASE_PATH.c_str(), 0) == -1) { + mkdir(BASE_PATH.c_str(), MKDIR_MODE); + } + + Progress progress0 = {0, UPDATE_STATE_DOWNLOAD_ON, ""}; + ENGINE_CHECK(upgradeStatus_ >= UPDATE_STATE_CHECK_VERSION_SUCCESS, + progress0.status = UPDATE_STATE_DOWNLOAD_FAIL; + progress0.endReason = "Invalid status"; + DownloadCallback("", progress0); return -1, "Invalid status %d", upgradeStatus_); + + ENGINE_CHECK(!versionInfo_.result[0].verifyInfo.empty(), + progress0.status = UPDATE_STATE_DOWNLOAD_FAIL; + progress0.endReason = "Invalid verify info"; + DownloadCallback("", progress0); return -1, "Invalid verify info"); + std::string downloadFileName = BASE_PATH + "/" + versionInfo_.result[0].verifyInfo; + size_t localFileLength = DownloadThread::GetLocalFileLength(downloadFileName); + ENGINE_LOGI("Download %zu %s", localFileLength, downloadFileName.c_str()); + if (localFileLength == versionInfo_.result[0].size && versionInfo_.result[0].size != 0) { + progress0.percent = DOWNLOAD_FINISH_PERCENT; + progress0.status = UPDATE_STATE_DOWNLOAD_SUCCESS; + DownloadCallback(downloadFileName, progress0); + return 0; + } + + upgradeStatus_ = UPDATE_STATE_DOWNLOAD_ON; + if (downloadThread_ == nullptr) { + downloadThread_ = new DownloadThread([&](const std::string &fileName, const Progress &progress) -> int { + DownloadCallback(fileName, progress); + return 0; + }); + ENGINE_CHECK(downloadThread_ != nullptr, + progress0.status = UPDATE_STATE_DOWNLOAD_FAIL; + progress0.endReason = "Failed to start thread"; + DownloadCallback(downloadFileName, progress0); return -1, "Failed to start thread"); + } + return downloadThread_->StartDownload(downloadFileName, GetDownloadServerUrl()); +} + +int32_t UpdateService::DoUpdate() +{ + Progress progress; + progress.percent = 1; + progress.status = UPDATE_STATE_INSTALL_ON; + ENGINE_CHECK(upgradeStatus_ >= UPDATE_STATE_DOWNLOAD_SUCCESS, + progress.endReason = "Invalid status"; + progress.status = UPDATE_STATE_INSTALL_FAIL; + UpgradeCallback(progress); + return -1, "Invalid status %d", upgradeStatus_); + + progress.status = UPDATE_STATE_INSTALL_SUCCESS; + bool ret = RebootAndInstallUpgradePackage(MISC_FILE, updateContext_.upgradeFile); + ENGINE_CHECK(ret, return -1, "UpdateService::DoUpdate SetParameter failed"); + progress.percent = DOWNLOAD_FINISH_PERCENT; + UpgradeCallback(progress); + return 0; +} + +void UpdateService::SearchCallback(const std::string &msg, SearchStatus status) +{ + ENGINE_LOGI("SearchCallback %s ", msg.c_str()); + versionInfo_.status = status; + versionInfo_.errMsg = msg; + if (status == HAS_NEW_VERSION || status == NO_NEW_VERSION) { + upgradeStatus_ = UPDATE_STATE_CHECK_VERSION_SUCCESS; + + // Compare the downloaded version with the local version. + std::string loadVersion = OHOS::system::GetParameter("ro.build.id", ""); + int32_t ret = UpdateHelper::CompareVersion(versionInfo_.result[0].versionCode, loadVersion); + if (ret <= 0) { + versionInfo_.status = NO_NEW_VERSION; + } + } else { + upgradeStatus_ = UPDATE_STATE_CHECK_VERSION_FAIL; + } + if (updateCallback_ != nullptr) { + updateCallback_->OnCheckVersionDone(versionInfo_); + } +} + +void UpdateService::DownloadCallback(const std::string &fileName, const Progress &progress) +{ + Progress downloadProgress {}; + upgradeStatus_ = UPDATE_STATE_DOWNLOAD_ON; + if (progress.status == UPDATE_STATE_DOWNLOAD_FAIL || + progress.status == UPDATE_STATE_DOWNLOAD_SUCCESS) { + upgradeStatus_ = progress.status; + } + downloadProgress.percent = progress.percent; + downloadProgress.status = progress.status; + downloadProgress.endReason = progress.endReason; + +#ifdef UPDATER_UT + upgradeStatus_ = UPDATE_STATE_DOWNLOAD_SUCCESS; +#endif + ENGINE_LOGI("DownloadCallback status %d %d", progress.status, progress.percent); + if (progress.status == UPDATE_STATE_DOWNLOAD_SUCCESS) { + ENGINE_LOGI("DownloadCallback fileName %s %s", fileName.c_str(), updateContext_.upgradeFile.c_str()); + if (rename(fileName.c_str(), updateContext_.upgradeFile.c_str())) { + ENGINE_LOGE("Rename file fail %s", fileName.c_str()); + remove(updateContext_.upgradeFile.c_str()); + downloadProgress.status = UPDATE_STATE_DOWNLOAD_FAIL; + } else if (!VerifyDownloadPkg(updateContext_.upgradeFile, downloadProgress)) { + // If the verification fails, delete the corresponding package. + remove(updateContext_.upgradeFile.c_str()); + downloadProgress.status = UPDATE_STATE_VERIFY_FAIL; + } + } + + if (updateCallback_ != nullptr) { + updateCallback_->OnDownloadProgress(downloadProgress); + } +} + +void UpdateService::UpgradeCallback(const Progress &progress) +{ + upgradeStatus_ = progress.status; + ENGINE_LOGE("UpgradeCallback status %d %d", progress.status, progress.percent); + if (updateCallback_ != nullptr) { + updateCallback_->OnUpgradeProgress(progress); + } +} + +void UpdateService::ReadDataFromSSL(int32_t engineSocket) +{ + SearchStatus result = SERVER_BUSY; + std::string errMsg = "Couldn't connect to server"; + std::vector buffer(JSON_MAX_SIZE); + + SSL_library_init(); + OpenSSL_add_all_algorithms(); + SSL_load_error_strings(); + SSL_CTX* sslCtx = SSL_CTX_new(SSLv23_client_method()); + ENGINE_CHECK(sslCtx != nullptr, return, "sslCtx is nullptr"); + SSL *ssl = SSL_new(sslCtx); + ENGINE_CHECK(ssl != nullptr, SSL_CTX_free(sslCtx); return, "ssl is nullptr"); + SSL_set_fd(ssl, engineSocket); + int32_t ret = SSL_connect(ssl); + if (ret != -1) { + int32_t len = SSL_read(ssl, buffer.data(), JSON_MAX_SIZE); + if (len > 0 && ParseJsonFile(buffer, versionInfo_) == 0) { + result = HAS_NEW_VERSION; + errMsg = ""; + } else { + result = SYSTEM_ERROR; + errMsg = "Couldn't read data"; + } + } else { + result = SYSTEM_ERROR; + errMsg = "Couldn't connect to server"; + } + SSL_shutdown(ssl); + SSL_free(ssl); + close(engineSocket); + SSL_CTX_free(sslCtx); + + SearchCallback(errMsg, result); + return; +} + +int32_t UpdateService::ParseJsonFile(const std::vector &buffer, VersionInfo &info) +{ + ENGINE_CHECK(buffer.size() > 0, return -1, "JsonFile length must > 0"); + cJSON *root = cJSON_Parse(buffer.data()); + ENGINE_CHECK(root != nullptr, return -1, "Error get root"); + + cJSON *item = cJSON_GetObjectItem(root, "searchStatus"); + ENGINE_CHECK(item != nullptr, cJSON_Delete(root); return -1, "Error get searchStatus"); + info.status = static_cast(item->valueint); + + item = cJSON_GetObjectItem(root, "errMsg"); + ENGINE_CHECK(item != nullptr, cJSON_Delete(root); return -1, "Error get errMsg"); + info.errMsg = item->valuestring; + + cJSON *results = cJSON_GetObjectItem(root, "checkResults"); + ENGINE_CHECK(results != nullptr, cJSON_Delete(root); return -1, "Error get checkResults"); + int32_t ret = ReadCheckVersionResult(results, info); + ENGINE_CHECK(ret == 0, cJSON_Delete(root); return -1, "Error get checkResults"); + + cJSON *descriptInfo = cJSON_GetObjectItem(root, "descriptInfo"); + ENGINE_CHECK(descriptInfo != nullptr, cJSON_Delete(root); return -1, "Error get descriptInfo"); + ret = ReadCheckVersiondescriptInfo(descriptInfo, info); + ENGINE_CHECK(ret == 0, cJSON_Delete(root); return -1, "Error get descriptInfo"); + + cJSON_Delete(root); + if (info.status == HAS_NEW_VERSION) { + ENGINE_CHECK(!info.result[0].verifyInfo.empty() && + !info.result[0].versionName.empty() && + info.result[0].size > 0, return -1, "Error get descriptInfo"); + } + return 0; +} + +int32_t UpdateService::ReadCheckVersionResult(const cJSON* results, VersionInfo &info) +{ + size_t number = cJSON_GetArraySize(results); + for (size_t i = 0; i < number && i < sizeof(info.result) / sizeof(info.result[0]); i++) { + cJSON *result = cJSON_GetArrayItem(results, i); + ENGINE_CHECK(result != nullptr, return -1, "Error get result"); + + cJSON *item = cJSON_GetObjectItem(result, "versionName"); + ENGINE_CHECK(item != nullptr, return -1, "Error get versionName"); + info.result[i].versionName = item->valuestring; + + item = cJSON_GetObjectItem(result, "versionCode"); + ENGINE_CHECK(item != nullptr, return -1, "Error get versionCode"); + info.result[i].versionCode = item->valuestring; + + item = cJSON_GetObjectItem(result, "verifyInfo"); + ENGINE_CHECK(item != nullptr, return -1, "Error get verifyInfo"); + info.result[i].verifyInfo = item->valuestring; + + item = cJSON_GetObjectItem(result, "size"); + ENGINE_CHECK(item != nullptr, return -1, "Error get size"); + info.result[i].size = item->valueint; + + item = cJSON_GetObjectItem(result, "packageType"); + ENGINE_CHECK(item != nullptr, return -1, "Error get packageType"); + info.result[i].packageType = (PackageType)(item->valueint); + + item = cJSON_GetObjectItem(result, "descriptPackageId"); + ENGINE_CHECK(item != nullptr, return -1, "Error get descriptPackageId"); + info.result[i].descriptPackageId = item->valuestring; + } + return 0; +} + +int32_t UpdateService::ReadCheckVersiondescriptInfo(const cJSON *descriptInfo, VersionInfo &info) +{ + size_t number = cJSON_GetArraySize(descriptInfo); + for (size_t i = 0; i < number && i < sizeof(info.result) / sizeof(info.result[0]); i++) { + cJSON* descript = cJSON_GetArrayItem(descriptInfo, i); + ENGINE_CHECK(descript != nullptr, return -1, "Error get descriptInfo"); + + cJSON *item = cJSON_GetObjectItem(descript, "descriptPackageId"); + if (item != nullptr) { + info.descriptInfo[i].descriptPackageId = item->valuestring; + } + item = cJSON_GetObjectItem(descript, "content"); + if (item != nullptr) { + info.descriptInfo[i].content = item->valuestring; + ENGINE_LOGI(" descriptInfo content %s", info.descriptInfo[i].content.c_str()); + } + } + return 0; +} + +bool UpdateService::VerifyDownloadPkg(const std::string &pkgName, Progress &progress) +{ + // Compare the downloaded version with the local version. Only update is supported. + std::string loadVersion = OHOS::system::GetParameter("ro.build.id", ""); + int32_t ret = UpdateHelper::CompareVersion(versionInfo_.result[0].versionCode, loadVersion); + if (ret <= 0) { + progress.endReason = "Update package version earlier than the local version"; + ENGINE_LOGE("Version compare Failed local '%s' server '%s'", + loadVersion.c_str(), versionInfo_.result[0].versionCode.c_str()); + return false; + } + ENGINE_LOGI("versionInfo_.result[0].verifyInfo %s ", versionInfo_.result[0].verifyInfo.c_str()); + std::vector digest = UpdateHelper::HexToDegist(versionInfo_.result[0].verifyInfo); + ret = VerifyPackage(pkgName.c_str(), + SIGNING_CERT_NAME.c_str(), versionInfo_.result[0].versionCode.c_str(), digest.data(), digest.size()); + if (ret != 0) { + progress.endReason = "Upgrade package verify Failed"; + ENGINE_LOGE("Package %s verification Failed", pkgName.c_str()); + return false; + } + ENGINE_LOGE("Package verify success"); + return true; +} + +std::string UpdateService::GetDownloadServerUrl() const +{ + std::string url = "http://"; + url += serverAddr_; + url += "/"; + url += versionInfo_.result[0].descriptPackageId; + return url; +} + +void UpdateService::GetServerIp(std::string &ip) +{ + if (access("/data/update_sa", 0) == -1) { + mkdir("/data/update_sa", MKDIR_MODE); + } + + xmlDocPtr doc = xmlReadFile("/data/update_sa/update_config.xml", "UTF-8", XML_PARSE_NOBLANKS); + ENGINE_CHECK(doc != nullptr, return, "Open config Failed"); + + xmlNodePtr rootNode = xmlDocGetRootElement(doc); + ENGINE_CHECK(rootNode != nullptr, xmlFreeDoc(doc); return, "Get root node Failed"); + + xmlChar *nodeContent = nullptr; + for (xmlNodePtr node = rootNode->children; node; node = node->next) { + if ((!xmlStrcmp(node->name, (const xmlChar *)"serverIp"))) { + nodeContent = xmlNodeGetContent(node); + break; + } + } + if (nodeContent != nullptr) { + ip = (char*)nodeContent; + xmlFree(nodeContent); + } + xmlFreeDoc(doc); + return; +} + +int32_t UpdateService::Cancel(int32_t service) +{ + ENGINE_LOGI("Cancel %d", service); + if (downloadThread_ != nullptr && service == DOWNLOAD) { + downloadThread_->StopDownload(); + ENGINE_LOGI("StopDownload"); + delete downloadThread_; + downloadThread_ = nullptr; + } + return 0; +} + +int32_t UpdateService::RebootAndClean(const std::string &miscFile, const std::string &cmd) +{ +#ifndef UPDATER_UT + return RebootAndCleanUserData(miscFile, cmd) ? 0 : -1; +#else + return 0; +#endif +} + +int32_t UpdateService::RebootAndInstall(const std::string &miscFile, const std::string &packageName) +{ +#ifndef UPDATER_UT + return RebootAndInstallUpgradePackage(miscFile, packageName) ? 0 : -1; +#else + return 0; +#endif +} + +void UpdateService::InitVersionInfo(VersionInfo &versionInfo) const +{ + versionInfo.status = HAS_NEW_VERSION; + std::string versionName = OHOS::system::GetParameter("ro.build.id", ""); + if (versionName.empty()) { + versionInfo.status = SYSTEM_ERROR; + versionInfo.errMsg = "Can not get local version"; + } + + for (size_t i = 0; i < sizeof(versionInfo.result) / sizeof(versionInfo.result[0]); i++) { + versionInfo.result[i].size = 0; + versionInfo.result[i].packageType = PACKAGE_TYPE_NORMAL; + versionInfo.result[i].versionName = versionName; + versionInfo.result[i].versionCode = ""; + versionInfo.result[i].verifyInfo = ""; + versionInfo.result[i].descriptPackageId = ""; + } + for (size_t i = 0; i < sizeof(versionInfo.descriptInfo) / sizeof(versionInfo.descriptInfo[0]); i++) { + versionInfo.descriptInfo[i].content = ""; + versionInfo.descriptInfo[i].descriptPackageId = ""; + } +} + +void UpdateService::OnStart() +{ + ENGINE_LOGI("UpdaterService OnStart"); + bool res = Publish(this); + if (res == false) { + ENGINE_LOGI("UpdaterService OnStart failed"); + } + return; +} + +void UpdateService::OnStop() +{ + ENGINE_LOGI("UpdaterService OnStop"); +} +} +} // namespace OHOS diff --git a/engine/src/update_service_stub.cpp b/engine/src/update_service_stub.cpp new file mode 100755 index 0000000..abebd16 --- /dev/null +++ b/engine/src/update_service_stub.cpp @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "update_service_stub.h" +#include "update_helper.h" +#include "securec.h" + +using namespace std; + +namespace OHOS { +namespace update_engine { +static int32_t GetNewVersionStub(UpdateServiceStub::UpdateServiceStubPtr service, + MessageParcel& data, MessageParcel& reply, MessageOption &option) +{ + ENGINE_CHECK(service != nullptr, return -1, "Invalid param"); + VersionInfo info = {}; + int32_t ret = service->GetNewVersion(info); + ENGINE_CHECK(ret == 0, return -1, "Failed to get new version"); + UpdateHelper::WriteVersionInfo(reply, info); + return 0; +} + +static int32_t GetUpgradeStatusStub(UpdateServiceStub::UpdateServiceStubPtr service, + MessageParcel& data, MessageParcel& reply, MessageOption &option) +{ + ENGINE_CHECK(service != nullptr, return -1, "Invalid param"); + UpgradeInfo info = {}; + int32_t ret = service->GetUpgradeStatus(info); + ENGINE_CHECK(ret == 0, return -1, "Failed to get new upgrade status"); + UpdateHelper::WriteUpgradeInfo(reply, info); + return 0; +} + +static int32_t CheckNewVersionStub(UpdateServiceStub::UpdateServiceStubPtr service, + MessageParcel& data, MessageParcel& reply, MessageOption &option) +{ + ENGINE_CHECK(service != nullptr, return -1, "Invalid param"); + int32_t ret = service->CheckNewVersion(); + reply.WriteInt32(ret); + return 0; +} + +static int32_t DownloadVersionStub(UpdateServiceStub::UpdateServiceStubPtr service, + MessageParcel& data, MessageParcel& reply, MessageOption &option) +{ + ENGINE_CHECK(service != nullptr, return -1, "Invalid param"); + int32_t ret = service->DownloadVersion(); + reply.WriteInt32(ret); + return 0; +} + +static int32_t DoUpdateStub(UpdateServiceStub::UpdateServiceStubPtr service, + MessageParcel& data, MessageParcel& reply, MessageOption &option) +{ + ENGINE_CHECK(service != nullptr, return -1, "Invalid param"); + int32_t ret = service->DoUpdate(); + reply.WriteInt32(ret); + return 0; +} + +static int32_t SetUpdatePolicyStub(UpdateServiceStub::UpdateServiceStubPtr service, + MessageParcel& data, MessageParcel& reply, MessageOption &option) +{ + ENGINE_CHECK(service != nullptr, return -1, "Invalid param"); + UpdatePolicy policy = {}; + UpdateHelper::ReadUpdatePolicy(data, policy); + int32_t ret = service->SetUpdatePolicy(policy); + reply.WriteInt32(ret); + return 0; +} + +static int32_t GetUpdatePolicyStub(UpdateServiceStub::UpdateServiceStubPtr service, + MessageParcel& data, MessageParcel& reply, MessageOption &option) +{ + ENGINE_CHECK(service != nullptr, return -1, "Invalid param"); + UpdatePolicy policy = {}; + int32_t ret = service->GetUpdatePolicy(policy); + ENGINE_CHECK(ret == 0, return -1, "Failed to get new get policy"); + UpdateHelper::WriteUpdatePolicy(reply, policy); + return 0; +} + +static int32_t RegisterUpdateCallbackStub(UpdateServiceStub::UpdateServiceStubPtr service, + MessageParcel& data, MessageParcel& reply, MessageOption &option) +{ + ENGINE_CHECK(service != nullptr, return -1, "Invalid param"); + int32_t ret = -1; + UpdateContext ctx {}; + UpdateHelper::ReadUpdateContext(data, ctx); + auto remote = data.ReadRemoteObject(); + ENGINE_CHECK(remote != nullptr, reply.WriteInt32(ret); return 0, "Failed to read remote obj"); + ret = service->RegisterUpdateCallback(ctx, iface_cast(remote)); + reply.WriteInt32(ret); + return 0; +} + +static int32_t UnregisterUpdateCallbackStub(UpdateServiceStub::UpdateServiceStubPtr service, + MessageParcel& data, MessageParcel& reply, MessageOption &option) +{ + ENGINE_CHECK(service != nullptr, return -1, "Invalid param"); + int32_t ret = service->UnregisterUpdateCallback(); + reply.WriteInt32(ret); + return 0; +} + +static int32_t CancelStub(UpdateServiceStub::UpdateServiceStubPtr service, + MessageParcel& data, MessageParcel& reply, MessageOption &option) +{ + ENGINE_CHECK(service != nullptr, return -1, "Invalid param"); + int32_t ret = service->Cancel(data.ReadInt32()); + reply.WriteInt32(ret); + return 0; +} + +static int32_t RebootAndCleanStub(UpdateServiceStub::UpdateServiceStubPtr service, + MessageParcel& data, MessageParcel& reply, MessageOption &option) +{ + ENGINE_CHECK(service != nullptr, return -1, "Invalid param"); + string miscFile = Str16ToStr8(data.ReadString16()); + string cmd = Str16ToStr8(data.ReadString16()); + int32_t ret = service->RebootAndClean(miscFile, cmd); + reply.WriteInt32(ret); + return 0; +} + +static int32_t RebootAndInstallStub(UpdateServiceStub::UpdateServiceStubPtr service, + MessageParcel& data, MessageParcel& reply, MessageOption &option) +{ + ENGINE_CHECK(service != nullptr, return -1, "Invalid param"); + string miscFile = Str16ToStr8(data.ReadString16()); + string packageName = Str16ToStr8(data.ReadString16()); + int32_t ret = service->RebootAndClean(miscFile, packageName); + reply.WriteInt32(ret); + return 0; +} + +int32_t UpdateServiceStub::OnRemoteRequest(uint32_t code, + MessageParcel& data, MessageParcel& reply, MessageOption &option) +{ + static std::map requestFuncMap = { + {IUpdateService::CHECK_VERSION, CheckNewVersionStub}, + {IUpdateService::DOWNLOAD, DownloadVersionStub}, + {IUpdateService::UPGRADE, DoUpdateStub}, + {IUpdateService::SET_POLICY, SetUpdatePolicyStub}, + {IUpdateService::GET_POLICY, GetUpdatePolicyStub}, + {IUpdateService::GET_NEW_VERSION, GetNewVersionStub}, + {IUpdateService::GET_STATUS, GetUpgradeStatusStub}, + {IUpdateService::REGISTER_CALLBACK, RegisterUpdateCallbackStub}, + {IUpdateService::UNREGISTER_CALLBACK, UnregisterUpdateCallbackStub}, + {IUpdateService::CANCEL, CancelStub}, + {IUpdateService::REBOOT_CLEAN, RebootAndCleanStub}, + {IUpdateService::REBOOT_INSTALL, RebootAndInstallStub}, + }; + + ENGINE_LOGI("UpdateServiceStub OnRemoteRequest code %u", code); + for (auto inter = requestFuncMap.begin(); inter != requestFuncMap.end(); inter++) { + if (inter->first == code) { + return inter->second(this, data, reply, option); + } + } + ENGINE_LOGE("UpdateServiceStub OnRemoteRequest code %u not found", code); + return IPCObjectStub::OnRemoteRequest(code, data, reply, option); +} +} +} // namespace OHO \ No newline at end of file diff --git a/interfaces/innerkits/engine/BUILD.gn b/interfaces/innerkits/engine/BUILD.gn new file mode 100755 index 0000000..1f37f8f --- /dev/null +++ b/interfaces/innerkits/engine/BUILD.gn @@ -0,0 +1,64 @@ +# Copyright (c) 2021 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//build/ohos.gni") + +ohos_prebuilt_etc("updater_sa.rc") { + source = "etc/updater_sa.rc" + relative_install_dir = "init" + part_name = "updater" +} + +ohos_static_library("updateservicekits") { + defines = [ "DUAL_ADAPTER" ] + sources = [ + "//base/update/updateservice/callback/src/update_callback.cpp", + "//base/update/updateservice/callback/src/update_callback_stub.cpp", + "//base/update/updateservice/engine/src/update_helper.cpp", + "//base/update/updateservice/interfaces/innerkits/engine/update_service_kits_impl.cpp", + "//base/update/updateservice/interfaces/innerkits/engine/update_service_proxy.cpp", + ] + + include_dirs = [ + "//base/update/updater/services/include", + "//base/update/updater/utils/include", + "//base/update/updater/interfaces/kits/include", + "//utils/native/base/include", + "//utils/system/safwk/native/include", + "//base/update/updateservice/interfaces/innerkits/include", + "//base/update/updateservice/engine/include", + "//base/update/updateservice/callback/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//foundation/distributedschedule/safwk/services/safwk/include", + "//foundation/distributedschedule/safwk/interfaces/innerkits/safwk", + "//foundation/distributedschedule/samgr/adapter/interfaces/innerkits/include", + "//foundation/distributedschedule/samgr/interfaces/innerkits/samgr_proxy/include", + "//third_party/bounds_checking_function/include", + ] + + deps = [ + "//base/update/updater/services/log:libupdaterlog", + "//third_party/bounds_checking_function:libsec_static", + "//utils/native/base:utils", + ] + + external_deps = [ + "hiviewdfx_hilog_native:libhilog", + "ipc:ipc_core", + "safwk:system_ability_fwk", + "samgr_L2:samgr_proxy", + "startup_l2:syspara", + ] + + part_name = "updater" +} diff --git a/interfaces/innerkits/engine/update_service_kits_impl.cpp b/interfaces/innerkits/engine/update_service_kits_impl.cpp new file mode 100755 index 0000000..1fc6001 --- /dev/null +++ b/interfaces/innerkits/engine/update_service_kits_impl.cpp @@ -0,0 +1,232 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "update_service_kits_impl.h" + +#include "if_system_ability_manager.h" +#include "iservice_registry.h" +#include "iupdate_service.h" +#include "iupdate_callback.h" +#include "securec.h" +#include "system_ability_definition.h" + +namespace OHOS { +namespace update_engine { +UpdateServiceKits& UpdateServiceKits::GetInstance() +{ + return DelayedRefSingleton::GetInstance(); +} + +UpdateServiceKitsImpl::UpdateServiceKitsImpl() {} + +UpdateServiceKitsImpl::~UpdateServiceKitsImpl() {} + +void UpdateServiceKitsImpl::ResetService(const wptr& remote) +{ + ENGINE_LOGI("Remote is dead, reset service instance"); + + std::lock_guard lock(updateServiceLock_); + if (updateService_ != nullptr) { + sptr object = updateService_->AsObject(); + if ((object != nullptr) && (remote == object)) { + object->RemoveDeathRecipient(deathRecipient_); + updateService_ = nullptr; + } + } +} + +sptr UpdateServiceKitsImpl::GetService() +{ + std::lock_guard lock(updateServiceLock_); + if (updateService_ != nullptr) { + return updateService_; + } + + sptr samgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); + ENGINE_CHECK(samgr != nullptr, return nullptr, "Get samgr failed"); + sptr object = samgr->GetSystemAbility(UPDATE_DISTRIBUTED_SERVICE_ID); + ENGINE_CHECK(object != nullptr, return nullptr, "Get update object from samgr failed"); + + if (deathRecipient_ == nullptr) { + deathRecipient_ = new DeathRecipient(); + } + + if ((object->IsProxyObject()) && (!object->AddDeathRecipient(deathRecipient_))) { + ENGINE_LOGE("Failed to add death recipient"); + } + + ENGINE_LOGI("get remote object ok"); + updateService_ = iface_cast(object); + if (updateService_ == nullptr) { + ENGINE_LOGE("account iface_cast failed"); + } + return updateService_; +} + +void UpdateServiceKitsImpl::DeathRecipient::OnRemoteDied(const wptr &remote) +{ + DelayedRefSingleton::GetInstance().ResetService(remote); +} + +UpdateServiceKitsImpl::RemoteUpdateCallback::RemoteUpdateCallback(const UpdateCallbackInfo &cb) + : UpdateCallback() +{ + updateCallback_.checkNewVersionDone = cb.checkNewVersionDone; + updateCallback_.downloadProgress = cb.downloadProgress; + updateCallback_.upgradeProgress = cb.upgradeProgress; +} + +UpdateServiceKitsImpl::RemoteUpdateCallback::~RemoteUpdateCallback() +{ + updateCallback_.checkNewVersionDone = nullptr; + updateCallback_.downloadProgress = nullptr; + updateCallback_.upgradeProgress = nullptr; +} + +void UpdateServiceKitsImpl::RemoteUpdateCallback::OnCheckVersionDone(const VersionInfo &info) +{ + ENGINE_LOGE("OnCheckVersionDone VersionInfo status %d", info.status); + ENGINE_LOGE("OnCheckVersionDone VersionInfo errMsg %s", info.errMsg.c_str()); + ENGINE_LOGE("OnCheckVersionDone VersionInfo versionName : %s", info.result[0].versionName.c_str()); + ENGINE_LOGE("OnCheckVersionDone VersionInfo versionCode : %s", info.result[0].versionCode.c_str()); + ENGINE_LOGE("OnCheckVersionDone VersionInfo verifyInfo : %s", info.result[0].verifyInfo.c_str()); + ENGINE_LOGE("OnCheckVersionDone VersionInfo size : %zu", info.result[0].size); + if (updateCallback_.checkNewVersionDone != nullptr) { + updateCallback_.checkNewVersionDone(info); + } +} + +void UpdateServiceKitsImpl::RemoteUpdateCallback::OnDownloadProgress(const Progress &progress) +{ + ENGINE_LOGE("OnDownloadProgress progress %u %d", progress.percent, progress.status); + if (updateCallback_.downloadProgress != nullptr) { + updateCallback_.downloadProgress(progress); + } +} + +void UpdateServiceKitsImpl::RemoteUpdateCallback::OnUpgradeProgress(const Progress &progress) +{ + ENGINE_LOGE("OnUpgradeProgress progress %u %d", progress.percent, progress.status); + if (updateCallback_.upgradeProgress != nullptr) { + updateCallback_.upgradeProgress(progress); + } +} + +int32_t UpdateServiceKitsImpl::RegisterUpdateCallback(const UpdateContext &ctx, const UpdateCallbackInfo &cb) +{ + updateContext_.upgradeDevId = ctx.upgradeDevId; + updateContext_.controlDevId = ctx.controlDevId; + updateContext_.upgradeApp = ctx.upgradeApp; + updateContext_.type = ctx.type; + updateContext_.upgradeFile = ctx.upgradeFile; + if (remoteUpdateCallback_ == nullptr) { + remoteUpdateCallback_ = new RemoteUpdateCallback(cb); + ENGINE_CHECK(remoteUpdateCallback_ != nullptr, return -1, "Failed to create remote callback"); + auto updateService = GetService(); + ENGINE_CHECK(updateService != nullptr, return -1, "Get updateService failed"); + updateService->RegisterUpdateCallback(ctx, remoteUpdateCallback_); + } + return 0; +} + +int32_t UpdateServiceKitsImpl::UnregisterUpdateCallback() +{ + delete remoteUpdateCallback_; + remoteUpdateCallback_ = nullptr; + return 0; +} + +int32_t UpdateServiceKitsImpl::CheckNewVersion() +{ + ENGINE_LOGI("UpdateServiceKitsImpl::CheckNewVersion"); + + auto updateService = GetService(); + ENGINE_CHECK(updateService != nullptr, return -1, "Get updateService failed"); + return updateService->CheckNewVersion(); +} + +int32_t UpdateServiceKitsImpl::DownloadVersion() +{ + ENGINE_LOGI("UpdateServiceKitsImpl::DownloadVersion"); + auto updateService = GetService(); + ENGINE_CHECK(updateService != nullptr, return -1, "Get updateService failed"); + return updateService->DownloadVersion(); +} + +int32_t UpdateServiceKitsImpl::DoUpdate() +{ + ENGINE_LOGI("UpdateServiceKitsImpl::DoUpdate"); + auto updateService = GetService(); + ENGINE_CHECK(updateService != nullptr, return -1, "Get updateService failed"); + return updateService->DoUpdate(); +} + +int32_t UpdateServiceKitsImpl::GetNewVersion(VersionInfo &versionInfo) +{ + ENGINE_LOGI("UpdateServiceKitsImpl::GetNewversion"); + auto updateService = GetService(); + ENGINE_CHECK(updateService != nullptr, return -1, "Get updateService failed"); + return updateService->GetNewVersion(versionInfo); +} + +int32_t UpdateServiceKitsImpl::GetUpgradeStatus(UpgradeInfo &info) +{ + ENGINE_LOGI("UpdateServiceKitsImpl::GetUpgradeStatus"); + auto updateService = GetService(); + ENGINE_CHECK(updateService != nullptr, return -1, "Get updateService failed"); + return updateService->GetUpgradeStatus(info); +} + +int32_t UpdateServiceKitsImpl::SetUpdatePolicy(const UpdatePolicy &policy) +{ + ENGINE_LOGI("UpdateServiceKitsImpl::SetUpdatePolicy"); + auto updateService = GetService(); + ENGINE_CHECK(updateService != nullptr, return -1, "Get updateService failed"); + return updateService->SetUpdatePolicy(policy); +} + +int32_t UpdateServiceKitsImpl::GetUpdatePolicy(UpdatePolicy &policy) +{ + ENGINE_LOGI("UpdateServiceKitsImpl::GetUpdatePolicy"); + auto updateService = GetService(); + ENGINE_CHECK(updateService != nullptr, return -1, "Get updateService failed"); + return updateService->GetUpdatePolicy(policy); +} + +int32_t UpdateServiceKitsImpl::Cancel(int32_t service) +{ + ENGINE_LOGI("UpdateServiceKitsImpl::Cancel %d", service); + auto updateService = GetService(); + ENGINE_CHECK(updateService != nullptr, return -1, "Get updateService failed"); + return updateService->Cancel(service); +} + +int32_t UpdateServiceKitsImpl::RebootAndClean(const std::string &miscFile, const std::string &cmd) +{ + ENGINE_LOGI("UpdateServiceKitsImpl::RebootAndCleanUserData"); + auto updateService = GetService(); + ENGINE_CHECK(updateService != nullptr, return -1, "Get updateService failed"); + return updateService->RebootAndClean(miscFile, cmd); +} + +int32_t UpdateServiceKitsImpl::RebootAndInstall(const std::string &miscFile, const std::string &packageName) +{ + ENGINE_LOGI("UpdateServiceKitsImpl::RebootAndInstall"); + auto updateService = GetService(); + ENGINE_CHECK(updateService != nullptr, return -1, "Get updateService failed"); + return updateService->RebootAndInstall(miscFile, packageName); +} +} +} // namespace OHOS diff --git a/interfaces/innerkits/engine/update_service_proxy.cpp b/interfaces/innerkits/engine/update_service_proxy.cpp new file mode 100755 index 0000000..28cbc1e --- /dev/null +++ b/interfaces/innerkits/engine/update_service_proxy.cpp @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "update_service_proxy.h" +#include "update_helper.h" +#include "securec.h" + +namespace OHOS { +namespace update_engine { +int32_t UpdateServiceProxy::RegisterUpdateCallback(const UpdateContext &ctx, + const sptr& updateCallback) +{ + ENGINE_CHECK(updateCallback != nullptr, return ERR_INVALID_VALUE, "Invalid param"); + ENGINE_LOGI("UpdateServiceProxy::RegisterUpdateCallback"); + + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return ERR_FLATTEN_OBJECT, "Can not get remote"); + + MessageParcel data; + UpdateHelper::WriteUpdateContext(data, ctx); + bool ret = data.WriteRemoteObject(updateCallback->AsObject()); + ENGINE_CHECK(ret, return ERR_FLATTEN_OBJECT, "Can not get remote"); + MessageParcel reply; + MessageOption option { MessageOption::TF_SYNC }; + int32_t res = remote->SendRequest(REGISTER_CALLBACK, data, reply, option); + ENGINE_CHECK(res == ERR_OK, return ERR_FLATTEN_OBJECT, "Transact error"); + return reply.ReadInt32(); +} + +int32_t UpdateServiceProxy::UnregisterUpdateCallback() +{ + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return ERR_FLATTEN_OBJECT, "Can not get remote"); + + MessageParcel data; + MessageParcel reply; + MessageOption option { MessageOption::TF_SYNC }; + int32_t res = remote->SendRequest(UNREGISTER_CALLBACK, data, reply, option); + ENGINE_CHECK(res == ERR_OK, return ERR_FLATTEN_OBJECT, "Transact error"); + return reply.ReadInt32(); +} + +int32_t UpdateServiceProxy::CheckNewVersion() +{ + ENGINE_LOGI("UpdateServiceProxy::CheckNewVersion"); + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return ERR_FLATTEN_OBJECT, "Can not get remote"); + + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_SYNC); + int32_t res = remote->SendRequest(CHECK_VERSION, data, reply, option); + ENGINE_CHECK(res == ERR_OK, return ERR_FLATTEN_OBJECT, "Transact error"); + return reply.ReadInt32(); +} + +int32_t UpdateServiceProxy::DownloadVersion() +{ + ENGINE_LOGI("UpdateServiceProxy::DownloadVersion"); + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return ERR_FLATTEN_OBJECT, "Can not get remote"); + + // Construct a data sending message to the stub. + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_ASYNC); + int32_t ret = remote->SendRequest(DOWNLOAD, data, reply, option); + ENGINE_CHECK(ret == ERR_OK, return ERR_FLATTEN_OBJECT, "Transact error"); + return reply.ReadInt32(); +} + +int32_t UpdateServiceProxy::DoUpdate() +{ + ENGINE_LOGI("UpdateServiceProxy::DoUpdate"); + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return ERR_FLATTEN_OBJECT, "Can not get remote"); + + // Construct a data sending message to the stub. + MessageParcel data; + MessageParcel reply; + MessageOption option(MessageOption::TF_ASYNC); + int32_t ret = remote->SendRequest(UPGRADE, data, reply, option); + ENGINE_CHECK(ret == ERR_OK, return ERR_FLATTEN_OBJECT, "Transact error"); + return reply.ReadInt32(); +} + +int32_t UpdateServiceProxy::GetNewVersion(VersionInfo &versionInfo) +{ + ENGINE_LOGI("UpdateServiceProxy::GetNewVersion"); + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return ERR_FLATTEN_OBJECT, "Can not get remote"); + + MessageParcel data; + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(GET_NEW_VERSION, data, reply, option); + ENGINE_CHECK(ret == ERR_OK, return ERR_FLATTEN_OBJECT, "Transact error"); + + return UpdateHelper::ReadVersionInfo(reply, versionInfo); +} + +int32_t UpdateServiceProxy::GetUpgradeStatus(UpgradeInfo &info) +{ + ENGINE_LOGI("UpdateServiceProxy::GetUpgradeStatus"); + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return ERR_FLATTEN_OBJECT, "Can not get remote"); + + MessageParcel data; + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(GET_STATUS, data, reply, option); + ENGINE_CHECK(ret == ERR_OK, return ERR_FLATTEN_OBJECT, "Transact error"); + + return UpdateHelper::ReadUpgradeInfo(reply, info); +} + +int32_t UpdateServiceProxy::SetUpdatePolicy(const UpdatePolicy &policy) +{ + ENGINE_LOGI("UpdateServiceProxy::SetUpdatePolicy"); + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return ERR_FLATTEN_OBJECT, "Can not get remote"); + + MessageParcel data; + UpdateHelper::WriteUpdatePolicy(data, policy); + MessageParcel reply; + MessageOption option; + int32_t res = remote->SendRequest(SET_POLICY, data, reply, option); + ENGINE_CHECK(res == ERR_OK, return ERR_FLATTEN_OBJECT, "Transact error"); + + int32_t result = 0; + bool ret = reply.ReadInt32(result); + ENGINE_CHECK(ret, return ERR_FLATTEN_OBJECT, "Failed to read length"); + return result; +} + +int32_t UpdateServiceProxy::GetUpdatePolicy(UpdatePolicy &policy) +{ + ENGINE_LOGI("UpdateServiceProxy::GetUpdatePolicy"); + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return ERR_FLATTEN_OBJECT, "Can not get remote"); + + MessageParcel data; + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(GET_POLICY, data, reply, option); + ENGINE_CHECK(ret == ERR_OK, return ERR_FLATTEN_OBJECT, "Transact error"); + return UpdateHelper::ReadUpdatePolicy(reply, policy); +} + +int32_t UpdateServiceProxy::Cancel(int32_t service) +{ + ENGINE_LOGI("UpdateServiceProxy::Cancel"); + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return ERR_FLATTEN_OBJECT, "Can not get remote"); + + MessageParcel data; + data.WriteInt32(static_cast(service)); + MessageParcel reply; + MessageOption option; + int32_t res = remote->SendRequest(CANCEL, data, reply, option); + ENGINE_CHECK(res == ERR_OK, return ERR_FLATTEN_OBJECT, "Transact error res %d", res); + + int32_t result = -1; + bool ret = reply.ReadInt32(result); + ENGINE_CHECK(ret, return ERR_FLATTEN_OBJECT, "Failed to read result"); + return result; +} + +int32_t UpdateServiceProxy::RebootAndClean(const std::string &miscFile, const std::string &cmd) +{ + ENGINE_LOGI("UpdateServiceProxy::RebootAndCleanUserData"); + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return ERR_FLATTEN_OBJECT, "Can not get remote"); + + MessageParcel data; + data.WriteString16(Str8ToStr16(miscFile)); + data.WriteString16(Str8ToStr16(cmd)); + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(REBOOT_CLEAN, data, reply, option); + ENGINE_CHECK(ret == ERR_OK, return ERR_FLATTEN_OBJECT, "Transact error"); + return reply.ReadInt32(); +} + +int32_t UpdateServiceProxy::RebootAndInstall(const std::string &miscFile, const std::string &packageName) +{ + ENGINE_LOGI("UpdateServiceProxy::RebootAndCleanUserData"); + auto remote = Remote(); + ENGINE_CHECK(remote != nullptr, return ERR_FLATTEN_OBJECT, "Can not get remote"); + + MessageParcel data; + data.WriteString16(Str8ToStr16(miscFile)); + data.WriteString16(Str8ToStr16(packageName)); + MessageParcel reply; + MessageOption option; + int32_t ret = remote->SendRequest(REBOOT_INSTALL, data, reply, option); + ENGINE_CHECK(ret == ERR_OK, return ERR_FLATTEN_OBJECT, "Transact error"); + return reply.ReadInt32(); +} +} +} // namespace OHOS diff --git a/interfaces/innerkits/include/iupdate_callback.h b/interfaces/innerkits/include/iupdate_callback.h new file mode 100755 index 0000000..f17dbe4 --- /dev/null +++ b/interfaces/innerkits/include/iupdate_callback.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IUPDATER_CALLBACK_H +#define IUPDATER_CALLBACK_H + +#include +#include "update_helper.h" +#include "iremote_broker.h" +#include "iremote_proxy.h" + +namespace OHOS { +namespace update_engine { +class IUpdateCallback : public OHOS::IRemoteBroker { +public: + virtual ~IUpdateCallback() = default; + enum { + CHECK_VERSION = 1, + DOWNLOAD, + UPGRADE, + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.Update.IUpdateCallback"); +public: + virtual void OnCheckVersionDone(const VersionInfo &info) = 0; + + virtual void OnDownloadProgress(const Progress &progress) = 0; + + virtual void OnUpgradeProgress(const Progress &progress) = 0; +}; +} // namespace update_engine +} // namespace OHOS +#endif // IUPDATER_CALLBACK_H diff --git a/interfaces/innerkits/include/iupdate_service.h b/interfaces/innerkits/include/iupdate_service.h new file mode 100755 index 0000000..326b169 --- /dev/null +++ b/interfaces/innerkits/include/iupdate_service.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IUPDATER_SERVICE_H +#define IUPDATER_SERVICE_H + +#include +#include "update_helper.h" +#include "iremote_broker.h" +#include "iremote_proxy.h" +#include "iupdate_callback.h" + +namespace OHOS { +namespace update_engine { +class IUpdateService : public OHOS::IRemoteBroker { +public: + enum { + CHECK_VERSION = 1, + DOWNLOAD, + UPGRADE, + SET_POLICY, + GET_POLICY, + GET_NEW_VERSION, + GET_STATUS, + REGISTER_CALLBACK, + UNREGISTER_CALLBACK, + CANCEL, + REBOOT_CLEAN, + REBOOT_INSTALL, + VERIFY_PACKAGE + }; + + DECLARE_INTERFACE_DESCRIPTOR(u"OHOS.Updater.IUpdateService"); +public: + virtual int32_t RegisterUpdateCallback(const UpdateContext &ctx, const sptr& updateCallback) = 0; + + virtual int32_t UnregisterUpdateCallback() = 0; + + virtual int32_t CheckNewVersion() = 0; + + virtual int32_t DownloadVersion() = 0; + + virtual int32_t DoUpdate() = 0; + + virtual int32_t GetNewVersion(VersionInfo &versionInfo) = 0; + + virtual int32_t GetUpgradeStatus (UpgradeInfo &info) = 0; + + virtual int32_t SetUpdatePolicy(const UpdatePolicy &policy) = 0; + + virtual int32_t GetUpdatePolicy(UpdatePolicy &policy) = 0; + + virtual int32_t Cancel(int32_t service) = 0; + + virtual int32_t RebootAndClean(const std::string &miscFile, const std::string &cmd) = 0; + + virtual int32_t RebootAndInstall(const std::string &miscFile, const std::string &packageName) = 0; +}; +} // namespace update_engine +} // namespace OHOS +#endif // IUPDATER_SERVICE_H diff --git a/interfaces/innerkits/include/update_helper.h b/interfaces/innerkits/include/update_helper.h new file mode 100755 index 0000000..e125e6a --- /dev/null +++ b/interfaces/innerkits/include/update_helper.h @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UPDATER_HELPER_H +#define UPDATER_HELPER_H + +#include +#include +#include +#include +#include +#include +#include +#include "parcel.h" +#include "message_parcel.h" +#include "hilog/log.h" +#include "system_ability_definition.h" + +namespace OHOS { +namespace update_engine { +// 搜索状态 +enum SearchStatus { + SYSTEM_ERROR = -1, + HAS_NEW_VERSION, + NO_NEW_VERSION, + SERVER_BUSY, +}; + +enum UpgradeStatus { + UPDATE_STATE_INIT = 0, + UPDATE_STATE_CHECK_VERSION_ON = 10, + UPDATE_STATE_CHECK_VERSION_FAIL, + UPDATE_STATE_CHECK_VERSION_SUCCESS, + UPDATE_STATE_DOWNLOAD_ON = 20, + UPDATE_STATE_DOWNLOAD_PAUSE, + UPDATE_STATE_DOWNLOAD_CANCEL, + UPDATE_STATE_DOWNLOAD_FAIL, + UPDATE_STATE_DOWNLOAD_SUCCESS, + UPDATE_STATE_VERIFY_ON = 30, + UPDATE_STATE_VERIFY_FAIL, + UPDATE_STATE_VERIFY_SUCCESS, + UPDATE_STATE_PACKAGE_TRANS_ON = 70, + UPDATE_STATE_PACKAGE_TRANS_FAIL, + UPDATE_STATE_PACKAGE_TRANS_SUCCESS, + UPDATE_STATE_INSTALL_ON = 80, + UPDATE_STATE_INSTALL_FAIL, + UPDATE_STATE_INSTALL_SUCCESS, + UPDATE_STATE_UPDATE_ON = 90, + UPDATE_STATE_UPDATE_FAIL, + UPDATE_STATE_UPDATE_SUCCESS +}; + +enum PackageType { + PACKAGE_TYPE_NORMAL = 1, + PACKAGE_TYPE_BASE = 2, + PACKAGE_TYPE_CUST = 3, + PACKAGE_TYPE_PRELOAD = 4, + PACKAGE_TYPE_COTA = 5, + PACKAGE_TYPE_VERSION = 6, + PACKAGE_TYPE_PATCH = 7 +}; + +struct UpdateContext { + std::string upgradeDevId; + std::string controlDevId; + std::string upgradeApp; + std::string upgradeFile; + std::string type; +}; + +struct DescriptInfo { + std::string descriptPackageId; + std::string content; +}; + +struct CheckResult { + size_t size; + PackageType packageType; + std::string versionName; + std::string versionCode; + std::string verifyInfo; + std::string descriptPackageId; +}; + +struct VersionInfo { + SearchStatus status; + std::string errMsg; + CheckResult result[2]; + DescriptInfo descriptInfo[2]; +}; + +struct Progress { + uint32_t percent; + UpgradeStatus status; + std::string endReason; +}; + +struct UpgradeInfo { + UpgradeStatus status; +}; + +enum InstallMode { + INSTALLMODE_NORMAL = 0, + INSTALLMODE_NIGHT, + INSTALLMODE_AUTO +}; + +enum AutoUpgradeCondition { + AUTOUPGRADECONDITION_IDLE = 0, +}; + +struct UpdatePolicy { + bool autoDownload; + bool autoDownloadNet; + InstallMode mode; + AutoUpgradeCondition autoUpgradeCondition; + uint32_t autoUpgradeInterval[2]; +}; + +using CheckNewVersionDone = std::function; +using DownloadProgress = std::function; +using UpgradeProgress = std::function; + +// 回调函数 +struct UpdateCallbackInfo { + CheckNewVersionDone checkNewVersionDone; + DownloadProgress downloadProgress; + UpgradeProgress upgradeProgress; +}; + +#ifdef UPDATE_SERVICE +static constexpr OHOS::HiviewDFX::HiLogLabel UPDATE_LABEL = {LOG_CORE, 0, "UPDATE_SA"}; +#else +static constexpr OHOS::HiviewDFX::HiLogLabel UPDATE_LABEL = {LOG_CORE, 0, "UPDATE_KITS"}; +#endif + +enum class UpdateLogLevel { + UPDATE_DEBUG = 0, + UPDATE_INFO, + UPDATE_WARN, + UPDATE_ERROR, + UPDATE_FATAL +}; + +class UpdateHelper { +public: + static int32_t WriteUpdateContext(MessageParcel &data, const UpdateContext &info); + static int32_t ReadUpdateContext(MessageParcel &reply, UpdateContext &info); + + static int32_t ReadVersionInfo(MessageParcel &reply, VersionInfo &info); + static int32_t WriteVersionInfo(MessageParcel &data, const VersionInfo &info); + + static int32_t WriteUpdatePolicy(MessageParcel &data, const UpdatePolicy &policy); + static int32_t ReadUpdatePolicy(MessageParcel &reply, UpdatePolicy &policy); + + static int32_t ReadUpgradeInfo(MessageParcel &reply, UpgradeInfo &info); + static int32_t WriteUpgradeInfo(MessageParcel &reply, const UpgradeInfo &info); + + static int32_t ReadUpdateProgress(MessageParcel &reply, Progress &info); + static int32_t WriteUpdateProgress(MessageParcel &data, const Progress &info); + + static int32_t CopyVersionInfo(const VersionInfo &srcInfo, VersionInfo &dstInfo); + static int32_t CopyUpdatePolicy(const UpdatePolicy &srcInfo, UpdatePolicy &dstInfo); + + static std::vector HexToDegist(const std::string &str); + static int32_t CompareVersion(const std::string &version1, const std::string &version2); + static std::vector SplitString(const std::string &str, const std::string &delimiter); + + static void Logger(const std::string &fileName, int32_t line, const char *format, ...); + + static bool JudgeLevel(const UpdateLogLevel& level); + + static void SetLogLevel(const UpdateLogLevel& level) + { + level_ = level; + } + + static const UpdateLogLevel& GetLogLevel() + { + return level_; + } + + static std::string GetBriefFileName(const std::string &file); + +private: + static UpdateLogLevel level_; +}; + +// 暂时记录两边日志 +#define PRINT_LOG(LEVEL, Level, fmt, ...) \ + UpdateHelper::Logger(__FILE__, (__LINE__), fmt, ##__VA_ARGS__); \ + if (UpdateHelper::JudgeLevel(UpdateLogLevel::LEVEL)) \ + OHOS::HiviewDFX::HiLog::Level(UPDATE_LABEL, "[%{public}s(%{public}d)] " fmt, \ + UpdateHelper::GetBriefFileName(std::string(__FILE__)).c_str(), __LINE__, ##__VA_ARGS__) + +#define ENGINE_LOGI(fmt, ...) PRINT_LOG(UPDATE_INFO, Info, fmt, ##__VA_ARGS__) +#define ENGINE_LOGE(fmt, ...) PRINT_LOG(UPDATE_ERROR, Error, fmt, ##__VA_ARGS__) + +#define ENGINE_CHECK(retCode, exper, ...) \ + do { \ + if (!(retCode)) { \ + ENGINE_LOGE(__VA_ARGS__); \ + exper; \ + } \ + } while (0) +} +} // namespace OHOS +#endif // UPDATER_HELPER_H \ No newline at end of file diff --git a/interfaces/innerkits/include/update_service_kits.h b/interfaces/innerkits/include/update_service_kits.h new file mode 100755 index 0000000..43f5c6c --- /dev/null +++ b/interfaces/innerkits/include/update_service_kits.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UPDATER_SERVICE_KITS_H +#define UPDATER_SERVICE_KITS_H + +#include +#include "iupdate_service.h" +#include "update_helper.h" + +namespace OHOS { +namespace update_engine { +class UpdateServiceKits { +public: + UpdateServiceKits() = default; + virtual ~UpdateServiceKits() = default; + DISALLOW_COPY_AND_MOVE(UpdateServiceKits); + + /** + * Get instance of ohos account manager. + * + * @return Instance of ohos account manager. + */ + static UpdateServiceKits& GetInstance(); + + virtual int32_t RegisterUpdateCallback(const UpdateContext &ctx, const UpdateCallbackInfo &cb) = 0; + + virtual int32_t UnregisterUpdateCallback() = 0; + + virtual int32_t CheckNewVersion() = 0; + + virtual int32_t DownloadVersion() = 0; + + virtual int32_t DoUpdate() = 0; + + virtual int32_t GetNewVersion(VersionInfo &versionInfo) = 0; + + virtual int32_t GetUpgradeStatus (UpgradeInfo &info) = 0; + + virtual int32_t SetUpdatePolicy(const UpdatePolicy &policy) = 0; + + virtual int32_t GetUpdatePolicy(UpdatePolicy &policy) = 0; + + virtual int32_t Cancel(int32_t service) = 0; + + virtual int32_t RebootAndClean(const std::string &miscFile, const std::string &cmd) = 0; + + virtual int32_t RebootAndInstall(const std::string &miscFile, const std::string &packageName) = 0; +}; +} // namespace update_engine +} // namespace OHOS +#endif // UPDATER_SERVICE_KITS_H diff --git a/interfaces/innerkits/include/update_service_kits_impl.h b/interfaces/innerkits/include/update_service_kits_impl.h new file mode 100755 index 0000000..ac1b056 --- /dev/null +++ b/interfaces/innerkits/include/update_service_kits_impl.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef UPDATER_SERVICE_KITS_IMPL_H +#define UPDATER_SERVICE_KITS_IMPL_H + +#include "update_service_kits.h" +#include "update_helper.h" +#include "singleton.h" +#include "iupdate_callback.h" +#include "update_callback.h" + +namespace OHOS { +namespace update_engine { +class UpdateServiceKitsImpl final : public UpdateServiceKits, + public DelayedRefSingleton { + DECLARE_DELAYED_REF_SINGLETON(UpdateServiceKitsImpl); +public: + DISALLOW_COPY_AND_MOVE(UpdateServiceKitsImpl); + + int32_t RegisterUpdateCallback(const UpdateContext &ctx, const UpdateCallbackInfo &cb) final; + + int32_t UnregisterUpdateCallback() final; + + int32_t CheckNewVersion() final; + + int32_t DownloadVersion() final; + + int32_t DoUpdate() final; + + int32_t GetNewVersion(VersionInfo &versionInfo) final; + + int32_t GetUpgradeStatus(UpgradeInfo &info) final; + + int32_t SetUpdatePolicy(const UpdatePolicy &policy) final; + + int32_t GetUpdatePolicy(UpdatePolicy &policy) final; + + int32_t Cancel(int32_t service); + + int32_t RebootAndClean(const std::string &miscFile, const std::string &cmd) final; + + int32_t RebootAndInstall(const std::string &miscFile, const std::string &packageName) final; +#ifndef UPDATER_UT +private: +#else +public: +#endif + // For call event procession + class RemoteUpdateCallback final : public UpdateCallback { + public: + RemoteUpdateCallback(const UpdateCallbackInfo &cb); + ~RemoteUpdateCallback(); + + DISALLOW_COPY_AND_MOVE(RemoteUpdateCallback); + + void OnCheckVersionDone(const VersionInfo &info) final; + + void OnDownloadProgress(const Progress &progress) final; + + void OnUpgradeProgress(const Progress &progress) final; + private: + UpdateCallbackInfo updateCallback_ {}; + }; + + // For death event procession + class DeathRecipient final : public IRemoteObject::DeathRecipient { + public: + DeathRecipient() = default; + ~DeathRecipient() final = default; + DISALLOW_COPY_AND_MOVE(DeathRecipient); + void OnRemoteDied(const wptr& remote) final; + }; + void ResetService(const wptr& remote); + sptr GetService(); + std::mutex updateServiceLock_; + sptr updateService_ {}; + sptr deathRecipient_ {}; + sptr remoteUpdateCallback_ {}; + UpdateContext updateContext_ {}; +}; +} // namespace update_engine +} // namespace OHOS +#endif // UPDATER_SERVICE_KITS_IMPL_H diff --git a/interfaces/kits/js/declaration/@ohos.update.d.ts b/interfaces/kits/js/declaration/@ohos.update.d.ts new file mode 100644 index 0000000..c781062 --- /dev/null +++ b/interfaces/kits/js/declaration/@ohos.update.d.ts @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AsyncCallback, BussinessError } from "./basic"; + +/** + * A static class to do update for device. + * + * @devices all + * @since 6 + * @Syscap SystemCapability.Updater.Raw + */ +declare namespace update { + /** + * Enumerates new version package types. + * + * @since 6 + */ + export enum PackageTypes { + PACKAGE_TYPE_NORMAL = 1, + PACKAGE_TYPE_BASE = 2, + PACKAGE_TYPE_CUST = 3, + PACKAGE_TYPE_PRELOAD = 4, + PACKAGE_TYPE_COTA = 5, + PACKAGE_TYPE_VERSION = 6, + PACKAGE_TYPE_PATCH = 7 + } + + /** + * Represents new version results after update version check. + * + * @since 6 + */ + export interface CheckResult { + /** + * New version name + * + * @since 6 + */ + versionName: number; + + /** + * New version code + * + * @since 6 + */ + versionCode: string; + + /** + * New version package size + * + * @since 6 + */ + size: number; + + /** + * New version verify information + * + * @since 6 + */ + verifyInfo: string; + + /** + * New version package type + * + * @since 6 + */ + packageType: PackageTypes; + + /** + * New version description ID + * + * @since 6 + */ + descriptionId: string; + } + + /** + * Represents new version description information. + * + * @since 6 + */ + export interface DescriptionInfo { + /** + * description ID + * + * @since 6 + */ + descriptionId: string; + + /** + * description content + * + * @since 6 + */ + content: string; + } + + /** + * Enumerates new version status. + * + * @since 6 + */ + export enum NewVersionStatus { + /** + * New version check with system error + * + * @since 6 + */ + VERSION_STATUS_ERR = -1, + + /** + * New version detected + * + * @since 6 + */ + VERSION_STATUS_NEW = 0, + + /** + * No New version + * + * @since 6 + */ + VERSION_STATUS_NONE = 1, + + /** + * Server busy + * + * @since 6 + */ + VERSION_STATUS_BUSY = 2 + } + + /** + * Represents new version information. + * + * @since 6 + */ + export interface NewVersionInfo { + /** + * Update Check Status + * + * @since 6 + */ + status: NewVersionStatus; + + /** + * New version check error message + * + * @since 6 + */ + errMsg: string; + + /** + * New version check results + * + * @since 6 + */ + checkResults: Array; + + /** + * New version check description + * + * @since 6 + */ + descriptionInfo: Array; + } + + /** + * Enumerates update status. + * + * @since 6 + */ + export enum UpdateState { + UPDATE_STATE_INIT = 0, + UPDATE_STATE_CHECK_VERSION_ON = 10, + UPDATE_STATE_CHECK_VERSION_FAIL, + UPDATE_STATE_CHECK_VERSION_SUCCESS, + UPDATE_STATE_DOWNLOAD_ON = 20, + UPDATE_STATE_DOWNLOAD_PAUSE, + UPDATE_STATE_DOWNLOAD_CANCEL, + UPDATE_STATE_DOWNLOAD_FAIL, + UPDATE_STATE_DOWNLOAD_SUCCESS, + UPDATE_STATE_VERIFY_ON = 30, + UPDATE_STATE_VERIFY_FAIL, + UPDATE_STATE_VERIFY_SUCCESS, + UPDATE_STATE_PACKAGE_TRANS_ON = 70, + UPDATE_STATE_PACKAGE_TRANS_FAIL, + UPDATE_STATE_PACKAGE_TRANS_SUCCESS, + UPDATE_STATE_INSTALL_ON = 80, + UPDATE_STATE_INSTALL_FAIL, + UPDATE_STATE_INSTALL_SUCCESS, + UPDATE_STATE_UPDATE_ON = 90, + UPDATE_STATE_UPDATE_FAIL, + UPDATE_STATE_UPDATE_SUCCESS + } + + /** + * Represents update progress information. + * + * @since 6 + */ + export interface Progress { + /** + * update progress percent + * + * @since 6 + */ + percent: number; + + /** + * update status + * + * @since 6 + */ + status: UpdateState; + + /** + * update end reason + * + * @since 6 + */ + endReason: string; + } + + /** + * Enumerates install mode for new version packages. + * + * @since 6 + */ + export enum InstallMode { + /** + * Normal update. + * + * @since 6 + */ + INSTALL_MODE_NORMAL, + + /** + * Update at night + * + * @since 6 + */ + INSTALL_MODE_NIGHT, + + /** + * Auto update + * + * @since 6 + */ + INSTALL_MODE_AUTO + } + + /** + * Represents update policy. + * + * @since 6 + */ + export interface UpdatePolicy { + /** + * Enable auto download new packages or not + * + * @since 6 + */ + autoDownload: boolean; + + /** + * New packages auto installation mode + * + * @since 6 + */ + installMode: INSTALL_MODE; + + /** + * Auto installation time interval + * + * @since 6 + */ + autoUpgradeInterval: Array; + } + + /** + * Called when the signal status changes. You need to implement this method in a child class. + * Unlike {@code onSignalStatus(status: number)}, a signal source is specified in this method. + * + * @param status Indicates the signal status. + * The value {@code 0} indicates that the signal is stable, + * {@code 1} indicates that no signal is available, + * {@code 2} indicates that the signal is not supported, + * and {@code 3} indicates that the signal is unstable. + * @param source Indicates the signal source. For details about available values, + * see {@link @system.tv.SourceIndices}. + * @since 6 + */ + export interface UpdateProgressCallback { + (progress: Progress): void; + } + + /** + * A static class to do update for the specified device. + * + * @devices all + * @since 6 + * @Syscap SystemCapability.Updater.Raw + */ + export interface Updater { + /** + * Check new version. + * + * @since 6 + */ + checkNewVersion(callback: AsyncCallback): void; + checkNewVersion(): Promise; + + /** + * Trigger download new version packages. + * apps should listen to downloadProgress event + * + * @since 6 + */ + download(): void; + + /** + * Install packages for the device. + * apps should listen to upgradeProgress event + * + * @since 6 + */ + upgrade(): void; + + /** + * Get new version information for the newly installed package. + * + * @since 6 + */ + getNewVersionInfo(callback: AsyncCallback): void; + getNewVersionInfo(): Promise; + + /** + * Get current update policy. + * + * @since 6 + */ + getUpdatePolicy(callback: AsyncCallback): void; + getUpdatePolicy(): Promise; + + /** + * Set update policy. + * + * @since 6 + */ + setUpdatePolicy(policy: UpdatePolicy, callback: AsyncCallback): void; + setUpdatePolicy(policy: UpdatePolicy): Promise; + + /** + * Reboot to apply upgrade package. + * + * @since 6 + */ + applyNewVersion(callback: AsyncCallback): void; + applyNewVersion(): Promise; + + /** + * Reboot to clean cache. + * + * @since 6 + */ + rebootAndCleanCache(callback: AsyncCallback): void; + rebootAndCleanCache(): Promise; + + /** + * verify update package. + * apps should listen to verifyProgress event + * + * @since 6 + */ + verifyUpdatePackage(upgradeFile: string, certsFile: string): void; + + /** + * Subscribe to download/upgrade/verify progress events + * + * @since 6 + */ + on(eventType: 'downloadProgress', callback: UpdateProgressCallback): void; + on(eventType: 'upgradeProgress', callback: UpdateProgressCallback): void; + on(eventType: 'verifyProgress', callback: UpdateProgressCallback): void; + + /** + * Unsubscribe to download/upgrade/verify progress events + * + * @since 6 + */ + off(eventType: 'downloadProgress', callback?: UpdateProgressCallback): void; + off(eventType: 'upgradeProgress', callback?: UpdateProgressCallback): void; + off(eventType: 'verifyProgress', callback?: UpdateProgressCallback): void; + } + + export type UpdateTypes = + 'OTA' | + 'patch'; + + /** + * Get Updater handler for the calling device. + * + * @return Updater handler to perform actual update + * @since 6 + */ + function getUpdater(upgradeFile: string, updateType?: UpdateTypes): Updater; + + /** + * Get Updater handler for the specified device. + * + * @return Updater handler to perform actual update + * @since 6 + */ + function getUpdaterForOther(upgradeFile: string, device: string, updateType?: UpdateTypes): Updater; + + /** + * Get Updater handler from other device to trigger update for the calling device. + * + * @return Updater handler to perform actual update + * @since 6 + */ + function getUpdaterFromOther(upgradeFile: string, device: string, updateType?: UpdateTypes): Updater; +} + +export default update;