• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "downgrade_download_napi.h"
17 
18 #include <cstddef>
19 #include <sys/types.h>
20 
21 #include "async_work.h"
22 #include "cloud_sync_manager.h"
23 #include "dfs_error.h"
24 #include "dfsu_access_token_helper.h"
25 #include "utils_log.h"
26 
27 namespace OHOS::FileManagement::CloudSync {
28 using namespace FileManagement::LibN;
29 using namespace std;
CheckPermissions(const string & permission,bool isSystemApp)30 static int32_t CheckPermissions(const string &permission, bool isSystemApp)
31 {
32     if (!permission.empty() && !DfsuAccessTokenHelper::CheckCallerPermission(permission)) {
33         LOGE("permission denied");
34         return E_PERMISSION_DENIED;
35     }
36     if (isSystemApp && !DfsuAccessTokenHelper::IsSystemApp()) {
37         LOGE("caller hap is not system hap");
38         return E_PERMISSION_SYSTEM;
39     }
40     return E_OK;
41 }
42 
DowngradeDlCallbackImpl(napi_env env,napi_value func)43 DowngradeDlCallbackImpl::DowngradeDlCallbackImpl(napi_env env, napi_value func) : env_(env)
44 {
45     napi_status status = napi_create_reference(env_, func, 1, &cbOnRef_);
46     if (status != napi_ok) {
47         LOGE("Failed to create napi ref, %{public}d", status);
48     }
49 }
50 
~DowngradeDlCallbackImpl()51 DowngradeDlCallbackImpl::~DowngradeDlCallbackImpl()
52 {
53     if (cbOnRef_ != nullptr) {
54         napi_status status = napi_delete_reference(env_, cbOnRef_);
55         if (status != napi_ok) {
56             LOGE("Failed to delete napi ref, %{public}d", status);
57         }
58         cbOnRef_ = nullptr;
59     }
60 }
61 
ConvertToValue()62 napi_value DowngradeDlCallbackImpl::ConvertToValue()
63 {
64     napi_value progressVal = NClass::InstantiateClass(env_, DowngradeProgressNapi::className_, {});
65     if (progressVal == nullptr) {
66         LOGE("Failed to instantiate class");
67         return nullptr;
68     }
69     auto progressEntity = NClass::GetEntityOf<DowngradeProgressEntity>(env_, progressVal);
70     if (progressEntity == nullptr) {
71         LOGE("Failed to get progressEntity.");
72         return nullptr;
73     }
74 
75     progressEntity->progress = dlProgress_;
76     return progressVal;
77 }
78 
UpdateDownloadProgress(const DowngradeProgress & progress)79 void DowngradeDlCallbackImpl::UpdateDownloadProgress(const DowngradeProgress &progress)
80 {
81     if (dlProgress_ == nullptr) {
82         dlProgress_ = std::make_shared<SingleBundleProgress>();
83     }
84 
85     dlProgress_->state = static_cast<int32_t>(progress.state);
86     dlProgress_->downloadedSize = progress.downloadedSize;
87     dlProgress_->totalSize = progress.totalSize;
88     dlProgress_->successfulCount = progress.successfulCount;
89     dlProgress_->failedCount = progress.failedCount;
90     dlProgress_->totalCount = progress.totalCount;
91     dlProgress_->stopReason = static_cast<int32_t>(progress.stopReason);
92 }
93 
OnDownloadProcess(const DowngradeProgress & progress)94 void DowngradeDlCallbackImpl::OnDownloadProcess(const DowngradeProgress &progress)
95 {
96     UpdateDownloadProgress(progress);
97     std::shared_ptr<DowngradeDlCallbackImpl> callbackImpl = shared_from_this();
98     napi_status status = napi_send_event(
99         callbackImpl->env_,
100         [callbackImpl]() mutable {
101             auto env = callbackImpl->env_;
102             auto ref = callbackImpl->cbOnRef_;
103             if (env == nullptr || ref == nullptr) {
104                 LOGE("The env context is invalid");
105                 return;
106             }
107             napi_handle_scope scope = nullptr;
108             napi_status status = napi_open_handle_scope(env, &scope);
109             if (status != napi_ok) {
110                 LOGE("Failed to open handle scope, status: %{public}d", status);
111                 return;
112             }
113             napi_value jsCallback = nullptr;
114             status = napi_get_reference_value(env, ref, &jsCallback);
115             if (status != napi_ok) {
116                 LOGE("Create reference failed, status: %{public}d", status);
117                 napi_close_handle_scope(env, scope);
118                 return;
119             }
120             napi_value jsProgress = callbackImpl->ConvertToValue();
121             if (jsProgress == nullptr) {
122                 napi_close_handle_scope(env, scope);
123                 return;
124             }
125             napi_value jsResult = nullptr;
126             status = napi_call_function(env, nullptr, jsCallback, 1, &jsProgress, &jsResult);
127             if (status != napi_ok) {
128                 LOGE("napi call function failed, status: %{public}d", status);
129             }
130             napi_close_handle_scope(env, scope);
131         },
132         napi_eprio_immediate);
133     if (status != napi_ok) {
134         LOGE("Failed to execute libuv work queue, status: %{public}d", status);
135     }
136 }
137 
Constructor(napi_env env,napi_callback_info info)138 napi_value DowngradeDownloadNapi::Constructor(napi_env env, napi_callback_info info)
139 {
140     NFuncArg funcArg(env, info);
141     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
142         LOGE("Start Number of arguments unmatched");
143         NError(EINVAL).ThrowErr(env);
144         return nullptr;
145     }
146     int32_t ret = CheckPermissions(PERM_CLOUD_SYNC_MANAGER, true);
147     if (ret != E_OK) {
148         NError(Convert2JsErrNum(ret)).ThrowErr(env);
149         return nullptr;
150     }
151     auto [succ, bundle, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
152     std::string bundleName(bundle.get());
153     if (!succ || bundleName.empty()) {
154         LOGE("Failed to get bundleName.");
155         NError(EINVAL).ThrowErr(env);
156         return nullptr;
157     }
158     auto downgradeEntity = make_unique<DowngradeEntity>(bundleName);
159     if (!NClass::SetEntityFor<DowngradeEntity>(env, funcArg.GetThisVar(), move(downgradeEntity))) {
160         LOGE("Failed to set file cache entity.");
161         NError(EINVAL).ThrowErr(env);
162         return nullptr;
163     }
164 
165     return funcArg.GetThisVar();
166 }
167 
ToExport(std::vector<napi_property_descriptor> props)168 bool DowngradeDownloadNapi::ToExport(std::vector<napi_property_descriptor> props)
169 {
170     std::string className = GetClassName();
171     auto [succ, classValue] = NClass::DefineClass(exports_.env_, className, Constructor, std::move(props));
172     if (!succ) {
173         NError(Convert2JsErrNum(E_SERVICE_INNER_ERROR)).ThrowErr(exports_.env_);
174         LOGE("Failed to define GallerySync class");
175         return false;
176     }
177 
178     succ = NClass::SaveClass(exports_.env_, className, classValue);
179     if (!succ) {
180         NError(Convert2JsErrNum(E_SERVICE_INNER_ERROR)).ThrowErr(exports_.env_);
181         LOGE("Failed to save GallerySync class");
182         return false;
183     }
184 
185     return exports_.AddProp(className, classValue);
186 }
187 
Export()188 bool DowngradeDownloadNapi::Export()
189 {
190     std::vector<napi_property_descriptor> props = {
191         NVal::DeclareNapiFunction("startDownload", DowngradeDownloadNapi::StartDownload),
192         NVal::DeclareNapiFunction("stopDownload", DowngradeDownloadNapi::StopDownload),
193         NVal::DeclareNapiFunction("getCloudFileInfo", DowngradeDownloadNapi::GetCloudFileInfo),
194     };
195 
196     return ToExport(props);
197 }
198 
StartDownload(napi_env env,napi_callback_info info)199 napi_value DowngradeDownloadNapi::StartDownload(napi_env env, napi_callback_info info)
200 {
201     NFuncArg funcArg(env, info);
202     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
203         LOGE("Start Number of arguments unmatched");
204         NError(EINVAL).ThrowErr(env);
205         return nullptr;
206     }
207     NVal callbackVal(env, funcArg[NARG_POS::FIRST]);
208     if (!callbackVal.TypeIs(napi_function)) {
209         LOGE("Batch-On argument type mismatch");
210         NError(EINVAL).ThrowErr(env);
211         return nullptr;
212     }
213 
214     auto downgradeEntity = NClass::GetEntityOf<DowngradeEntity>(env, funcArg.GetThisVar());
215     if (!downgradeEntity) {
216         LOGE("Failed to get downgrade entity.");
217         NError(Convert2JsErrNum(E_SERVICE_INNER_ERROR)).ThrowErr(env);
218         return nullptr;
219     }
220 
221     if (downgradeEntity->callbackImpl == nullptr) {
222         downgradeEntity->callbackImpl = make_shared<DowngradeDlCallbackImpl>(env, callbackVal.val_);
223     }
224 
225     auto cbExec = [callbackImpl{downgradeEntity->callbackImpl}, bundleName{downgradeEntity->bundleName}]() -> NError {
226         if (callbackImpl == nullptr) {
227             LOGE("Failed to get download callback");
228             return NError(Convert2JsErrNum(E_SERVICE_INNER_ERROR));
229         }
230         int32_t ret = CloudSyncManager::GetInstance().StartDowngrade(bundleName, callbackImpl);
231         if (ret != E_OK) {
232             LOGE("Start downgrade failed! ret = %{public}d", ret);
233             return NError(Convert2JsErrNum(ret));
234         }
235 
236         LOGI("Start downgrade success!");
237         return NError(ERRNO_NOERR);
238     };
239 
240     auto cbCompl = [](napi_env env, NError err) -> NVal {
241         if (err) {
242             return {env, err.GetNapiErr(env)};
243         }
244         return NVal::CreateUndefined(env);
245     };
246 
247     string procedureName = "downgradeDownload";
248     auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast<size_t>(NARG_CNT::TWO));
249     return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbCompl).val_;
250 }
251 
StopDownload(napi_env env,napi_callback_info info)252 napi_value DowngradeDownloadNapi::StopDownload(napi_env env, napi_callback_info info)
253 {
254     NFuncArg funcArg(env, info);
255     funcArg.InitArgs(NARG_CNT::ZERO);
256     auto downgradeEntity = NClass::GetEntityOf<DowngradeEntity>(env, funcArg.GetThisVar());
257     if (!downgradeEntity || downgradeEntity->callbackImpl == nullptr) {
258         LOGE("Failed to get downgrade entity.");
259         NError(Convert2JsErrNum(E_SERVICE_INNER_ERROR)).ThrowErr(env);
260         return nullptr;
261     }
262 
263     auto cbExec = [bundleName{downgradeEntity->bundleName}]() -> NError {
264         int32_t ret = CloudSyncManager::GetInstance().StopDowngrade(bundleName);
265         if (ret != E_OK) {
266             LOGE("Stop downgrade failed! ret = %{public}d", ret);
267             return NError(Convert2JsErrNum(ret));
268         }
269         LOGI("Stop downgrade success!");
270         return NError(ERRNO_NOERR);
271     };
272 
273     auto cbCompl = [](napi_env env, NError err) -> NVal {
274         if (err) {
275             return {env, err.GetNapiErr(env)};
276         }
277         return NVal::CreateUndefined(env);
278     };
279 
280     string procedureName = "downgradeDownload";
281     auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast<size_t>(NARG_CNT::TWO));
282     return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbCompl).val_;
283 }
284 
GetCloudFileInfo(napi_env env,napi_callback_info info)285 napi_value DowngradeDownloadNapi::GetCloudFileInfo(napi_env env, napi_callback_info info)
286 {
287     NFuncArg funcArg(env, info);
288     funcArg.InitArgs(NARG_CNT::ZERO);
289     auto downgradeEntity = NClass::GetEntityOf<DowngradeEntity>(env, funcArg.GetThisVar());
290     if (!downgradeEntity) {
291         LOGE("Failed to get downgrade entity.");
292         NError(Convert2JsErrNum(E_SERVICE_INNER_ERROR)).ThrowErr(env);
293         return nullptr;
294     }
295 
296     auto fileInfo = std::make_shared<CloudFileInfo>();
297     std::string bundleName = downgradeEntity->bundleName;
298     auto cbExec = [bundleName{downgradeEntity->bundleName}, fileInfo]() -> NError {
299         int32_t ret = CloudSyncManager::GetInstance().GetCloudFileInfo(bundleName, *fileInfo);
300         if (ret != E_OK) {
301             LOGE("Start Download failed! ret = %{public}d", ret);
302             return NError(Convert2JsErrNum(ret));
303         }
304         LOGI("Start Download Success!");
305         return NError(ERRNO_NOERR);
306     };
307 
308     auto cbCompl = [fileInfo](napi_env env, NError err) -> NVal {
309         if (err) {
310             return {env, err.GetNapiErr(env)};
311         }
312         NVal obj = NVal::CreateObject(env);
313         obj.AddProp("cloudfileCount", NVal::CreateInt32(env, fileInfo->cloudfileCount).val_);
314         obj.AddProp("cloudFileTotalSize", NVal::CreateInt64(env, fileInfo->cloudFileTotalSize).val_);
315         obj.AddProp("localFileCount", NVal::CreateInt32(env, fileInfo->localFileCount).val_);
316         obj.AddProp("localFileTotalSize", NVal::CreateInt64(env, fileInfo->localFileTotalSize).val_);
317         obj.AddProp("bothFileCount", NVal::CreateInt32(env, fileInfo->bothFileCount).val_);
318         obj.AddProp("bothFileTotalSize", NVal::CreateInt64(env, fileInfo->bothFileTotalSize).val_);
319         return obj;
320     };
321 
322     string procedureName = "downgradeDownload";
323     auto asyncWork = GetPromiseOrCallBackWork(env, funcArg, static_cast<size_t>(NARG_CNT::ONE));
324     return asyncWork == nullptr ? nullptr : asyncWork->Schedule(procedureName, cbExec, cbCompl).val_;
325 }
326 
GetClassName()327 string DowngradeDownloadNapi::GetClassName()
328 {
329     return className_;
330 }
331 } // namespace OHOS::FileManagement::CloudSync