• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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