1 /*
2 * Copyright (c) 2022-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 "ext_backup_js.h"
17
18 #include <cstdio>
19 #include <memory>
20 #include <sstream>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23
24 #include "bundle_mgr_client.h"
25 #include "ext_backup_context_js.h"
26 #include "js_extension_context.h"
27 #include "js_native_api.h"
28 #include "js_native_api_types.h"
29 #include "js_runtime.h"
30 #include "js_runtime_utils.h"
31 #include "napi/native_api.h"
32 #include "napi/native_node_api.h"
33 #include "napi_common_util.h"
34 #include "napi_common_want.h"
35 #include "napi_remote_object.h"
36 #include "unique_fd.h"
37
38 #include "b_anony/b_anony.h"
39 #include "b_error/b_error.h"
40 #include "b_error/b_excep_utils.h"
41 #include "b_json/b_json_cached_entity.h"
42 #include "b_json/b_json_entity_extension_config.h"
43 #include "b_radar/b_radar.h"
44 #include "b_resources/b_constants.h"
45 #include "directory_ex.h"
46 #include "ext_extension.h"
47 #include "filemgmt_libhilog.h"
48
49 namespace OHOS::FileManagement::Backup {
50 using namespace std;
51 constexpr size_t ARGC_ONE = 1;
52 static std::mutex g_extBackupValidLock;
53 static int32_t g_extBackupCount = 0;
54
GetSrcPath(const AppExecFwk::AbilityInfo & info)55 static string GetSrcPath(const AppExecFwk::AbilityInfo &info)
56 {
57 using AbilityRuntime::Extension;
58 stringstream ss;
59
60 // API9(stage model) 中通过 $(module)$(name)/$(srcEntrance/(.*$)/(.abc)) 获取自定义插件路径
61 if (!info.srcEntrance.empty()) {
62 ss << info.moduleName << '/' << string(info.srcEntrance, 0, info.srcEntrance.rfind(".")) << ".abc";
63 return ss.str();
64 }
65 return "";
66 }
67
DealNapiStrValue(napi_env env,const napi_value napi_StrValue,std::string & result)68 static napi_status DealNapiStrValue(napi_env env, const napi_value napi_StrValue, std::string &result)
69 {
70 HILOGI("Start DealNapiStrValue");
71 std::string buffer = "";
72 size_t bufferSize = 0;
73 napi_status status = napi_ok;
74 status = napi_get_value_string_utf8(env, napi_StrValue, nullptr, -1, &bufferSize);
75 if (status != napi_ok) {
76 HILOGE("Can not get buffer size");
77 return status;
78 }
79 buffer.reserve(bufferSize + 1);
80 buffer.resize(bufferSize);
81 if (bufferSize > 0) {
82 status = napi_get_value_string_utf8(env, napi_StrValue, buffer.data(), bufferSize + 1, &bufferSize);
83 if (status != napi_ok) {
84 HILOGE("Can not get buffer value");
85 return status;
86 }
87 }
88 result = buffer;
89 return status;
90 }
91
DealNapiException(napi_env env,napi_value & exception,std::string & exceptionInfo)92 static napi_status DealNapiException(napi_env env, napi_value &exception, std::string &exceptionInfo)
93 {
94 HILOGI("call DealNapiException start.");
95 napi_status status = napi_get_and_clear_last_exception(env, &exception);
96 if (status != napi_ok) {
97 HILOGE("call napi_get_and_clear_last_exception failed.");
98 return status;
99 }
100 status = DealNapiStrValue(env, exception, exceptionInfo);
101 if (status != napi_ok) {
102 HILOGE("call DealNapiStrValue failed.");
103 return status;
104 }
105 HILOGI("call DealNapiException end, exception info = %{public}s.", exceptionInfo.c_str());
106 return status;
107 }
108
PromiseCallback(napi_env env,napi_callback_info info)109 static napi_value PromiseCallback(napi_env env, napi_callback_info info)
110 {
111 std::lock_guard<std::mutex> lock(g_extBackupValidLock);
112 if (g_extBackupCount <= 0) {
113 HILOGE("ExtBackup is invalid, count=%{public}d", g_extBackupCount);
114 return nullptr;
115 }
116 HILOGI("Promise callback.");
117 void *data = nullptr;
118 if (napi_get_cb_info(env, info, nullptr, 0, nullptr, &data) != napi_ok) {
119 HILOGE("Failed to get callback info.");
120 return nullptr;
121 }
122 auto *callbackInfo = static_cast<CallbackInfo *>(data);
123 if (callbackInfo == nullptr) {
124 HILOGE("CallbackInfo is nullptr");
125 return nullptr;
126 }
127 string str;
128 callbackInfo->callback(BError(BError::Codes::OK), str);
129 data = nullptr;
130 return nullptr;
131 }
132
PromiseCatchCallback(napi_env env,napi_callback_info info)133 static napi_value PromiseCatchCallback(napi_env env, napi_callback_info info)
134 {
135 HILOGI("Promise catch callback begin.");
136 size_t argc = 1;
137 napi_value argv = {nullptr};
138 void *data = nullptr;
139 NAPI_CALL_NO_THROW(napi_get_cb_info(env, info, &argc, &argv, nullptr, &data), nullptr);
140 string exceptionInfo;
141 DealNapiStrValue(env, argv, exceptionInfo);
142 HILOGI("Catch exception info is %{public}s.", exceptionInfo.c_str());
143 auto *callbackInfo = static_cast<CallbackInfo *>(data);
144 if (callbackInfo == nullptr) {
145 HILOGE("CallbackInfo is nullptr");
146 return nullptr;
147 }
148 napi_status throwStatus = napi_fatal_exception(env, argv);
149 if (throwStatus != napi_ok) {
150 HILOGE("Failed to throw an exception, %{public}d", throwStatus);
151 return nullptr;
152 }
153 std::lock_guard<std::mutex> lock(g_extBackupValidLock);
154 if (g_extBackupCount <= 0) {
155 HILOGE("ExtBackup is invalid, count=%{public}d", g_extBackupCount);
156 data = nullptr;
157 return nullptr;
158 }
159 callbackInfo->callback(BError(BError::Codes::EXT_THROW_EXCEPTION), exceptionInfo);
160 data = nullptr;
161 HILOGI("Promise catch callback end.");
162 return nullptr;
163 }
164
PromiseCallbackEx(napi_env env,napi_callback_info info)165 static napi_value PromiseCallbackEx(napi_env env, napi_callback_info info)
166 {
167 std::lock_guard<std::mutex> lock(g_extBackupValidLock);
168 if (g_extBackupCount <= 0) {
169 HILOGE("ExtBackup is invalid, count=%{public}d", g_extBackupCount);
170 return nullptr;
171 }
172 HILOGI("PromiseEx callback.");
173 void *data = nullptr;
174 std::string str;
175 size_t argc = 1;
176 napi_value argv = {nullptr};
177 NAPI_CALL_NO_THROW(napi_get_cb_info(env, info, &argc, &argv, nullptr, &data), nullptr);
178 auto *callbackInfoEx = static_cast<CallbackInfoEx *>(data);
179 if (callbackInfoEx == nullptr) {
180 HILOGE("CallbackInfo is nullPtr");
181 return nullptr;
182 }
183 DealNapiStrValue(env, argv, str);
184 callbackInfoEx->callbackParam(BError(BError::Codes::OK), str);
185 data = nullptr;
186 return nullptr;
187 }
188
PromiseCatchCallbackEx(napi_env env,napi_callback_info info)189 static napi_value PromiseCatchCallbackEx(napi_env env, napi_callback_info info)
190 {
191 HILOGI("PromiseEx catch callback begin.");
192 void *data = nullptr;
193 size_t argc = 1;
194 napi_value argv = {nullptr};
195 NAPI_CALL_NO_THROW(napi_get_cb_info(env, info, &argc, &argv, nullptr, &data), nullptr);
196 string exceptionInfo;
197 DealNapiStrValue(env, argv, exceptionInfo);
198 HILOGI("Catch exception info is %{public}s.", exceptionInfo.c_str());
199 auto *callbackInfoEx = static_cast<CallbackInfoEx *>(data);
200 if (callbackInfoEx == nullptr) {
201 HILOGE("CallbackInfo is nullPtr");
202 return nullptr;
203 }
204 napi_status throwStatus = napi_fatal_exception(env, argv);
205 if (throwStatus != napi_ok) {
206 HILOGE("Failed to throw an exception, %{public}d", throwStatus);
207 return nullptr;
208 }
209 std::lock_guard<std::mutex> lock(g_extBackupValidLock);
210 if (g_extBackupCount <= 0) {
211 HILOGE("ExtBackup is invalid, count=%{public}d", g_extBackupCount);
212 data = nullptr;
213 return nullptr;
214 }
215 callbackInfoEx->callbackParam(BError(BError::Codes::EXT_THROW_EXCEPTION), exceptionInfo);
216 data = nullptr;
217 HILOGI("PromiseEx catch callback end.");
218 return nullptr;
219 }
220
CheckPromise(napi_env env,napi_value value)221 static bool CheckPromise(napi_env env, napi_value value)
222 {
223 if (value == nullptr) {
224 HILOGE("CheckPromise, result is null, no need to call promise.");
225 return false;
226 }
227 bool isPromise = false;
228 if (napi_is_promise(env, value, &isPromise) != napi_ok) {
229 HILOGE("CheckPromise, result is not promise, no need to call promise.");
230 return false;
231 }
232 return isPromise;
233 }
234
CallCatchPromise(AbilityRuntime::JsRuntime & jsRuntime,napi_value result,CallbackInfo * callbackInfo)235 static bool CallCatchPromise(AbilityRuntime::JsRuntime &jsRuntime, napi_value result, CallbackInfo *callbackInfo)
236 {
237 HILOGI("CallCatchPromise Begin.");
238 AbilityRuntime::HandleScope handleScope(jsRuntime);
239 auto env = jsRuntime.GetNapiEnv();
240 napi_value method = nullptr;
241 if (napi_get_named_property(env, result, "catch", &method) != napi_ok) {
242 HILOGE("CallCatchPromise, Failed to get method catch");
243 return false;
244 }
245 bool isCallable = false;
246 if (napi_is_callable(env, method, &isCallable) != napi_ok) {
247 HILOGE("CallCatchPromise, Failed to check method then is callable");
248 return false;
249 }
250 if (!isCallable) {
251 HILOGE("CallCatchPromise, property then is not callable.");
252 return false;
253 }
254 napi_value ret;
255 if (napi_create_function(env, "promiseCatchCallback", strlen("promiseCatchCallback"), PromiseCatchCallback,
256 callbackInfo, &ret) != napi_ok) {
257 HILOGE("napi create function failed");
258 return false;
259 }
260 napi_value argv[1] = {ret};
261 if (napi_call_function(env, result, method, 1, argv, nullptr) != napi_ok) {
262 HILOGE("napi call function failed");
263 return false;
264 }
265 return true;
266 }
267
CallPromise(AbilityRuntime::JsRuntime & jsRuntime,napi_value result,CallbackInfo * callbackInfo)268 static bool CallPromise(AbilityRuntime::JsRuntime &jsRuntime, napi_value result, CallbackInfo *callbackInfo)
269 {
270 AbilityRuntime::HandleScope handleScope(jsRuntime);
271 auto env = jsRuntime.GetNapiEnv();
272 napi_value method = nullptr;
273 if (napi_get_named_property(env, result, "then", &method) != napi_ok) {
274 HILOGE("CallPromise, Failed to get method then");
275 return false;
276 }
277 bool isCallable = false;
278 if (napi_is_callable(env, method, &isCallable) != napi_ok) {
279 HILOGE("CallPromise, Failed to check method then is callable");
280 return false;
281 }
282 if (!isCallable) {
283 HILOGE("CallPromise, property then is not callable.");
284 return false;
285 }
286 napi_value ret;
287 if (napi_create_function(env, "promiseCallback", strlen("promiseCallback"), PromiseCallback, callbackInfo, &ret) !=
288 napi_ok) {
289 HILOGE("napi create function failed");
290 return false;
291 }
292 napi_value argv[1] = {ret};
293 if (napi_call_function(env, result, method, 1, argv, nullptr) != napi_ok) {
294 HILOGE("napi call function failed");
295 return false;
296 }
297 if (!CallCatchPromise(jsRuntime, result, callbackInfo)) {
298 HILOGE("CallCatchPromise failed.");
299 return false;
300 }
301 return true;
302 }
303
CallCatchPromiseEx(AbilityRuntime::JsRuntime & jsRuntime,napi_value result,CallbackInfoEx * callbackInfoEx)304 static bool CallCatchPromiseEx(AbilityRuntime::JsRuntime &jsRuntime, napi_value result, CallbackInfoEx *callbackInfoEx)
305 {
306 HILOGI("CallCatchPromiseEx Begin.");
307 AbilityRuntime::HandleScope handleScope(jsRuntime);
308 auto env = jsRuntime.GetNapiEnv();
309 napi_value method = nullptr;
310 if (napi_get_named_property(env, result, "catch", &method) != napi_ok) {
311 HILOGE("CallCatchPromiseEx, Failed to get method catch");
312 return false;
313 }
314 bool isCallable = false;
315 if (napi_is_callable(env, method, &isCallable) != napi_ok) {
316 HILOGE("CallCatchPromiseEx, Failed to check method then is callable");
317 return false;
318 }
319 if (!isCallable) {
320 HILOGE("CallCatchPromiseEx, property then is not callable.");
321 return false;
322 }
323 napi_value ret;
324 if (napi_create_function(env, "promiseCatchCallbackEx", strlen("promiseCatchCallbackEx"), PromiseCatchCallbackEx,
325 callbackInfoEx, &ret) != napi_ok) {
326 HILOGE("napi create function failed");
327 return false;
328 }
329 napi_value argv[1] = {ret};
330 if (napi_call_function(env, result, method, 1, argv, nullptr) != napi_ok) {
331 HILOGE("napi call function failed");
332 return false;
333 }
334 return true;
335 }
336
CallPromiseEx(AbilityRuntime::JsRuntime & jsRuntime,napi_value result,CallbackInfoEx * callbackInfoEx)337 static bool CallPromiseEx(AbilityRuntime::JsRuntime &jsRuntime, napi_value result, CallbackInfoEx *callbackInfoEx)
338 {
339 AbilityRuntime::HandleScope handleScope(jsRuntime);
340 auto env = jsRuntime.GetNapiEnv();
341 napi_value method = nullptr;
342 if (napi_get_named_property(env, result, "then", &method) != napi_ok) {
343 HILOGE("CallPromise, Failed to get method then");
344 return false;
345 }
346 bool isCallable = false;
347 if (napi_is_callable(env, method, &isCallable) != napi_ok) {
348 HILOGE("CallPromise, Failed to check method then is callable");
349 return false;
350 }
351 if (!isCallable) {
352 HILOGE("CallPromise, property then is not callable.");
353 return false;
354 }
355 napi_value ret;
356 if (napi_create_function(env, "promiseCallbackEx", strlen("promiseCallbackEx"), PromiseCallbackEx, callbackInfoEx,
357 &ret) != napi_ok) {
358 HILOGE("napi create function failed");
359 return false;
360 }
361 napi_value argv[1] = {ret};
362 if (napi_call_function(env, result, method, 1, argv, nullptr) != napi_ok) {
363 HILOGE("napi call function failed");
364 return false;
365 }
366 if (!CallCatchPromiseEx(jsRuntime, result, callbackInfoEx)) {
367 HILOGE("CallCatchPromiseEx failed.");
368 return false;
369 }
370 return true;
371 }
372
CallPromiseEx(AbilityRuntime::JsRuntime & jsRuntime,napi_value result,CallbackInfoBackup * callbackInfoBackup)373 static bool CallPromiseEx(AbilityRuntime::JsRuntime &jsRuntime, napi_value result,
374 CallbackInfoBackup *callbackInfoBackup)
375 {
376 AbilityRuntime::HandleScope handleScope(jsRuntime);
377 auto env = jsRuntime.GetNapiEnv();
378 napi_value method = nullptr;
379 if (napi_get_named_property(env, result, "then", &method) != napi_ok) {
380 HILOGE("CallPromise, Failed to get method then");
381 return false;
382 }
383 bool isCallable = false;
384 if (napi_is_callable(env, method, &isCallable) != napi_ok) {
385 HILOGE("CallPromise, Failed to check method then is callable");
386 return false;
387 }
388 if (!isCallable) {
389 HILOGE("CallPromise, property then is not callable.");
390 return false;
391 }
392 napi_value ret;
393 if (napi_create_function(env, "promiseCallbackEx", strlen("promiseCallbackEx"), PromiseCallbackEx,
394 callbackInfoBackup, &ret) != napi_ok) {
395 HILOGE("napi create function failed");
396 return false;
397 }
398 napi_value argv[1] = {ret};
399 if (napi_call_function(env, result, method, 1, argv, nullptr) != napi_ok) {
400 HILOGE("napi call function failed");
401 return false;
402 }
403 return true;
404 }
405
Init(const shared_ptr<AppExecFwk::AbilityLocalRecord> & record,const shared_ptr<AppExecFwk::OHOSApplication> & application,shared_ptr<AppExecFwk::AbilityHandler> & handler,const sptr<IRemoteObject> & token)406 void ExtBackupJs::Init(const shared_ptr<AppExecFwk::AbilityLocalRecord> &record,
407 const shared_ptr<AppExecFwk::OHOSApplication> &application,
408 shared_ptr<AppExecFwk::AbilityHandler> &handler,
409 const sptr<IRemoteObject> &token)
410 {
411 HILOGI("Init the BackupExtensionAbility(JS)");
412 try {
413 ExtBackup::Init(record, application, handler, token);
414 BExcepUltils::BAssert(abilityInfo_, BError::Codes::EXT_BROKEN_FRAMEWORK, "Invalid abilityInfo_");
415 // 获取应用扩展的 BackupExtensionAbility 的路径
416 const AppExecFwk::AbilityInfo &info = *abilityInfo_;
417 string bundleName = info.bundleName;
418 InitTempPath(bundleName);
419 string moduleName(info.moduleName + "::" + info.name);
420 string modulePath = GetSrcPath(info);
421 int moduleType = static_cast<int>(info.type);
422 HILOGI("Try to load %{public}s's %{public}s(type %{public}d) from %{public}s", bundleName.c_str(),
423 moduleName.c_str(), moduleType, modulePath.c_str());
424
425 // 加载用户扩展 BackupExtensionAbility 到 JS 引擎,并将之暂存在 jsObj_ 中。注意,允许加载失败,往后执行默认逻辑
426 AbilityRuntime::HandleScope handleScope(jsRuntime_);
427 jsObj_ = jsRuntime_.LoadModule(moduleName, modulePath, info.hapPath,
428 abilityInfo_->compileMode == AbilityRuntime::CompileMode::ES_MODULE, false,
429 abilityInfo_->srcEntrance);
430 if (jsObj_ == nullptr) {
431 HILOGW("Oops! There's no custom BackupExtensionAbility");
432 return;
433 }
434 HILOGI("Wow! Here's a custsom BackupExtensionAbility");
435 ExportJsContext();
436 } catch (const BError &e) {
437 HILOGE("%{public}s", e.what());
438 } catch (const exception &e) {
439 HILOGE("%{public}s", e.what());
440 }
441 }
442
AttachBackupExtensionContext(napi_env env,void * value,void *)443 napi_value AttachBackupExtensionContext(napi_env env, void *value, void *)
444 {
445 HILOGI("AttachBackupExtensionContext");
446 if (value == nullptr || env == nullptr) {
447 HILOG_WARN("invalid parameter.");
448 return nullptr;
449 }
450 auto ptr = reinterpret_cast<std::weak_ptr<ExtBackupContext> *>(value)->lock();
451 if (ptr == nullptr) {
452 HILOGE("invalid context.");
453 return nullptr;
454 }
455 auto object = CreateExtBackupJsContext(env, ptr);
456 if (object == nullptr) {
457 HILOGE("Failed to get js backup extension context");
458 return nullptr;
459 }
460 auto contextRef =
461 AbilityRuntime::JsRuntime::LoadSystemModuleByEngine(env, "application.BackupExtensionContext", &object, 1);
462 if (contextRef == nullptr) {
463 HILOGE("Failed to load BackupExtensionContext.");
464 return nullptr;
465 }
466 napi_value contextObj = contextRef->GetNapiValue();
467 napi_coerce_to_native_binding_object(env, contextObj, AbilityRuntime::DetachCallbackFunc,
468 AttachBackupExtensionContext, value, nullptr);
469
470 auto workContext = new (std::nothrow) std::weak_ptr<ExtBackupContext>(ptr);
471 if (workContext == nullptr) {
472 HILOGE("Failed to get backup extension context");
473 return nullptr;
474 }
475 napi_status status = napi_wrap(
476 env, contextObj, workContext,
477 [](napi_env, void *data, void *) {
478 HILOG_DEBUG("Finalizer for weak_ptr base context is called");
479 delete static_cast<std::weak_ptr<ExtBackupContext> *>(data);
480 },
481 nullptr, nullptr);
482 if (status != napi_ok) {
483 HILOG_DEBUG("Failed to wrap js instance");
484 delete workContext;
485 workContext = nullptr;
486 }
487 return contextObj;
488 }
489
ExtBackupJs(AbilityRuntime::JsRuntime & jsRuntime)490 ExtBackupJs::ExtBackupJs(AbilityRuntime::JsRuntime &jsRuntime) : jsRuntime_(jsRuntime)
491 {
492 std::lock_guard<std::mutex> lock(g_extBackupValidLock);
493 g_extBackupCount += 1;
494 HILOGI("ExtBackupJs::ExtBackupJs, count=%{public}d.", g_extBackupCount);
495 }
496
~ExtBackupJs()497 ExtBackupJs::~ExtBackupJs()
498 {
499 jsRuntime_.FreeNativeReference(std::move(jsObj_));
500 std::lock_guard<std::mutex> lock(g_extBackupValidLock);
501 g_extBackupCount -= 1;
502 HILOGI("ExtBackupJs::~ExtBackupJs, count=%{public}d.", g_extBackupCount);
503 }
504
ExportJsContext(void)505 void ExtBackupJs::ExportJsContext(void)
506 {
507 auto env = jsRuntime_.GetNapiEnv();
508 if (jsObj_ == nullptr) {
509 HILOGE("Failed to get js object.");
510 return;
511 }
512 napi_value obj = jsObj_->GetNapiValue();
513 if (obj == nullptr) {
514 HILOGE("Failed to get BackupExtAbility object");
515 return;
516 }
517
518 auto context = GetContext();
519 if (context == nullptr) {
520 HILOGE("Failed to get context");
521 return;
522 }
523
524 HILOGI("CreateBackupExtAbilityContext");
525 napi_value contextObj = CreateExtBackupJsContext(env, context);
526 auto contextRef = jsRuntime_.LoadSystemModule("application.BackupExtensionContext", &contextObj, ARGC_ONE);
527 if (!contextRef) {
528 HILOGE("context is nullptr");
529 return;
530 }
531 contextObj = contextRef->GetNapiValue();
532 HILOGI("Bind context");
533 context->Bind(jsRuntime_, contextRef.release());
534 napi_set_named_property(env, obj, "context", contextObj);
535
536 auto workContext = new (std::nothrow) std::weak_ptr<ExtBackupContext>(context);
537 if (workContext == nullptr) {
538 HILOGE("Failed to create ExtBackupContext.");
539 return;
540 }
541 napi_coerce_to_native_binding_object(env, contextObj, AbilityRuntime::DetachCallbackFunc,
542 AttachBackupExtensionContext, workContext, nullptr);
543 HILOGI("Set backup extension ability context pointer is nullptr: %{public}d", context.get() == nullptr);
544 napi_status status = napi_wrap(
545 env, contextObj, workContext,
546 [](napi_env, void *data, void *) {
547 HILOG_DEBUG("Finalizer for weak_ptr base context is called");
548 delete static_cast<std::weak_ptr<ExtBackupContext> *>(data);
549 },
550 nullptr, nullptr);
551 if (status != napi_ok) {
552 HILOG_DEBUG("Failed to wrap js instance");
553 delete workContext;
554 workContext = nullptr;
555 }
556 }
557
CallObjectMethod(string_view name,const vector<napi_value> & argv)558 [[maybe_unused]] tuple<ErrCode, napi_value> ExtBackupJs::CallObjectMethod(string_view name,
559 const vector<napi_value> &argv)
560 {
561 HILOGI("Call %{public}s", name.data());
562 return {BError(BError::Codes::OK).GetCode(), nullptr};
563 }
564
Create(const unique_ptr<AbilityRuntime::Runtime> & runtime)565 ExtBackupJs *ExtBackupJs::Create(const unique_ptr<AbilityRuntime::Runtime> &runtime)
566 {
567 HILOGI("Create as an BackupExtensionAbility(JS)");
568 return new ExtBackupJs(static_cast<AbilityRuntime::JsRuntime &>(*runtime));
569 }
570
OnBackup(function<void (ErrCode,std::string)> callback,std::function<void (ErrCode,const std::string)> callbackEx)571 ErrCode ExtBackupJs::OnBackup(function<void(ErrCode, std::string)> callback,
572 std::function<void(ErrCode, const std::string)> callbackEx)
573 {
574 HILOGI("BackupExtensionAbility(JS) OnBackup ex");
575 BExcepUltils::BAssert(jsObj_, BError::Codes::EXT_BROKEN_FRAMEWORK,
576 "The app does not provide the onBackup interface.");
577 BExcepUltils::BAssert(callback, BError::Codes::EXT_BROKEN_FRAMEWORK, "OnBackup callback is nullptr.");
578 BExcepUltils::BAssert(callbackEx, BError::Codes::EXT_BROKEN_FRAMEWORK, "OnBackup callbackEx is nullptr.");
579 callExtDefaultFunc_.store(false);
580 callJsExMethodDone_.store(false);
581 callbackInfo_ = std::make_shared<CallbackInfo>(callback);
582 callbackInfoEx_ = std::make_shared<CallbackInfoEx>(callbackEx);
583 return CallJsOnBackupEx();
584 }
585
CallJsOnBackupEx()586 ErrCode ExtBackupJs::CallJsOnBackupEx()
587 {
588 HILOGI("Start call app js method onBackupEx");
589 auto retParser = [jsRuntime{ &jsRuntime_ }, callbackInfoEx { callbackInfoEx_ }](napi_env envir,
590 napi_value result) -> bool {
591 if (!CheckPromise(envir, result)) {
592 string str;
593 bool isExceptionPending;
594 napi_is_exception_pending(envir, &isExceptionPending);
595 HILOGI("napi exception pending = %{public}d.", isExceptionPending);
596 if (!callbackInfoEx) {
597 HILOGE("callbackInfoEx is nullptr");
598 return false;
599 }
600 if (isExceptionPending) {
601 napi_value exception;
602 DealNapiException(envir, exception, str);
603 napi_fatal_exception(envir, exception);
604 callbackInfoEx->callbackParam(BError(BError::Codes::EXT_THROW_EXCEPTION), str);
605 } else {
606 DealNapiStrValue(envir, result, str);
607 callbackInfoEx->callbackParam(BError(BError::Codes::OK), str);
608 }
609 return true;
610 }
611 HILOGI("CheckPromise onBackupEx ok");
612 return CallPromiseEx(*jsRuntime, result, callbackInfoEx.get());
613 };
614 auto errCode = CallJsMethod("onBackupEx", jsRuntime_, jsObj_.get(), ParseBackupExInfo(), retParser);
615 if (errCode != ERR_OK) {
616 HILOGE("Call onBackupEx error");
617 return errCode;
618 }
619 HILOGI("Check call onBackupEx load");
620 std::unique_lock<std::mutex> lock(callJsMutex_);
621 callJsCon_.wait(lock, [this] { return callJsExMethodDone_.load(); });
622
623 if (!callExtDefaultFunc_.load()) {
624 HILOGI("Call Js method onBackupEx done");
625 return ERR_OK;
626 }
627 return CallJsOnBackup();
628 }
629
CallJsOnBackup()630 ErrCode ExtBackupJs::CallJsOnBackup()
631 {
632 HILOGI("Start call app js method onBackup");
633 auto retParser = [jsRuntime {&jsRuntime_}, callbackInfo {callbackInfo_}](napi_env env,
634 napi_value result) -> bool {
635 if (!CheckPromise(env, result)) {
636 string str;
637 bool isExceptionPending;
638 napi_is_exception_pending(env, &isExceptionPending);
639 HILOGI("napi exception pending = %{public}d.", isExceptionPending);
640 if (!callbackInfo) {
641 HILOGE("callbackInfo is nullptr");
642 return false;
643 }
644 if (isExceptionPending) {
645 napi_value exception;
646 DealNapiException(env, exception, str);
647 napi_fatal_exception(env, exception);
648 callbackInfo->callback(BError(BError::Codes::EXT_THROW_EXCEPTION), str);
649 } else {
650 callbackInfo->callback(BError(BError::Codes::OK), str);
651 }
652 return true;
653 }
654 HILOGI("CheckPromise Js Method onBackup ok.");
655 return CallPromise(*jsRuntime, result, callbackInfo.get());
656 };
657 auto errCode = CallJsMethod("onBackup", jsRuntime_, jsObj_.get(), {}, retParser);
658 if (errCode != ERR_OK) {
659 HILOGE("CallJsMethod error, code:%{public}d.", errCode);
660 }
661 return errCode;
662 }
663
OnRestore(function<void (ErrCode,std::string)> callback,std::function<void (ErrCode,const std::string)> callbackEx)664 ErrCode ExtBackupJs::OnRestore(function<void(ErrCode, std::string)> callback,
665 std::function<void(ErrCode, const std::string)> callbackEx)
666 {
667 HILOGI("BackupExtensionAbility(JS) OnRestore.");
668 BExcepUltils::BAssert(jsObj_, BError::Codes::EXT_BROKEN_FRAMEWORK,
669 "The app does not provide the onRestore interface.");
670 BExcepUltils::BAssert(callback, BError::Codes::EXT_BROKEN_FRAMEWORK, "OnRestore callback is nullptr.");
671 BExcepUltils::BAssert(callbackEx, BError::Codes::EXT_BROKEN_FRAMEWORK, "OnRestore callbackEx is nullptr.");
672 callExtDefaultFunc_.store(false);
673 callJsExMethodDone_.store(false);
674 callbackInfo_ = std::make_shared<CallbackInfo>(callback);
675 callbackInfoEx_ = std::make_shared<CallbackInfoEx>(callbackEx);
676 return CallJSRestoreEx();
677 }
678
CallJSRestoreEx()679 ErrCode ExtBackupJs::CallJSRestoreEx()
680 {
681 HILOGI("Start call app js method onRestoreEx");
682 auto retParser = [jsRuntime {&jsRuntime_}, callbackInfoEx {callbackInfoEx_}](napi_env envir, napi_value result) ->
683 bool {
684 if (!CheckPromise(envir, result)) {
685 string str;
686 bool isExceptionPending;
687 napi_is_exception_pending(envir, &isExceptionPending);
688 HILOGI("napi exception pending = %{public}d.", isExceptionPending);
689 if (!callbackInfoEx) {
690 HILOGE("callbackInfoEx is nullptr");
691 return false;
692 }
693 if (isExceptionPending) {
694 napi_value exception;
695 DealNapiException(envir, exception, str);
696 napi_fatal_exception(envir, exception);
697 callbackInfoEx->callbackParam(BError(BError::Codes::EXT_THROW_EXCEPTION), str);
698 } else {
699 DealNapiStrValue(envir, result, str);
700 callbackInfoEx->callbackParam(BError(BError::Codes::OK), str);
701 }
702 return true;
703 }
704 HILOGI("CheckPromise onRestoreEx ok");
705 return CallPromiseEx(*jsRuntime, result, callbackInfoEx.get());
706 };
707 auto errCode = CallJsMethod("onRestoreEx", jsRuntime_, jsObj_.get(), ParseRestoreExInfo(), retParser);
708 if (errCode != ERR_OK) {
709 HILOGE("Call onRestoreEx error");
710 return errCode;
711 }
712 HILOGI("Check callRestoreExDone load");
713 std::unique_lock<std::mutex> lock(callJsMutex_);
714 callJsCon_.wait(lock, [this] { return callJsExMethodDone_.load(); });
715 HILOGI("Check needCallOnRestore load");
716 if (!callExtDefaultFunc_.load()) {
717 HILOGI("Call Js method onRestoreEx done");
718 return ERR_OK;
719 }
720 return CallJSRestore();
721 }
722
CallJSRestore()723 ErrCode ExtBackupJs::CallJSRestore()
724 {
725 HILOGI("Start call app js method onRestore");
726 auto retParser = [jsRuntime {&jsRuntime_}, callbackInfo {callbackInfo_}](napi_env env, napi_value result) -> bool {
727 if (!CheckPromise(env, result)) {
728 string str;
729 bool isExceptionPending;
730 napi_is_exception_pending(env, &isExceptionPending);
731 HILOGI("napi exception pending = %{public}d.", isExceptionPending);
732 if (!callbackInfo) {
733 HILOGE("callbackInfo is nullptr");
734 return false;
735 }
736 if (isExceptionPending) {
737 napi_value exception;
738 DealNapiException(env, exception, str);
739 napi_fatal_exception(env, exception);
740 callbackInfo->callback(BError(BError::Codes::EXT_THROW_EXCEPTION), str);
741 } else {
742 callbackInfo->callback(BError(BError::Codes::OK), str);
743 }
744 return true;
745 }
746 HILOGI("CheckPromise Js Method onRestore ok.");
747 return CallPromise(*jsRuntime, result, callbackInfo.get());
748 };
749 auto errCode = CallJsMethod("onRestore", jsRuntime_, jsObj_.get(), ParseRestoreInfo(), retParser);
750 if (errCode != ERR_OK) {
751 HILOGE("CallJsMethod error, code:%{public}d.", errCode);
752 return errCode;
753 }
754 return ERR_OK;
755 }
756
GetBackupInfo(std::function<void (ErrCode,const std::string)> callback)757 ErrCode ExtBackupJs::GetBackupInfo(std::function<void(ErrCode, const std::string)> callback)
758 {
759 HILOGI("BackupExtensionAbility(JS) GetBackupInfo begin.");
760 BExcepUltils::BAssert(jsObj_, BError::Codes::EXT_BROKEN_FRAMEWORK,
761 "The app does not provide the GetBackupInfo interface.");
762 callbackInfoBackup_ = std::make_shared<CallbackInfoBackup>(callback);
763 auto retParser = [jsRuntime {&jsRuntime_}, callBackInfo {callbackInfoBackup_}](napi_env env,
764 napi_value result) -> bool {
765 if (!CheckPromise(env, result)) {
766 bool isExceptionPending;
767 napi_is_exception_pending(env, &isExceptionPending);
768 HILOGI("napi exception pending = %{public}d.", isExceptionPending);
769 if (!callBackInfo) {
770 HILOGE("callBackInfo is nullptr");
771 return false;
772 }
773 if (isExceptionPending) {
774 string str;
775 napi_value exception;
776 DealNapiException(env, exception, str);
777 callBackInfo->callbackParam(BError(BError::Codes::EXT_THROW_EXCEPTION), str);
778 return false;
779 }
780 size_t strLen = 0;
781 napi_status status = napi_get_value_string_utf8(env, result, nullptr, -1, &strLen);
782 if (status != napi_ok) {
783 return false;
784 }
785 size_t bufLen = strLen + 1;
786 unique_ptr<char[]> str = make_unique<char[]>(bufLen);
787 status = napi_get_value_string_utf8(env, result, str.get(), bufLen, &strLen);
788 callBackInfo->callbackParam(BError(BError::Codes::OK), str.get());
789 return true;
790 }
791 HILOGI("BackupExtensionAbulity(JS) GetBackupInfo ok.");
792 return CallPromiseEx(*jsRuntime, result, callBackInfo.get());
793 };
794
795 auto errCode = CallJsMethod("getBackupInfo", jsRuntime_, jsObj_.get(), {}, retParser);
796 if (errCode != ERR_OK) {
797 HILOGE("CallJsMethod error, code:%{public}d.", errCode);
798 }
799 HILOGI("BackupExtensionAbulity(JS) GetBackupInfo end.");
800 return errCode;
801 }
802
InvokeJsMethod(CallJsParam * param,AbilityRuntime::HandleEscape & handleEscape,napi_env env,napi_handle_scope & scope,vector<napi_value> & argv)803 static int InvokeJsMethod(CallJsParam *param, AbilityRuntime::HandleEscape& handleEscape, napi_env env,
804 napi_handle_scope& scope, vector<napi_value>& argv)
805 {
806 if (param == nullptr || param->jsObj == nullptr) {
807 HILOGE("param or jsObj is nullptr");
808 return EINVAL;
809 }
810 napi_value value = param->jsObj->GetNapiValue();
811 if (value == nullptr) {
812 HILOGE("failed to get napi value object.");
813 return EINVAL;
814 }
815 napi_status status;
816 napi_value method;
817 status = napi_get_named_property(env, value, param->funcName.c_str(), &method);
818 if (status != napi_ok || param->retParser == nullptr) {
819 HILOGE("ResultValueParser must not null.");
820 return EINVAL;
821 }
822 napi_value result;
823 HILOGI("Extension start do call current js method, methodName:%{public}s", param->funcName.c_str());
824 if (napi_call_function(env, value, method, argv.size(), argv.data(), &result) != napi_ok) {
825 HILOGE("napi call function failed");
826 }
827 if (!param->retParser(env, handleEscape.Escape(result))) {
828 HILOGE("Parser js result fail.");
829 return EINVAL;
830 }
831 return ERR_OK;
832 }
833
DoCallJsMethod(CallJsParam * param)834 static int DoCallJsMethod(CallJsParam *param)
835 {
836 if (param == nullptr) {
837 HILOGE("param is nullptr");
838 return EINVAL;
839 }
840 AbilityRuntime::JsRuntime *jsRuntime = param->jsRuntime;
841 HILOGI("Start execute DoCallJsMethod");
842 if (jsRuntime == nullptr) {
843 HILOGE("failed to get jsRuntime");
844 return EINVAL;
845 }
846 AbilityRuntime::HandleEscape handleEscape(*jsRuntime);
847 auto env = jsRuntime->GetNapiEnv();
848 napi_handle_scope scope = nullptr;
849 napi_open_handle_scope(env, &scope);
850 if (scope == nullptr) {
851 HILOGE("scope is nullptr");
852 return EINVAL;
853 }
854 vector<napi_value> argv = {};
855 if (param->argParser != nullptr) {
856 if (!param->argParser(env, argv)) {
857 HILOGE("failed to get params.");
858 napi_close_handle_scope(env, scope);
859 return EINVAL;
860 }
861 }
862 auto ret = InvokeJsMethod(param, handleEscape, env, scope, argv);
863 napi_close_handle_scope(env, scope);
864 HILOGI("End execute DoCallJsMethod");
865 return ret;
866 }
867
CallJsMethod(const std::string & funcName,AbilityRuntime::JsRuntime & jsRuntime,NativeReference * jsObj,InputArgsParser argParser,ResultValueParser retParser)868 int ExtBackupJs::CallJsMethod(const std::string &funcName,
869 AbilityRuntime::JsRuntime &jsRuntime,
870 NativeReference *jsObj,
871 InputArgsParser argParser,
872 ResultValueParser retParser)
873 {
874 auto param = std::make_shared<CallJsParam>(funcName, &jsRuntime, jsObj, argParser, retParser);
875 BExcepUltils::BAssert(param, BError::Codes::EXT_BROKEN_FRAMEWORK, "failed to new param.");
876
877 HILOGI("Will execute current js method");
878 auto task = [](void* ptr) ->void {
879 auto param = reinterpret_cast<CallJsParam *>(ptr);
880 do {
881 if (param == nullptr) {
882 HILOGE("failed to get CallJsParam.");
883 break;
884 }
885 HILOGI("Start call current js method");
886 if (DoCallJsMethod(param) != ERR_OK) {
887 HILOGE("failed to call DoCallJsMethod.");
888 }
889 } while (false);
890 HILOGI("will notify current thread info");
891 std::unique_lock<std::mutex> lock(param->backupOperateMutex);
892 param->isReady.store(true);
893 param->backupOperateCondition.notify_all();
894 };
895 uint64_t handleId = 0;
896 auto ret = napi_send_cancelable_event(jsRuntime.GetNapiEnv(), task, param.get(), napi_eprio_high, &handleId,
897 funcName.c_str());
898 if (ret != napi_status::napi_ok) {
899 HILOGE("failed to napi_send_cancelable_event, ret:%{public}d, name:%{public}s.", ret, funcName.c_str());
900 return EINVAL;
901 }
902 HILOGI("Wait execute current js method");
903 std::unique_lock<std::mutex> lock(param->backupOperateMutex);
904 param->backupOperateCondition.wait(lock, [param]() { return param->isReady.load(); });
905 HILOGI("End do call current js method");
906 return ERR_OK;
907 }
908
ParseBackupExInfo()909 std::function<bool(napi_env env, std::vector<napi_value> &argv)> ExtBackupJs::ParseBackupExInfo()
910 {
911 auto onBackupExFun = [backupExtInfo(backupExtInfo_)](napi_env env, vector<napi_value> &argv) -> bool {
912 napi_value backupExtInfoVal = nullptr;
913 napi_create_object(env, &backupExtInfoVal);
914 HILOGI("backupExtInfo is:%{public}s", GetAnonyString(backupExtInfo).c_str());
915 if (napi_create_string_utf8(env, backupExtInfo.c_str(), backupExtInfo.size(), &backupExtInfoVal) != napi_ok) {
916 HILOGE("create napi string failed");
917 return false;
918 }
919 argv.emplace_back(backupExtInfoVal);
920 return true;
921 };
922 return onBackupExFun;
923 }
924
ParseRestoreExInfo()925 std::function<bool(napi_env env, std::vector<napi_value> &argv)> ExtBackupJs::ParseRestoreExInfo()
926 {
927 auto onRestoreExFun = [appVersionCode(appVersionCode_), appVersionStr(appVersionStr_),
928 restoreExtInfo(restoreExtInfo_)](napi_env env, vector<napi_value> &argv) -> bool {
929 HILOGI("restoreExtInfo is:%{public}s", GetAnonyString(restoreExtInfo).c_str());
930 napi_value objValue = nullptr;
931 napi_value restoreRetValue = nullptr;
932 napi_create_object(env, &objValue);
933 napi_create_object(env, &restoreRetValue);
934 napi_set_named_property(env, objValue, "code", AbilityRuntime::CreateJsValue(env, appVersionCode));
935 napi_set_named_property(env, objValue, "name", AbilityRuntime::CreateJsValue(env, appVersionStr.c_str()));
936 if (napi_create_string_utf8(env, restoreExtInfo.c_str(), restoreExtInfo.size(), &restoreRetValue) != napi_ok) {
937 HILOGE("create napi string failed");
938 return false;
939 }
940 argv.emplace_back(objValue);
941 argv.emplace_back(restoreRetValue);
942 return true;
943 };
944 return onRestoreExFun;
945 }
946
ParseRestoreInfo()947 std::function<bool(napi_env env, std::vector<napi_value> &argv)> ExtBackupJs::ParseRestoreInfo()
948 {
949 auto onRestoreFun = [appVersionCode(appVersionCode_), appVersionStr(appVersionStr_)](napi_env env,
950 vector<napi_value> &argv) -> bool {
951 std::string appVersionStrFlag = appVersionStr;
952 int64_t appVersionCodeFlag = appVersionCode;
953 napi_value objValue = nullptr;
954 napi_create_object(env, &objValue);
955 auto pos = appVersionStrFlag.find_first_of(BConstants::VERSION_NAME_SEPARATOR_CHAR);
956 std::string appVersionFlag = "";
957 if (pos != string::npos) {
958 appVersionFlag = appVersionStrFlag.substr(0, pos);
959 if (appVersionFlag == BConstants::DEFAULT_VERSION_NAME) {
960 appVersionStrFlag = appVersionFlag;
961 appVersionCodeFlag = 0;
962 }
963 }
964 napi_set_named_property(env, objValue, "code", AbilityRuntime::CreateJsValue(env, appVersionCodeFlag));
965 napi_set_named_property(env, objValue, "name", AbilityRuntime::CreateJsValue(env, appVersionStrFlag.c_str()));
966 argv.emplace_back(objValue);
967 return true;
968 };
969 return onRestoreFun;
970 }
971
InvokeAppExtMethod(ErrCode errCode,const std::string result)972 ErrCode ExtBackupJs::InvokeAppExtMethod(ErrCode errCode, const std::string result)
973 {
974 HILOGI("Start Get onBackupEx/onRestoreEx method result, errCode: %{public}d, result: %{public}s",
975 errCode, result.c_str());
976 if ((result.size() == 0) && (errCode == BError(BError::Codes::OK))) {
977 callExtDefaultFunc_.store(true);
978 } else {
979 callExtDefaultFunc_.store(false);
980 }
981 callJsExMethodDone_.store(true);
982 callJsCon_.notify_one();
983 HILOGI("End Get App onBackupEx/onRestoreEx method result");
984 return ERR_OK;
985 }
986
OnProcess(std::function<void (ErrCode,const std::string)> callback)987 ErrCode ExtBackupJs::OnProcess(std::function<void(ErrCode, const std::string)> callback)
988 {
989 HILOGI("BackupExtensionAbility(JS) OnProcess begin.");
990 BExcepUltils::BAssert(jsObj_, BError::Codes::EXT_BROKEN_FRAMEWORK,
991 "The app does not provide the OnProcess interface.");
992 onProcessCallback_ = std::make_shared<OnProcessCallBackInfo>(callback);
993 auto retParser = [jsRuntime {&jsRuntime_}, callBackInfo {onProcessCallback_}](napi_env env,
994 napi_value result) -> bool {
995 string processStr;
996 bool isExceptionPending;
997 napi_is_exception_pending(env, &isExceptionPending);
998 HILOGI("napi exception pending = %{public}d.", isExceptionPending);
999 if (!callBackInfo) {
1000 HILOGE("callbackInfo is nullptr");
1001 return false;
1002 }
1003 if (isExceptionPending) {
1004 napi_value exception;
1005 napi_get_and_clear_last_exception(env, &exception);
1006 callBackInfo->onProcessCallback(BError(BError::Codes::EXT_THROW_EXCEPTION), processStr);
1007 } else {
1008 DealNapiStrValue(env, result, processStr);
1009 callBackInfo->onProcessCallback(BError(BError::Codes::OK), processStr);
1010 }
1011 return true;
1012 };
1013 auto errCode = CallJsMethod("onProcess", jsRuntime_, jsObj_.get(), {}, retParser);
1014 if (errCode != ERR_OK) {
1015 HILOGE("CallJsMethod error, code:%{public}d.", errCode);
1016 }
1017 HILOGI("BackupExtensionAbulity(JS) OnProcess end.");
1018 return errCode;
1019 }
1020
OnRelease(std::function<void (ErrCode,const std::string)> callback,int32_t scenario)1021 ErrCode ExtBackupJs::OnRelease(std::function<void(ErrCode, const std::string)> callback, int32_t scenario)
1022 {
1023 HILOGI("BackupExtensionAbility(JS) OnRelease begin.");
1024 BExcepUltils::BAssert(jsObj_, BError::Codes::EXT_BROKEN_FRAMEWORK,
1025 "The app does not provide the OnProcess interface.");
1026 scenario_ = scenario;
1027 onReleaseCallback_ = std::make_shared<CallbackInfo>(callback);
1028 auto retParser = [jsRuntime {&jsRuntime_}, callbackInfo {onReleaseCallback_}](napi_env env,
1029 napi_value result) -> bool {
1030 if (!CheckPromise(env, result)) {
1031 string str;
1032 bool isExceptionPending;
1033 napi_is_exception_pending(env, &isExceptionPending);
1034 HILOGI("napi exception pending = %{public}d.", isExceptionPending);
1035 if (!callbackInfo) {
1036 HILOGE("callbackInfo is nullptr");
1037 return false;
1038 }
1039 if (isExceptionPending) {
1040 napi_value exception;
1041 DealNapiException(env, exception, str);
1042 napi_fatal_exception(env, exception);
1043 callbackInfo->callback(BError(BError::Codes::EXT_THROW_EXCEPTION), str);
1044 } else {
1045 callbackInfo->callback(BError(BError::Codes::OK), str);
1046 }
1047 return true;
1048 }
1049 HILOGI("CheckPromise Js Method onRelease ok.");
1050 return CallPromise(*jsRuntime, result, callbackInfo.get());
1051 };
1052 auto errCode = CallJsMethod("onRelease", jsRuntime_, jsObj_.get(), ParseReleaseInfo(), retParser);
1053 if (errCode != ERR_OK) {
1054 HILOGE("CallJsMethod error, code:%{public}d.", errCode);
1055 }
1056 HILOGI("BackupExtensionAbility(JS) OnRelease end.");
1057 return errCode;
1058 }
1059
ParseReleaseInfo()1060 std::function<bool(napi_env env, std::vector<napi_value> &argv)> ExtBackupJs::ParseReleaseInfo()
1061 {
1062 auto onReleaseFun = [scenario(scenario_)](napi_env env, vector<napi_value> &argv) -> bool {
1063 int32_t scenarioFlag = scenario;
1064 HILOGI("ParseReleaseInfo, scenario:%{public}d", scenarioFlag);
1065 napi_value scenarioValue = nullptr;
1066 napi_create_int32(env, scenarioFlag, &scenarioValue);
1067 argv.emplace_back(scenarioValue);
1068 return true;
1069 };
1070 return onReleaseFun;
1071 }
1072
InitTempPath(const std::string & bundleName)1073 void ExtBackupJs::InitTempPath(const std::string &bundleName)
1074 {
1075 std::string el2BackupDir(BConstants::PATH_BUNDLE_BACKUP_HOME);
1076 if (access(el2BackupDir.c_str(), F_OK) != 0) {
1077 HILOGW("backup home el2 dir not exits, try to create");
1078 if (!ForceCreateDirectory(el2BackupDir.data())) {
1079 HILOGE("Failed to create directory, err = %{public}d", errno);
1080 AppRadar::Info info(bundleName, "", "Create backup home el2 dir failed");
1081 AppRadar::GetInstance().RecordDefaultFuncRes(info, "ExtBackupJs::InitTempPath",
1082 AppRadar::GetInstance().GetUserId(), BizStageBackup::BIZ_STAGE_DEFAULT,
1083 static_cast<int32_t>(BError::Codes::EXT_CREATE_DIR_ERROR));
1084 }
1085 }
1086 std::string el1BackupDir(BConstants::PATH_BUNDLE_BACKUP_HOME_EL1);
1087 if (access(el1BackupDir.c_str(), F_OK) != 0) {
1088 HILOGW("backup home el1 dir not exits, try to create");
1089 if (!ForceCreateDirectory(el1BackupDir.data())) {
1090 HILOGE("Failed to create home el1 dir, err = %{public}d", errno);
1091 AppRadar::Info info(bundleName, "", "Create backup home el1 dir failed");
1092 AppRadar::GetInstance().RecordDefaultFuncRes(info, "ExtBackupJs::InitTempPath",
1093 AppRadar::GetInstance().GetUserId(), BizStageBackup::BIZ_STAGE_DEFAULT,
1094 static_cast<int32_t>(BError::Codes::EXT_CREATE_DIR_ERROR));
1095 }
1096 }
1097 }
1098
GetBackupCompatibilityInfo(std::function<void (ErrCode,const std::string)> callbackEx,std::string extInfo)1099 ErrCode ExtBackupJs::GetBackupCompatibilityInfo(std::function<void(ErrCode, const std::string)> callbackEx,
1100 std::string extInfo)
1101 {
1102 HILOGI("BackupExtensionAbility(JS) GetBackupCompatibilityInfo begin.");
1103 BExcepUltils::BAssert(jsObj_, BError::Codes::EXT_BROKEN_FRAMEWORK,
1104 "The app does not provide the GetBackupCompatibilityInfo interface.");
1105 extInfo_ = extInfo;
1106 getComInfoCallbackEx_ = std::make_shared<CallbackInfoEx>(callbackEx);
1107 auto retParser = [jsRuntime {&jsRuntime_}, callbackInfoEx {getComInfoCallbackEx_}](napi_env env,
1108 napi_value result) -> bool {
1109 if (!CheckPromise(env, result)) {
1110 string str;
1111 bool isExceptionPending;
1112 napi_is_exception_pending(env, &isExceptionPending);
1113 HILOGI("napi exception pending = %{public}d.", isExceptionPending);
1114 if (!callbackInfoEx) {
1115 HILOGE("callbackInfoEx is nullptr");
1116 return false;
1117 }
1118 if (isExceptionPending) {
1119 napi_value exception;
1120 DealNapiException(env, exception, str);
1121 napi_fatal_exception(env, exception);
1122 callbackInfoEx->callbackParam(BError(BError::Codes::EXT_THROW_EXCEPTION), str);
1123 } else {
1124 callbackInfoEx->callbackParam(BError(BError::Codes::OK), str);
1125 }
1126 return true;
1127 }
1128 HILOGI("CheckPromise Js Method GetBackupCompatibilityInfo ok.");
1129 return CallPromiseEx(*jsRuntime, result, callbackInfoEx.get());
1130 };
1131 auto errCode = CallJsMethod("getBackupCompatibilityInfo", jsRuntime_, jsObj_.get(),
1132 ParseCompatibilityInfo(), retParser);
1133 if (errCode != ERR_OK) {
1134 HILOGE("CallJsMethod error, code:%{public}d.", errCode);
1135 }
1136 HILOGI("BackupExtensionAbility(JS) GetBackupCompatibilityInfo end.");
1137 return errCode;
1138 }
1139
GetRestoreCompatibilityInfo(std::function<void (ErrCode,const std::string)> callbackEx,std::string extInfo)1140 ErrCode ExtBackupJs::GetRestoreCompatibilityInfo(std::function<void(ErrCode, const std::string)> callbackEx,
1141 std::string extInfo)
1142 {
1143 HILOGI("BackupExtensionAbility(JS) GetRestoreCompatibilityInfo begin.");
1144 BExcepUltils::BAssert(jsObj_, BError::Codes::EXT_BROKEN_FRAMEWORK,
1145 "The app does not provide the GetRestoreCompatibilityInfo interface.");
1146 extInfo_ = extInfo;
1147 getComInfoCallbackEx_ = std::make_shared<CallbackInfoEx>(callbackEx);
1148 auto retParser = [jsRuntime {&jsRuntime_}, callbackInfoEx {getComInfoCallbackEx_}](napi_env env,
1149 napi_value result) -> bool {
1150 if (!CheckPromise(env, result)) {
1151 string str;
1152 bool isExceptionPending;
1153 napi_is_exception_pending(env, &isExceptionPending);
1154 HILOGI("napi exception pending = %{public}d.", isExceptionPending);
1155 if (!callbackInfoEx) {
1156 HILOGE("callbackInfoEx is nullptr");
1157 return false;
1158 }
1159 if (isExceptionPending) {
1160 napi_value exception;
1161 DealNapiException(env, exception, str);
1162 napi_fatal_exception(env, exception);
1163 callbackInfoEx->callbackParam(BError(BError::Codes::EXT_THROW_EXCEPTION), str);
1164 } else {
1165 callbackInfoEx->callbackParam(BError(BError::Codes::OK), str);
1166 }
1167 return true;
1168 }
1169 HILOGI("CheckPromise Js Method GetRestoreCompatibilityInfo ok.");
1170 return CallPromiseEx(*jsRuntime, result, callbackInfoEx.get());
1171 };
1172 auto errCode = CallJsMethod("getRestoreCompatibilityInfo", jsRuntime_, jsObj_.get(),
1173 ParseCompatibilityInfo(), retParser);
1174 if (errCode != ERR_OK) {
1175 HILOGE("CallJsMethod error, code:%{public}d.", errCode);
1176 }
1177 HILOGI("BackupExtensionAbility(JS) GetRestoreCompatibilityInfo end.");
1178 return errCode;
1179 }
1180
ParseCompatibilityInfo()1181 std::function<bool(napi_env env, std::vector<napi_value> &argv)> ExtBackupJs::ParseCompatibilityInfo()
1182 {
1183 auto getCompatibilityInfoFun = [extInfo(extInfo_)](napi_env env, vector<napi_value> &argv) -> bool {
1184 napi_value extInfoValue = nullptr;
1185 napi_create_object(env, &extInfoValue);
1186 HILOGI("ParseCompatibilityInfo, extInfo is:%{public}s", GetAnonyString(extInfo).c_str());
1187 if (napi_create_string_utf8(env, extInfo.c_str(), extInfo.size(), &extInfoValue) != napi_ok) {
1188 HILOGE("create napi string failed");
1189 return false;
1190 }
1191 argv.emplace_back(extInfoValue);
1192 return true;
1193 };
1194 return getCompatibilityInfoFun;
1195 }
1196 } // namespace OHOS::FileManagement::Backup
1197