• 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 "js_service_extension_context.h"
17 
18 #include <chrono>
19 #include <cstdint>
20 
21 #include "ability_manager_client.h"
22 #include "ability_runtime/js_caller_complex.h"
23 #include "hilog_tag_wrapper.h"
24 #include "js_extension_context.h"
25 #include "js_error_utils.h"
26 #include "js_data_struct_converter.h"
27 #include "js_deferred_callback.h"
28 #include "js_runtime.h"
29 #include "js_runtime_utils.h"
30 #include "js_start_abilities_observer.h"
31 #include "napi/native_api.h"
32 #include "napi_common_ability.h"
33 #include "napi_common_want.h"
34 #include "napi_common_util.h"
35 #include "napi_remote_object.h"
36 #include "napi_common_start_options.h"
37 #include "open_link_options.h"
38 #include "open_link/napi_common_open_link_options.h"
39 #include "start_options.h"
40 #include "hitrace_meter.h"
41 #include "uri.h"
42 
43 namespace OHOS {
44 namespace AbilityRuntime {
45 namespace {
46 constexpr int32_t INDEX_ZERO = 0;
47 constexpr int32_t INDEX_ONE = 1;
48 constexpr int32_t INDEX_TWO = 2;
49 constexpr int32_t INDEX_THREE = 3;
50 constexpr int32_t INDEX_FOUR = 4;
51 constexpr size_t ARGC_ZERO = 0;
52 constexpr size_t ARGC_ONE = 1;
53 constexpr size_t ARGC_TWO = 2;
54 constexpr size_t ARGC_THREE = 3;
55 constexpr size_t ARGC_FOUR = 4;
56 constexpr const char* ATOMIC_SERVICE_PREFIX = "com.atomicservice.";
57 const std::string JSON_KEY_ERR_MSG = "errMsg";
58 
59 class StartAbilityByCallParameters {
60 public:
61     int err = 0;
62     sptr<IRemoteObject> remoteCallee = nullptr;
63     std::shared_ptr<CallerCallBack> callerCallBack = nullptr;
64     std::mutex mutexlock;
65     std::condition_variable condition;
66 };
67 
68 static std::mutex g_connectsMutex;
69 static std::map<ConnectionKey, sptr<JSServiceExtensionConnection>, key_compare> g_connects;
70 static int64_t g_serialNumber = 0;
71 
RemoveConnection(int64_t connectId)72 void RemoveConnection(int64_t connectId)
73 {
74     TAG_LOGD(AAFwkTag::SERVICE_EXT, "enter");
75     std::lock_guard guard(g_connectsMutex);
76     auto item = std::find_if(g_connects.begin(), g_connects.end(),
77     [&connectId](const auto &obj) {
78         return connectId == obj.first.id;
79     });
80     if (item != g_connects.end()) {
81         TAG_LOGD(AAFwkTag::SERVICE_EXT, "remove conn ability exist");
82         if (item->second) {
83             item->second->RemoveConnectionObject();
84         }
85         g_connects.erase(item);
86     } else {
87         TAG_LOGD(AAFwkTag::SERVICE_EXT, "remove conn ability not exist");
88     }
89 }
90 
91 class JsServiceExtensionContext final {
92 public:
JsServiceExtensionContext(const std::shared_ptr<ServiceExtensionContext> & context)93     explicit JsServiceExtensionContext(const std::shared_ptr<ServiceExtensionContext>& context) : context_(context) {}
94     ~JsServiceExtensionContext() = default;
95 
Finalizer(napi_env env,void * data,void * hint)96     static void Finalizer(napi_env env, void* data, void* hint)
97     {
98         TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
99         std::unique_ptr<JsServiceExtensionContext>(static_cast<JsServiceExtensionContext*>(data));
100     }
101 
StartAbility(napi_env env,napi_callback_info info)102     static napi_value StartAbility(napi_env env, napi_callback_info info)
103     {
104         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnStartAbility);
105     }
106 
OpenLink(napi_env env,napi_callback_info info)107     static napi_value OpenLink(napi_env env, napi_callback_info info)
108     {
109         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnOpenLink);
110     }
111 
StartAbilityAsCaller(napi_env env,napi_callback_info info)112     static napi_value StartAbilityAsCaller(napi_env env, napi_callback_info info)
113     {
114         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnStartAbilityAsCaller);
115     }
116 
StartRecentAbility(napi_env env,napi_callback_info info)117     static napi_value StartRecentAbility(napi_env env, napi_callback_info info)
118     {
119         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnStartRecentAbility);
120     }
121 
StartAbilityByCall(napi_env env,napi_callback_info info)122     static napi_value StartAbilityByCall(napi_env env, napi_callback_info info)
123     {
124         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnStartAbilityByCall);
125     }
126 
StartAbilityWithAccount(napi_env env,napi_callback_info info)127     static napi_value StartAbilityWithAccount(napi_env env, napi_callback_info info)
128     {
129         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnStartAbilityWithAccount);
130     }
131 
StartUIAbilities(napi_env env,napi_callback_info info)132     static napi_value StartUIAbilities(napi_env env, napi_callback_info info)
133     {
134         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnStartUIAbilities);
135     }
136 
ConnectAbilityWithAccount(napi_env env,napi_callback_info info)137     static napi_value ConnectAbilityWithAccount(napi_env env, napi_callback_info info)
138     {
139         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnConnectAbilityWithAccount);
140     }
141 
TerminateAbility(napi_env env,napi_callback_info info)142     static napi_value TerminateAbility(napi_env env, napi_callback_info info)
143     {
144         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnTerminateAbility);
145     }
146 
ConnectAbility(napi_env env,napi_callback_info info)147     static napi_value ConnectAbility(napi_env env, napi_callback_info info)
148     {
149         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnConnectAbility);
150     }
151 
DisconnectAbility(napi_env env,napi_callback_info info)152     static napi_value DisconnectAbility(napi_env env, napi_callback_info info)
153     {
154         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnDisconnectAbility);
155     }
156 
StartServiceExtensionAbility(napi_env env,napi_callback_info info)157     static napi_value StartServiceExtensionAbility(napi_env env, napi_callback_info info)
158     {
159         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnStartExtensionAbility);
160     }
161 
StartUIServiceExtensionAbility(napi_env env,napi_callback_info info)162     static napi_value StartUIServiceExtensionAbility(napi_env env, napi_callback_info info)
163     {
164         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnStartUIServiceExtension);
165     }
166 
StartServiceExtensionAbilityWithAccount(napi_env env,napi_callback_info info)167     static napi_value StartServiceExtensionAbilityWithAccount(napi_env env, napi_callback_info info)
168     {
169         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnStartExtensionAbilityWithAccount);
170     }
171 
StopServiceExtensionAbility(napi_env env,napi_callback_info info)172     static napi_value StopServiceExtensionAbility(napi_env env, napi_callback_info info)
173     {
174         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnStopExtensionAbility);
175     }
176 
StopServiceExtensionAbilityWithAccount(napi_env env,napi_callback_info info)177     static napi_value StopServiceExtensionAbilityWithAccount(napi_env env, napi_callback_info info)
178     {
179         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnStopExtensionAbilityWithAccount);
180     }
181 
RequestModalUIExtension(napi_env env,napi_callback_info info)182     static napi_value RequestModalUIExtension(napi_env env, napi_callback_info info)
183     {
184         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnRequestModalUIExtension);
185     }
186 
PreStartMission(napi_env env,napi_callback_info info)187     static napi_value PreStartMission(napi_env env, napi_callback_info info)
188     {
189         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnPreStartMission);
190     }
191 
OpenAtomicService(napi_env env,napi_callback_info info)192     static napi_value OpenAtomicService(napi_env env, napi_callback_info info)
193     {
194         GET_NAPI_INFO_AND_CALL(env, info, JsServiceExtensionContext, OnOpenAtomicService);
195     }
196 
197 private:
198     std::weak_ptr<ServiceExtensionContext> context_;
199     sptr<JsFreeInstallObserver> freeInstallObserver_ = nullptr;
ClearFailedCallConnection(const std::weak_ptr<ServiceExtensionContext> & serviceContext,const std::shared_ptr<CallerCallBack> & callback)200     static void ClearFailedCallConnection(
201         const std::weak_ptr<ServiceExtensionContext>& serviceContext, const std::shared_ptr<CallerCallBack> &callback)
202     {
203         TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
204         auto context = serviceContext.lock();
205         if (context == nullptr || callback == nullptr) {
206             TAG_LOGE(AAFwkTag::SERVICE_EXT, "null context or callback");
207             return;
208         }
209 
210         context->ClearFailedCallConnection(callback);
211     }
212 
AddFreeInstallObserver(napi_env env,const AAFwk::Want & want,napi_value callback,napi_value * result,bool isOpenLink=false)213     void AddFreeInstallObserver(napi_env env, const AAFwk::Want &want, napi_value callback,
214         napi_value* result, bool isOpenLink = false)
215     {
216         // adapter free install async return install and start result
217         int ret = 0;
218         if (freeInstallObserver_ == nullptr) {
219             freeInstallObserver_ = new JsFreeInstallObserver(env);
220             auto context = context_.lock();
221             if (!context) {
222                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "context released");
223                 return;
224             }
225             ret = context->AddFreeInstallObserver(freeInstallObserver_);
226         }
227 
228         if (ret != ERR_OK) {
229             TAG_LOGE(AAFwkTag::SERVICE_EXT, "AddFreeInstallObserver failed");
230             return;
231         }
232         std::string startTime = want.GetStringParam(Want::PARAM_RESV_START_TIME);
233         // build a callback observer with last param
234         if (!isOpenLink) {
235             TAG_LOGI(AAFwkTag::SERVICE_EXT, "AddJsObserverObject");
236             std::string bundleName = want.GetElement().GetBundleName();
237             std::string abilityName = want.GetElement().GetAbilityName();
238             freeInstallObserver_->AddJsObserverObject(
239                 bundleName, abilityName, startTime, callback, result);
240             return;
241         }
242         std::string url = want.GetUriString();
243         freeInstallObserver_->AddJsObserverObject(startTime, url, callback, result);
244     }
245 
OnStartAbility(napi_env env,NapiCallbackInfo & info,bool isStartRecent=false)246     napi_value OnStartAbility(napi_env env, NapiCallbackInfo& info, bool isStartRecent = false)
247     {
248         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
249         TAG_LOGD(AAFwkTag::SERVICE_EXT, "StartAbility");
250 
251         size_t unwrapArgc = 0;
252         AAFwk::Want want;
253         AAFwk::StartOptions startOptions;
254         if (!CheckStartAbilityInputParam(env, info, want, startOptions, unwrapArgc)) {
255             return CreateJsUndefined(env);
256         }
257 
258         if (isStartRecent) {
259             TAG_LOGD(AAFwkTag::SERVICE_EXT, "OnStartRecentAbility is called");
260             want.SetParam(Want::PARAM_RESV_START_RECENT, true);
261         }
262 
263         if ((want.GetFlags() & Want::FLAG_INSTALL_ON_DEMAND) == Want::FLAG_INSTALL_ON_DEMAND) {
264             std::string startTime = std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
265                 system_clock::now().time_since_epoch()).count());
266             want.SetParam(Want::PARAM_RESV_START_TIME, startTime);
267         }
268 
269         auto innerErrorCode = std::make_shared<int>(ERR_OK);
270         auto execute = GetStartAbilityExecFunc(want, startOptions, DEFAULT_INVAL_VALUE,
271             unwrapArgc != 1, innerErrorCode);
272         auto complete = GetSimpleCompleteFunc(innerErrorCode);
273 
274         napi_value lastParam = (info.argc == unwrapArgc) ? nullptr : info.argv[unwrapArgc];
275         napi_value result = nullptr;
276         if ((want.GetFlags() & Want::FLAG_INSTALL_ON_DEMAND) == Want::FLAG_INSTALL_ON_DEMAND) {
277             AddFreeInstallObserver(env, want, lastParam, &result);
278             NapiAsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartAbility", env,
279                 CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), nullptr, nullptr));
280         } else {
281             NapiAsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartAbility", env,
282                 CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
283         }
284         return result;
285     }
286 
CheckUrl(std::string & urlValue)287     bool CheckUrl(std::string &urlValue)
288     {
289         if (urlValue.empty()) {
290             return false;
291         }
292         Uri uri = Uri(urlValue);
293         if (uri.GetScheme().empty() || uri.GetHost().empty()) {
294             return false;
295         }
296 
297         return true;
298     }
299 
ParseOpenLinkParams(const napi_env & env,const NapiCallbackInfo & info,std::string & linkValue,AAFwk::OpenLinkOptions & openLinkOptions,AAFwk::Want & want)300     bool ParseOpenLinkParams(const napi_env &env, const NapiCallbackInfo &info, std::string &linkValue,
301         AAFwk::OpenLinkOptions &openLinkOptions, AAFwk::Want &want)
302     {
303         if (info.argc != ARGC_TWO) {
304             TAG_LOGE(AAFwkTag::SERVICE_EXT, "wrong argc");
305             ThrowTooFewParametersError(env);
306             return false;
307         }
308 
309         if (!CheckTypeForNapiValue(env, info.argv[ARGC_ZERO], napi_string)) {
310             TAG_LOGE(AAFwkTag::SERVICE_EXT, "link must be string");
311             ThrowInvalidParamError(env, "Parse param link failed, must be a string.");
312             return false;
313         }
314         if (!ConvertFromJsValue(env, info.argv[ARGC_ZERO], linkValue) || !CheckUrl(linkValue)) {
315             TAG_LOGE(AAFwkTag::SERVICE_EXT, "param link invalid");
316             ThrowInvalidParamError(env, "link parameter invalid.");
317             return false;
318         }
319 
320         if (CheckTypeForNapiValue(env, info.argv[INDEX_ONE], napi_object)) {
321             TAG_LOGD(AAFwkTag::SERVICE_EXT, "OpenLinkOptions used");
322             if (!AppExecFwk::UnwrapOpenLinkOptions(env, info.argv[INDEX_ONE], openLinkOptions, want)) {
323                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "OpenLinkOptions parse failed");
324                 ThrowInvalidParamError(env, "Parse param options failed, must be a OpenLinkOptions.");
325                 return false;
326             }
327         }
328 
329         return true;
330     }
331 
OnOpenLink(napi_env env,NapiCallbackInfo & info)332     napi_value OnOpenLink(napi_env env, NapiCallbackInfo& info)
333     {
334         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
335         TAG_LOGD(AAFwkTag::SERVICE_EXT, "OnOpenLink");
336 
337         std::string linkValue("");
338         AAFwk::OpenLinkOptions openLinkOptions;
339         AAFwk::Want want;
340         want.SetParam(AppExecFwk::APP_LINKING_ONLY, false);
341 
342         if (!ParseOpenLinkParams(env, info, linkValue, openLinkOptions, want)) {
343             TAG_LOGE(AAFwkTag::SERVICE_EXT, "parse OpenLinkParams failed");
344             ThrowInvalidParamError(env,
345                 "Parse param link or openLinkOptions failed, link must be string, openLinkOptions must be options.");
346             return CreateJsUndefined(env);
347         }
348 
349         want.SetUri(linkValue);
350         std::string startTime = std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
351             system_clock::now().time_since_epoch()).count());
352         want.SetParam(Want::PARAM_RESV_START_TIME, startTime);
353 
354         return OnOpenLinkInner(env, want, startTime, linkValue);
355     }
356 
OnOpenLinkInner(napi_env env,const AAFwk::Want & want,const std::string & startTime,const std::string & url)357     napi_value OnOpenLinkInner(napi_env env, const AAFwk::Want& want,
358         const std::string& startTime, const std::string& url)
359     {
360         auto innerErrorCode = std::make_shared<int>(ERR_OK);
361         NapiAsyncTask::ExecuteCallback execute = [weak = context_, want, innerErrorCode]() {
362             auto context = weak.lock();
363             if (!context) {
364                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "context released");
365                 *innerErrorCode = static_cast<int>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
366                 return;
367             }
368             *innerErrorCode = context->OpenLink(want, -1);
369         };
370 
371         NapiAsyncTask::CompleteCallback complete = [innerErrorCode, startTime, url,
372             freeInstallObserver = freeInstallObserver_](
373             napi_env env, NapiAsyncTask& task, int32_t status) {
374             if (*innerErrorCode == 0) {
375                 TAG_LOGI(AAFwkTag::SERVICE_EXT, "OpenLink success");
376                 return;
377             }
378             if (freeInstallObserver == nullptr) {
379                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "null freeInstallObserver_");
380                 return;
381             }
382             if (*innerErrorCode == AAFwk::ERR_OPEN_LINK_START_ABILITY_DEFAULT_OK) {
383                 TAG_LOGI(AAFwkTag::SERVICE_EXT, "start ability by default succeeded");
384                 freeInstallObserver->OnInstallFinishedByUrl(startTime, url, ERR_OK);
385                 return;
386             }
387             TAG_LOGI(AAFwkTag::SERVICE_EXT, "OpenLink failed");
388             freeInstallObserver->OnInstallFinishedByUrl(startTime, url, *innerErrorCode);
389         };
390 
391         napi_value result = nullptr;
392         AddFreeInstallObserver(env, want, nullptr, &result, true);
393         NapiAsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnOpenLink", env,
394             CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), nullptr));
395 
396         return result;
397     }
398 
UnWrapCompletionHandlerForAtomicService(napi_env env,napi_value param,AAFwk::StartOptions & options,const std::string & appId)399     void UnWrapCompletionHandlerForAtomicService(
400         napi_env env, napi_value param, AAFwk::StartOptions &options, const std::string &appId)
401     {
402         napi_value completionHandlerForAtomicService = AppExecFwk::GetPropertyValueByPropertyName(env, param,
403             "completionHandlerForAtomicService", napi_object);
404         if (completionHandlerForAtomicService == nullptr) {
405             TAG_LOGD(AAFwkTag::SERVICE_EXT, "null completionHandlerForAtomicService");
406             return;
407         }
408         TAG_LOGI(AAFwkTag::SERVICE_EXT, "completionHandlerForAtomicService exists");
409         napi_value onRequestSuccFunc = AppExecFwk::GetPropertyValueByPropertyName(env,
410             completionHandlerForAtomicService, "onAtomicServiceRequestSuccess", napi_function);
411         napi_value onRequestFailFunc = AppExecFwk::GetPropertyValueByPropertyName(env,
412             completionHandlerForAtomicService, "onAtomicServiceRequestFailure", napi_function);
413         if (onRequestSuccFunc == nullptr || onRequestFailFunc == nullptr) {
414             TAG_LOGE(AAFwkTag::SERVICE_EXT, "null onRequestSuccFunc or onRequestFailFunc");
415             return;
416         }
417         OnAtomicRequestSuccess onRequestSucc = [env, completionHandlerForAtomicService, onRequestSuccFunc](
418             const std::string &appId) {
419             napi_value argv[ARGC_ONE] = { CreateJsValue(env, appId) };
420             napi_status status = napi_call_function(
421                 env, completionHandlerForAtomicService, onRequestSuccFunc, ARGC_ONE, argv, nullptr);
422             if (status != napi_ok) {
423                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "call onRequestSuccess, failed: %{public}d", status);
424             }
425         };
426         OnAtomicRequestFailure onRequestFail = [env, completionHandlerForAtomicService, onRequestFailFunc](
427             const std::string &appId, int32_t failureCode, const std::string &message) {
428             napi_value argv[ARGC_THREE] = { CreateJsValue(env, appId), CreateJsValue(env, failureCode),
429                 CreateJsValue(env, message) };
430             napi_status status = napi_call_function(
431                 env, completionHandlerForAtomicService, onRequestFailFunc, ARGC_THREE, argv, nullptr);
432             if (status != napi_ok) {
433                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "call onRequestFailure, failed: %{public}d", status);
434             }
435         };
436         auto context = context_.lock();
437         if (!context) {
438             TAG_LOGE(AAFwkTag::SERVICE_EXT, "null context");
439             return;
440         }
441         std::string requestId = std::to_string(
442             static_cast<uint64_t>(std::chrono::duration_cast<std::chrono::nanoseconds>(
443             std::chrono::high_resolution_clock::now().time_since_epoch()).count()));
444         if (context->AddCompletionHandlerForAtomicService(requestId, onRequestSucc, onRequestFail, appId) != ERR_OK) {
445             TAG_LOGE(AAFwkTag::SERVICE_EXT, "add completionHandler failed");
446             return;
447         }
448         options.requestId_ = requestId;
449     }
450 
OnOpenAtomicService(napi_env env,NapiCallbackInfo & info)451     napi_value OnOpenAtomicService(napi_env env, NapiCallbackInfo &info)
452     {
453         TAG_LOGD(AAFwkTag::SERVICE_EXT, "OpenAtomicService");
454         if (info.argc == ARGC_ZERO) {
455             ThrowTooFewParametersError(env);
456             return CreateJsUndefined(env);
457         }
458 
459         std::string appId;
460         if (!ConvertFromJsValue(env, info.argv[INDEX_ZERO], appId)) {
461             TAG_LOGE(AAFwkTag::SERVICE_EXT, "parse appId failed");
462             ThrowInvalidParamError(env, "Parse param appId failed, appId must be string.");
463             return CreateJsUndefined(env);
464         }
465 
466         AAFwk::Want want;
467         AAFwk::StartOptions startOptions;
468         if (info.argc > ARGC_ONE && CheckTypeForNapiValue(env, info.argv[INDEX_ONE], napi_object)) {
469             TAG_LOGD(AAFwkTag::SERVICE_EXT, "atomic service options is used");
470             if (!AppExecFwk::UnwrapStartOptionsAndWant(env, info.argv[INDEX_ONE], startOptions, want)) {
471                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "invalid atomic service options");
472                 ThrowInvalidParamError(env, "Parse param startOptions failed, startOptions must be StartOption.");
473                 return CreateJsUndefined(env);
474             }
475             UnWrapCompletionHandlerForAtomicService(env, info.argv[INDEX_ONE], startOptions, appId);
476         }
477 
478         std::string bundleName = ATOMIC_SERVICE_PREFIX + appId;
479         TAG_LOGD(AAFwkTag::SERVICE_EXT, "bundleName: %{public}s", bundleName.c_str());
480         want.SetBundle(bundleName);
481         want.AddFlags(Want::FLAG_INSTALL_ON_DEMAND);
482         std::string startTime = std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(
483             std::chrono::system_clock::now().time_since_epoch()).count());
484         want.SetParam(Want::PARAM_RESV_START_TIME, startTime);
485         return OpenAtomicServiceInner(env, want, startOptions, startTime);
486     }
487 
OpenAtomicServiceInner(napi_env env,const AAFwk::Want & want,const AAFwk::StartOptions & options,std::string startTime)488     napi_value OpenAtomicServiceInner(napi_env env, const AAFwk::Want &want, const AAFwk::StartOptions &options,
489         std::string startTime)
490     {
491         auto innerErrorCode = std::make_shared<int>(ERR_OK);
492         NapiAsyncTask::ExecuteCallback execute = [weak = context_, want, options, innerErrorCode]() {
493             auto context = weak.lock();
494             if (!context) {
495                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "context released");
496                 *innerErrorCode = static_cast<int>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
497                 return;
498             }
499             *innerErrorCode = context->OpenAtomicService(want, options);
500         };
501         NapiAsyncTask::CompleteCallback complete = [innerErrorCode, startTime, want, observer = freeInstallObserver_,
502             weak = context_, options](
503             napi_env env, NapiAsyncTask &task, int32_t status) {
504             if (*innerErrorCode == 0) {
505                 TAG_LOGI(AAFwkTag::SERVICE_EXT, "OpenAtomicService success");
506                 return;
507             }
508             TAG_LOGI(AAFwkTag::SERVICE_EXT, "OpenAtomicService failed");
509             if (observer != nullptr) {
510                 std::string bundleName = want.GetElement().GetBundleName();
511                 std::string abilityName = want.GetElement().GetAbilityName();
512                 observer->OnInstallFinished(bundleName, abilityName, startTime, *innerErrorCode);
513             }
514             auto context = weak.lock();
515             if (context == nullptr) {
516                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "null context");
517                 return;
518             }
519             if (!options.requestId_.empty()) {
520                 nlohmann::json jsonObject = nlohmann::json {
521                     { JSON_KEY_ERR_MSG, "failed to call openAtomicService" }
522                 };
523                 context->OnRequestFailure(options.requestId_, want.GetElement(), jsonObject.dump());
524             }
525         };
526         napi_value result = nullptr;
527         AddFreeInstallObserver(env, want, nullptr, &result);
528         NapiAsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnOpenAtomicService", env,
529             CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), nullptr));
530         return result;
531     }
532 
OnStartRecentAbility(napi_env env,NapiCallbackInfo & info,bool isStartRecent=false)533     napi_value OnStartRecentAbility(napi_env env, NapiCallbackInfo& info, bool isStartRecent = false)
534     {
535         return OnStartAbility(env, info, true);
536     }
537 
OnStartAbilityAsCaller(napi_env env,NapiCallbackInfo & info)538     napi_value OnStartAbilityAsCaller(napi_env env, NapiCallbackInfo& info)
539     {
540         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
541         TAG_LOGI(AAFwkTag::SERVICE_EXT, "StartAbilityAsCaller");
542 
543         size_t unwrapArgc = 0;
544         AAFwk::Want want;
545         AAFwk::StartOptions startOptions;
546         if (!CheckStartAbilityInputParam(env, info, want, startOptions, unwrapArgc)) {
547             return CreateJsUndefined(env);
548         }
549         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
550         NapiAsyncTask::ExecuteCallback execute = [weak = context_, want, startOptions, unwrapArgc, innerErrCode]() {
551             TAG_LOGD(AAFwkTag::SERVICE_EXT, "startAbility begin");
552             auto context = weak.lock();
553             if (!context) {
554                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "context released");
555                 *innerErrCode = static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
556                 return;
557             }
558             *innerErrCode =(unwrapArgc == 1) ? context->StartAbilityAsCaller(want) :
559                 context->StartAbilityAsCaller(want, startOptions);
560         };
561         NapiAsyncTask::CompleteCallback complete =
562             [innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
563                 if (*innerErrCode == ERR_OK) {
564                     task.Resolve(env, CreateJsUndefined(env));
565                 } else if (*innerErrCode == static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)) {
566                     task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
567                 } else {
568                     task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
569                 }
570             };
571 
572         napi_value lastParam = (info.argc == unwrapArgc) ? nullptr : info.argv[unwrapArgc];
573         napi_value result = nullptr;
574         NapiAsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartAbilityAsCaller",
575             env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
576         return result;
577     }
578 
CheckStartAbilityInputParam(napi_env env,NapiCallbackInfo & info,AAFwk::Want & want,AAFwk::StartOptions & startOptions,size_t & unwrapArgc) const579     bool CheckStartAbilityInputParam(napi_env env, NapiCallbackInfo& info,
580         AAFwk::Want& want, AAFwk::StartOptions& startOptions, size_t& unwrapArgc) const
581     {
582         if (info.argc < ARGC_ONE) {
583             TAG_LOGE(AAFwkTag::SERVICE_EXT, "invalid argc");
584             ThrowTooFewParametersError(env);
585             return false;
586         }
587         unwrapArgc = ARGC_ZERO;
588         // Check input want
589         if (!AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want)) {
590             ThrowInvalidParamError(env, "Parse param want failed, must be a Want.");
591             return false;
592         }
593         ++unwrapArgc;
594         if (info.argc > ARGC_ONE && CheckTypeForNapiValue(env, info.argv[1], napi_object)) {
595             TAG_LOGD(AAFwkTag::SERVICE_EXT, "OnStartAbility start options used");
596             AppExecFwk::UnwrapStartOptions(env, info.argv[1], startOptions);
597             unwrapArgc++;
598         }
599         return true;
600     }
601 
OnStartAbilityByCall(napi_env env,NapiCallbackInfo & info)602     napi_value OnStartAbilityByCall(napi_env env, NapiCallbackInfo& info)
603     {
604         TAG_LOGI(AAFwkTag::SERVICE_EXT, "StartAbilityByCall");
605         AAFwk::Want want;
606         int32_t accountId = DEFAULT_INVAL_VALUE;
607         if (!CheckStartAbilityByCallInputParam(env, info, want, accountId)) {
608             return CreateJsUndefined(env);
609         }
610 
611         std::shared_ptr<StartAbilityByCallParameters> calls = std::make_shared<StartAbilityByCallParameters>();
612         napi_value retsult = nullptr;
613         calls->callerCallBack = std::make_shared<CallerCallBack>();
614         calls->callerCallBack->SetCallBack(GetCallBackDone(calls));
615         calls->callerCallBack->SetOnRelease(GetReleaseListen());
616 
617         auto context = context_.lock();
618         if (context == nullptr) {
619             TAG_LOGE(AAFwkTag::SERVICE_EXT, "null context");
620             ThrowError(env, AbilityErrorCode::ERROR_CODE_INNER);
621             return CreateJsUndefined(env);
622         }
623 
624         auto ret = context->StartAbilityByCall(want, calls->callerCallBack, accountId);
625         if (ret) {
626             TAG_LOGE(AAFwkTag::SERVICE_EXT, "OnStartAbilityByCall failed");
627             ThrowErrorByNativeErr(env, ret);
628             return CreateJsUndefined(env);
629         }
630 
631         if (calls->remoteCallee == nullptr) {
632             TAG_LOGD(AAFwkTag::SERVICE_EXT, "async wait execute");
633             NapiAsyncTask::ScheduleHighQos("JsAbilityContext::OnStartAbilityByCall", env,
634                 CreateAsyncTaskWithLastParam(
635                     env, nullptr, GetCallExecute(calls), GetCallComplete(calls), &retsult));
636         } else {
637             NapiAsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartAbilityByCall", env,
638                 CreateAsyncTaskWithLastParam(env, nullptr, nullptr, GetCallComplete(calls), &retsult));
639         }
640         return retsult;
641     }
642 
CheckStartAbilityByCallInputParam(napi_env env,NapiCallbackInfo & info,AAFwk::Want & want,int32_t & accountId)643     bool CheckStartAbilityByCallInputParam(
644         napi_env env, NapiCallbackInfo& info, AAFwk::Want& want, int32_t& accountId)
645     {
646         if (info.argc < ARGC_ONE) {
647             TAG_LOGE(AAFwkTag::SERVICE_EXT, "invalid argc");
648             ThrowTooFewParametersError(env);
649             return false;
650         }
651 
652         if (!AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want)) {
653             ThrowInvalidParamError(env, "Parse param want failed, must be a Want.");
654             return false;
655         }
656 
657         if (info.argc > ARGC_ONE) {
658             if (CheckTypeForNapiValue(env, info.argv[INDEX_ONE], napi_number)) {
659                 if (!ConvertFromJsValue(env, info.argv[1], accountId)) {
660                     TAG_LOGE(AAFwkTag::SERVICE_EXT, "check param accountId failed");
661                     ThrowInvalidParamError(env, "Parse param accountId failed, must be a number.");
662                     return false;
663                 }
664             } else {
665                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "param type invalid");
666                 ThrowInvalidParamError(env, "Parse param accountId failed, must be a number.");
667                 return false;
668             }
669         }
670 
671         TAG_LOGI(AAFwkTag::SERVICE_EXT, "callee:%{public}s.%{public}s.",
672             want.GetBundle().c_str(),
673             want.GetElement().GetAbilityName().c_str());
674         return true;
675     }
676 
GetCallComplete(std::shared_ptr<StartAbilityByCallParameters> calls)677     NapiAsyncTask::CompleteCallback GetCallComplete(std::shared_ptr<StartAbilityByCallParameters> calls)
678     {
679         auto callComplete = [weak = context_, calldata = calls] (
680             napi_env env, NapiAsyncTask& task, int32_t) {
681             if (calldata->err != 0) {
682                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "callComplete err: %{public}d", calldata->err);
683                 ClearFailedCallConnection(weak, calldata->callerCallBack);
684                 task.Reject(env, CreateJsError(env, calldata->err, "callComplete err."));
685                 return;
686             }
687 
688             auto context = weak.lock();
689             if (context != nullptr && calldata->callerCallBack != nullptr && calldata->remoteCallee != nullptr) {
690                 auto releaseCallFunc = [weak] (
691                     const std::shared_ptr<CallerCallBack> &callback) -> ErrCode {
692                     auto contextForRelease = weak.lock();
693                     if (contextForRelease == nullptr) {
694                         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null contextForRelease");
695                         return -1;
696                     }
697                     return contextForRelease->ReleaseCall(callback);
698                 };
699                 task.Resolve(env,
700                     CreateJsCallerComplex(
701                         env, releaseCallFunc, calldata->remoteCallee, calldata->callerCallBack));
702             } else {
703                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "null %{public}s",
704                     context == nullptr ? "context" :
705                         (calldata->remoteCallee == nullptr ? "remoteCallee" : "callerCallBack"));
706                 task.Reject(env, CreateJsError(env, -1, "Create Call Failed."));
707             }
708 
709             TAG_LOGD(AAFwkTag::SERVICE_EXT, "end");
710         };
711         return callComplete;
712     }
713 
GetCallExecute(std::shared_ptr<StartAbilityByCallParameters> calls)714     NapiAsyncTask::ExecuteCallback GetCallExecute(std::shared_ptr<StartAbilityByCallParameters> calls)
715     {
716         auto callExecute = [calldata = calls] () {
717             constexpr int callerTimeOut = 10; // 10s
718             std::unique_lock<std::mutex> lock(calldata->mutexlock);
719             if (calldata->remoteCallee != nullptr) {
720                 TAG_LOGI(AAFwkTag::SERVICE_EXT, "callee not null");
721                 return;
722             }
723 
724             if (calldata->condition.wait_for(lock, std::chrono::seconds(callerTimeOut)) == std::cv_status::timeout) {
725                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "waiting callee timeout");
726                 calldata->err = -1;
727             }
728             TAG_LOGD(AAFwkTag::SERVICE_EXT, "exit");
729         };
730         return callExecute;
731     }
732 
GetCallBackDone(std::shared_ptr<StartAbilityByCallParameters> calls)733     CallerCallBack::CallBackClosure GetCallBackDone(std::shared_ptr<StartAbilityByCallParameters> calls)
734     {
735         auto callBackDone = [calldata = calls] (const sptr<IRemoteObject> &obj) {
736             TAG_LOGD(AAFwkTag::SERVICE_EXT, "mutexlock");
737             std::unique_lock<std::mutex> lock(calldata->mutexlock);
738             TAG_LOGD(AAFwkTag::SERVICE_EXT, "remoteCallee assignment");
739             calldata->remoteCallee = obj;
740             calldata->condition.notify_all();
741             TAG_LOGI(AAFwkTag::SERVICE_EXT, "end");
742         };
743         return callBackDone;
744     }
745 
GetReleaseListen()746     CallerCallBack::OnReleaseClosure GetReleaseListen()
747     {
748         auto releaseListen = [](const std::string &str) {
749             TAG_LOGD(AAFwkTag::SERVICE_EXT, "called, %{public}s", str.c_str());
750         };
751         return releaseListen;
752     }
753 
OnStartAbilityWithAccount(napi_env env,NapiCallbackInfo & info)754     napi_value OnStartAbilityWithAccount(napi_env env, NapiCallbackInfo& info)
755     {
756         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
757         TAG_LOGI(AAFwkTag::SERVICE_EXT, "StartAbilityWithAccount");
758 
759         size_t unwrapArgc = 0;
760         AAFwk::Want want;
761         int32_t accountId = 0;
762         if (!CheckStartAbilityWithAccountInputParam(env, info, want, accountId, unwrapArgc)) {
763             return CreateJsUndefined(env);
764         }
765 
766         AAFwk::StartOptions startOptions;
767         if (info.argc > ARGC_TWO && CheckTypeForNapiValue(env, info.argv[INDEX_TWO], napi_object)) {
768             TAG_LOGD(AAFwkTag::SERVICE_EXT, "start options used");
769             AppExecFwk::UnwrapStartOptions(env, info.argv[INDEX_TWO], startOptions);
770             unwrapArgc++;
771         }
772 
773         if ((want.GetFlags() & Want::FLAG_INSTALL_ON_DEMAND) == Want::FLAG_INSTALL_ON_DEMAND) {
774             std::string startTime = std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
775                 system_clock::now().time_since_epoch()).count());
776             want.SetParam(Want::PARAM_RESV_START_TIME, startTime);
777         }
778         auto innerErrorCode = std::make_shared<int>(ERR_OK);
779         auto execute = GetStartAbilityExecFunc(want, startOptions, accountId, unwrapArgc != ARGC_TWO, innerErrorCode);
780         auto complete = GetSimpleCompleteFunc(innerErrorCode);
781 
782         napi_value lastParam = (info.argc == unwrapArgc) ? nullptr : info.argv[unwrapArgc];
783         napi_value result = nullptr;
784         if ((want.GetFlags() & Want::FLAG_INSTALL_ON_DEMAND) == Want::FLAG_INSTALL_ON_DEMAND) {
785             AddFreeInstallObserver(env, want, lastParam, &result);
786             NapiAsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartAbilityWithAccount", env,
787                 CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), nullptr, nullptr));
788         } else {
789             NapiAsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartAbilityWithAccount", env,
790                 CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
791         }
792         return result;
793     }
794 
CheckStartAbilityWithAccountInputParam(napi_env env,NapiCallbackInfo & info,AAFwk::Want & want,int32_t & accountId,size_t & unwrapArgc) const795     bool CheckStartAbilityWithAccountInputParam(
796         napi_env env, NapiCallbackInfo& info,
797         AAFwk::Want& want, int32_t& accountId, size_t& unwrapArgc) const
798     {
799         if (info.argc < ARGC_TWO) {
800             TAG_LOGE(AAFwkTag::SERVICE_EXT, "invalid argc");
801             ThrowTooFewParametersError(env);
802             return false;
803         }
804         unwrapArgc = ARGC_ZERO;
805         // Check input want
806         if (!AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want)) {
807             ThrowInvalidParamError(env, "Parse param want failed, must be a Want.");
808             return false;
809         }
810         ++unwrapArgc;
811         if (!AppExecFwk::UnwrapInt32FromJS2(env, info.argv[INDEX_ONE], accountId)) {
812             ThrowInvalidParamError(env, "Parse param accountId failed, must be a number.");
813             return false;
814         }
815         ++unwrapArgc;
816         return true;
817     }
818 
OnStartUIAbilities(napi_env env,NapiCallbackInfo & info)819     napi_value OnStartUIAbilities(napi_env env, NapiCallbackInfo& info)
820     {
821         TAG_LOGI(AAFwkTag::SERVICE_EXT, "call OnStartUIAbilities");
822         if (info.argc < ARGC_ONE) {
823             TAG_LOGE(AAFwkTag::SERVICE_EXT, "Too few parameters.");
824             ThrowTooFewParametersError(env);
825             return CreateJsUndefined(env);
826         }
827 
828         std::vector<AAFwk::Want> wantList;
829         std::string requestKey = std::to_string(std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::
830             system_clock::now().time_since_epoch()).count());
831 
832         if (!UnwrapWantList(env, info, wantList)) {
833             TAG_LOGE(AAFwkTag::SERVICE_EXT, "Unwrap wantList param failed.");
834             return CreateJsUndefined(env);
835         }
836 
837         TAG_LOGD(AAFwkTag::SERVICE_EXT, "startUIAbilities wantListLength: %{public}zu", wantList.size());
838 
839         JsDeferredCallback callback(env);
840         JsStartAbilitiesObserver::GetInstance().AddObserver(requestKey, callback);
841         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
842         NapiAsyncTask::ExecuteCallback execute = [weak = context_, wantList, requestKey, innerErrCode]() {
843             auto context = weak.lock();
844             if (!context) {
845                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "null context");
846                 *innerErrCode = static_cast<int>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
847                 return;
848             }
849             *innerErrCode = context->StartUIAbilities(wantList, requestKey);
850         };
851 
852         NapiAsyncTask::CompleteCallback complete = [innerErrCode, weak = context_, requestKey]
853             (napi_env, NapiAsyncTask&, int32_t) {
854                 TAG_LOGI(AAFwkTag::SERVICE_EXT, "startUIAbilities complete innerErrCode: %{public}d", *innerErrCode);
855                 if (*innerErrCode == AAFwk::START_UI_ABILITIES_WAITING_SPECIFIED_CODE)  {
856                     TAG_LOGI(AAFwkTag::SERVICE_EXT, "startUIAbilities waiting specified.");
857                     return;
858                 }
859                 JsStartAbilitiesObserver::GetInstance().HandleFinished(requestKey, *innerErrCode);
860         };
861 
862         NapiAsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartUIAbilities", env,
863             CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), nullptr));
864         return callback.result;
865     }
866 
UnwrapWantList(napi_env env,NapiCallbackInfo & info,std::vector<AAFwk::Want> & wantList)867     bool UnwrapWantList(napi_env env, NapiCallbackInfo &info, std::vector<AAFwk::Want> &wantList)
868     {
869         AppExecFwk::ComplexArrayData jsWantList;
870         if (!AppExecFwk::UnwrapArrayComplexFromJS(env, info.argv[INDEX_ZERO], jsWantList)) {
871             TAG_LOGE(AAFwkTag::SERVICE_EXT, "wantList not array.");
872             ThrowInvalidParamError(env, "WantList is not an array.");
873             return false;
874         }
875 
876         size_t jsWantSize = jsWantList.objectList.size();
877         if (jsWantSize < INDEX_ONE || jsWantSize > INDEX_FOUR) {
878             TAG_LOGE(AAFwkTag::SERVICE_EXT, "wantList size not support");
879             ThrowErrorByNativeErr(env, AAFwk::START_UI_ABILITIES_WANT_LIST_SIZE_ERROR);
880             return false;
881         }
882 
883         for (uint32_t index = 0; index < jsWantSize; index++) {
884             AAFwk::Want curWant;
885             if (!OHOS::AppExecFwk::UnwrapWant(env, jsWantList.objectList[index], curWant)) {
886                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "startUIAbilities parse want failed");
887                 ThrowInvalidParamError(env, "Parse param want failed, want must be Want.");
888                 return false;
889             }
890             TAG_LOGD(AAFwkTag::SERVICE_EXT, "startUIAbilities ability:%{public}s",
891                 curWant.GetElement().GetAbilityName().c_str());
892             wantList.emplace_back(curWant);
893         }
894         return true;
895     }
896 
CheckConnectAbilityWithAccountInputParam(napi_env env,NapiCallbackInfo & info,AAFwk::Want & want,int32_t & accountId,sptr<JSServiceExtensionConnection> & connection) const897     bool CheckConnectAbilityWithAccountInputParam(
898         napi_env env, NapiCallbackInfo& info,
899         AAFwk::Want& want, int32_t& accountId, sptr<JSServiceExtensionConnection>& connection) const
900     {
901         if (info.argc < ARGC_THREE) {
902             TAG_LOGE(AAFwkTag::SERVICE_EXT, "invalid argc");
903             ThrowTooFewParametersError(env);
904             return false;
905         }
906         // Check input want
907         if (!AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want)) {
908             ThrowInvalidParamError(env, "Parse param want failed, must be a Want.");
909             return false;
910         }
911         if (!AppExecFwk::UnwrapInt32FromJS2(env, info.argv[INDEX_ONE], accountId)) {
912             ThrowInvalidParamError(env, "Parse param accountId failed, must be a number.");
913             return false;
914         }
915         if (!CheckConnectionParam(env, info.argv[INDEX_TWO], connection, want, accountId)) {
916             ThrowInvalidParamError(env, "Parse param options failed, must be a ConnectOptions.");
917             return false;
918         }
919         return true;
920     }
921 
OnTerminateAbility(napi_env env,NapiCallbackInfo & info)922     napi_value OnTerminateAbility(napi_env env, NapiCallbackInfo& info)
923     {
924         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
925         TAG_LOGI(AAFwkTag::SERVICE_EXT, "TerminateAbility");
926         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
927         NapiAsyncTask::ExecuteCallback execute = [weak = context_, innerErrCode]() {
928             auto context = weak.lock();
929             if (!context) {
930                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "context released");
931                 *innerErrCode = static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
932                 return;
933             }
934             *innerErrCode = context->TerminateAbility();
935         };
936         NapiAsyncTask::CompleteCallback complete =
937             [innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
938                 if (*innerErrCode == ERR_OK) {
939                     task.Resolve(env, CreateJsUndefined(env));
940                 } else if (*innerErrCode == static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)) {
941                     task.Reject(env, CreateJsError(env, *innerErrCode, "context is released"));
942                 } else {
943                     task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
944                 }
945             };
946 
947         napi_value lastParam = (info.argc == ARGC_ZERO) ? nullptr : info.argv[INDEX_ZERO];
948         napi_value result = nullptr;
949         NapiAsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnTerminateAbility",
950             env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
951         return result;
952     }
953 
OnConnectAbility(napi_env env,NapiCallbackInfo & info)954     napi_value OnConnectAbility(napi_env env, NapiCallbackInfo& info)
955     {
956         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
957         TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
958         // Check params count
959         if (info.argc < ARGC_TWO) {
960             TAG_LOGE(AAFwkTag::SERVICE_EXT, "invalid argc");
961             ThrowTooFewParametersError(env);
962             return CreateJsUndefined(env);
963         }
964         // Unwrap want and connection
965         AAFwk::Want want;
966         sptr<JSServiceExtensionConnection> connection = new JSServiceExtensionConnection(env);
967         if (!AppExecFwk::UnwrapWant(env, info.argv[0], want)) {
968             ThrowInvalidParamError(env, "Parse param want failed, must be a Want.");
969             return CreateJsUndefined(env);
970         }
971         if (!CheckConnectionParam(env, info.argv[1], connection, want)) {
972             ThrowInvalidParamError(env, "Parse param options failed, must be a ConnectOptions.");
973             return CreateJsUndefined(env);
974         }
975         int64_t connectId = connection->GetConnectionId();
976         auto innerErrorCode = std::make_shared<int>(ERR_OK);
977         auto execute = GetConnectAbilityExecFunc(want, connection, connectId, innerErrorCode);
978         NapiAsyncTask::CompleteCallback complete = [connection, connectId, innerErrorCode](napi_env env,
979             NapiAsyncTask& task, int32_t status) {
980             if (*innerErrorCode == 0) {
981                 TAG_LOGI(AAFwkTag::SERVICE_EXT, "Connect ability success");
982                 task.ResolveWithNoError(env, CreateJsUndefined(env));
983                 return;
984             }
985 
986             TAG_LOGE(AAFwkTag::SERVICE_EXT, "Connect ability failed");
987             int32_t errcode = static_cast<int32_t>(AbilityRuntime::GetJsErrorCodeByNativeError(*innerErrorCode));
988             if (errcode) {
989                 connection->CallJsFailed(errcode);
990                 RemoveConnection(connectId);
991             }
992         };
993         napi_value result = nullptr;
994         NapiAsyncTask::ScheduleHighQos("JSServiceExtensionConnection::OnConnectAbility",
995             env, CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result));
996         return CreateJsValue(env, connectId);
997     }
998 
OnConnectAbilityWithAccount(napi_env env,NapiCallbackInfo & info)999     napi_value OnConnectAbilityWithAccount(napi_env env, NapiCallbackInfo& info)
1000     {
1001         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
1002         TAG_LOGI(AAFwkTag::SERVICE_EXT, "ConnectAbilityWithAccount");
1003         // Unwrap want, accountId and connection
1004         AAFwk::Want want;
1005         int32_t accountId = 0;
1006         sptr<JSServiceExtensionConnection> connection = new JSServiceExtensionConnection(env);
1007         if (!CheckConnectAbilityWithAccountInputParam(env, info, want, accountId, connection)) {
1008             return CreateJsUndefined(env);
1009         }
1010         int64_t connectId = connection->GetConnectionId();
1011         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
1012         NapiAsyncTask::ExecuteCallback execute = [weak = context_,
1013             want, accountId, connection, connectId, innerErrCode]() {
1014             auto context = weak.lock();
1015             if (!context) {
1016                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "context released");
1017                 *innerErrCode = static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
1018                 return;
1019             }
1020             TAG_LOGD(AAFwkTag::SERVICE_EXT, "connection:%{public}d", static_cast<int32_t>(connectId));
1021             *innerErrCode = context->ConnectAbilityWithAccount(want, accountId, connection);
1022         };
1023         NapiAsyncTask::CompleteCallback complete =
1024             [connection, connectId, innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
1025                 if (*innerErrCode == static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)) {
1026                     task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode, "Context is released"));
1027                     RemoveConnection(connectId);
1028                 } else {
1029                     int32_t errcode = static_cast<int32_t>(AbilityRuntime::GetJsErrorCodeByNativeError(*innerErrCode));
1030                     if (errcode) {
1031                         connection->CallJsFailed(errcode);
1032                         RemoveConnection(connectId);
1033                     }
1034                     task.Resolve(env, CreateJsUndefined(env));
1035                 }
1036             };
1037         napi_value result = nullptr;
1038         NapiAsyncTask::ScheduleHighQos("JSServiceExtensionConnection::OnConnectAbilityWithAccount",
1039             env, CreateAsyncTaskWithLastParam(env, nullptr, nullptr, std::move(complete), &result));
1040         return CreateJsValue(env, connectId);
1041     }
1042 
CheckConnectionParam(napi_env env,napi_value value,sptr<JSServiceExtensionConnection> & connection,AAFwk::Want & want,int32_t accountId=-1) const1043     bool CheckConnectionParam(napi_env env, napi_value value,
1044         sptr<JSServiceExtensionConnection>& connection, AAFwk::Want& want, int32_t accountId = -1) const
1045     {
1046         if (!CheckTypeForNapiValue(env, value, napi_object)) {
1047             TAG_LOGE(AAFwkTag::SERVICE_EXT, "get connection obj failed");
1048             return false;
1049         }
1050         connection->SetJsConnectionObject(value);
1051         ConnectionKey key;
1052         {
1053             std::lock_guard guard(g_connectsMutex);
1054             key.id = g_serialNumber;
1055             key.want = want;
1056             key.accountId = accountId;
1057             connection->SetConnectionId(key.id);
1058             g_connects.emplace(key, connection);
1059             if (g_serialNumber < INT32_MAX) {
1060                 g_serialNumber++;
1061             } else {
1062                 g_serialNumber = 0;
1063             }
1064         }
1065         TAG_LOGD(AAFwkTag::SERVICE_EXT, "Unable to find connection, make new one");
1066         return true;
1067     }
1068 
OnDisconnectAbility(napi_env env,NapiCallbackInfo & info)1069     napi_value OnDisconnectAbility(napi_env env, NapiCallbackInfo& info)
1070     {
1071         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
1072         TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
1073         if (info.argc < ARGC_ONE) {
1074             TAG_LOGE(AAFwkTag::SERVICE_EXT, "invalid argc");
1075             ThrowTooFewParametersError(env);
1076             return CreateJsUndefined(env);
1077         }
1078         int64_t connectId = -1;
1079         if (!AppExecFwk::UnwrapInt64FromJS2(env, info.argv[INDEX_ZERO], connectId)) {
1080             ThrowInvalidParamError(env, "Parse param connection failed, must be a number.");
1081             return CreateJsUndefined(env);
1082         }
1083         AAFwk::Want want;
1084         sptr<JSServiceExtensionConnection> connection = nullptr;
1085         int32_t accountId = -1;
1086         FindConnection(want, connection, connectId, accountId);
1087         // begin disconnect
1088         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
1089         NapiAsyncTask::ExecuteCallback execute = [weak = context_, want, connection, accountId, innerErrCode]() {
1090             auto context = weak.lock();
1091             if (!context) {
1092                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "context released");
1093                 *innerErrCode = static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
1094                 return;
1095             }
1096             if (!connection) {
1097                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "null connection");
1098                 *innerErrCode = static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INNER);
1099                 return;
1100             }
1101             TAG_LOGD(AAFwkTag::SERVICE_EXT, "context->DisconnectAbility");
1102             *innerErrCode = context->DisconnectAbility(want, connection, accountId);
1103         };
1104         NapiAsyncTask::CompleteCallback complete =
1105             [innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
1106                 if (*innerErrCode == ERR_OK) {
1107                     task.Resolve(env, CreateJsUndefined(env));
1108                 } else if (*innerErrCode == static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)) {
1109                     task.Reject(env, CreateJsError(env, *innerErrCode, "Context is released"));
1110                 } else if (*innerErrCode == static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INNER)) {
1111                     task.Reject(env, CreateJsError(env, *innerErrCode, "not found connection"));
1112                 } else {
1113                     task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
1114                 }
1115             };
1116         napi_value lastParam = (info.argc == ARGC_ONE) ? nullptr : info.argv[INDEX_ONE];
1117         napi_value result = nullptr;
1118         NapiAsyncTask::Schedule("JSServiceExtensionConnection::OnDisconnectAbility",
1119             env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
1120         return result;
1121     }
1122 
FindConnection(AAFwk::Want & want,sptr<JSServiceExtensionConnection> & connection,int64_t & connectId,int32_t & accountId) const1123     void FindConnection(AAFwk::Want& want, sptr<JSServiceExtensionConnection>& connection, int64_t& connectId,
1124         int32_t &accountId) const
1125     {
1126         TAG_LOGI(AAFwkTag::SERVICE_EXT, "Disconnect ability:%{public}d",
1127             static_cast<int32_t>(connectId));
1128         std::lock_guard guard(g_connectsMutex);
1129         auto item = std::find_if(g_connects.begin(),
1130             g_connects.end(),
1131             [&connectId](const auto &obj) {
1132                 return connectId == obj.first.id;
1133             });
1134         if (item != g_connects.end()) {
1135             // match id
1136             want = item->first.want;
1137             connection = item->second;
1138             accountId = item->first.accountId;
1139             TAG_LOGD(AAFwkTag::SERVICE_EXT, "find conn ability exist");
1140         }
1141         return;
1142     }
1143 
OnStartExtensionAbility(napi_env env,NapiCallbackInfo & info)1144     napi_value OnStartExtensionAbility(napi_env env, NapiCallbackInfo& info)
1145     {
1146         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
1147         TAG_LOGI(AAFwkTag::SERVICE_EXT, "called");
1148         if (info.argc < ARGC_ONE) {
1149             TAG_LOGE(AAFwkTag::SERVICE_EXT, "invalid argc");
1150             ThrowTooFewParametersError(env);
1151             return CreateJsUndefined(env);
1152         }
1153         AAFwk::Want want;
1154         if (!AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want)) {
1155             ThrowInvalidParamError(env, "Parse param want failed, must be a Want.");
1156             return CreateJsUndefined(env);
1157         }
1158         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
1159         NapiAsyncTask::ExecuteCallback execute = [weak = context_, want, innerErrCode]() {
1160             auto context = weak.lock();
1161             if (!context) {
1162                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "context released");
1163                 *innerErrCode = static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
1164                 return;
1165             }
1166             *innerErrCode = context->StartServiceExtensionAbility(want);
1167         };
1168         NapiAsyncTask::CompleteCallback complete =
1169             [innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
1170                 if (*innerErrCode == ERR_OK) {
1171                     task.Resolve(env, CreateJsUndefined(env));
1172                 } else if (*innerErrCode == static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)) {
1173                     task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
1174                 } else {
1175                     task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
1176                 }
1177             };
1178 
1179         napi_value lastParam = (info.argc <= ARGC_ONE) ? nullptr : info.argv[ARGC_ONE];
1180         napi_value result = nullptr;
1181         NapiAsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartExtensionAbility",
1182             env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
1183         return result;
1184     }
1185 
OnStartUIServiceExtension(napi_env env,NapiCallbackInfo & info)1186     napi_value OnStartUIServiceExtension(napi_env env, NapiCallbackInfo& info)
1187     {
1188         TAG_LOGI(AAFwkTag::SERVICE_EXT, "called");
1189         if (info.argc <ARGC_TWO) {
1190             TAG_LOGE(AAFwkTag::SERVICE_EXT, "invalid argc");
1191             ThrowTooFewParametersError(env);
1192             return CreateJsUndefined(env);
1193         }
1194 
1195         AAFwk::Want want;
1196         if (!AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want)) {
1197             TAG_LOGE(AAFwkTag::SERVICE_EXT, "parse want failed");
1198             ThrowInvalidParamError(env, "Parse param want failed, want must be Want.");
1199             return CreateJsUndefined(env);
1200         }
1201         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
1202         NapiAsyncTask::ExecuteCallback execute = [weak = context_, want, innerErrCode]() {
1203             auto context = weak.lock();
1204             if (!context) {
1205                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "context released");
1206                 *innerErrCode = static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
1207                 return;
1208             }
1209             *innerErrCode = context->StartUIServiceExtensionAbility(want);
1210         };
1211         NapiAsyncTask::CompleteCallback complete =
1212             [innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
1213                 if (*innerErrCode == ERR_OK) {
1214                     task.ResolveWithNoError(env, CreateJsUndefined(env));
1215                 } else if (*innerErrCode == static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)) {
1216                     task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
1217                 } else {
1218                     task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
1219                 }
1220             };
1221 
1222         napi_value lastParam = (info.argc > ARGC_ONE) ? info.argv[INDEX_ONE] : nullptr;
1223         napi_value result = nullptr;
1224         NapiAsyncTask::ScheduleHighQos("JsAbilityContext::OnStartUIServiceExtension",
1225             env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
1226         return result;
1227     }
1228 
OnStartExtensionAbilityWithAccount(napi_env env,NapiCallbackInfo & info)1229     napi_value OnStartExtensionAbilityWithAccount(napi_env env, NapiCallbackInfo& info)
1230     {
1231         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
1232         TAG_LOGI(AAFwkTag::SERVICE_EXT, "called");
1233         AAFwk::Want want;
1234         int32_t accountId = -1;
1235         size_t unwrapArgc = 0;
1236         if (!CheckStartAbilityWithAccountInputParam(env, info, want, accountId, unwrapArgc)) {
1237             return CreateJsUndefined(env);
1238         }
1239         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
1240         NapiAsyncTask::ExecuteCallback execute = [weak = context_, want, accountId, innerErrCode]() {
1241             auto context = weak.lock();
1242             if (!context) {
1243                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "context released");
1244                 *innerErrCode = static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
1245                 return;
1246             }
1247             *innerErrCode = context->StartServiceExtensionAbility(want, accountId);
1248         };
1249         NapiAsyncTask::CompleteCallback complete =
1250             [innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
1251                 if (*innerErrCode == ERR_OK) {
1252                     task.Resolve(env, CreateJsUndefined(env));
1253                 } else if (*innerErrCode == static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)) {
1254                     task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
1255                 } else {
1256                     task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
1257                 }
1258             };
1259 
1260         napi_value lastParam = (info.argc <= ARGC_TWO) ? nullptr : info.argv[ARGC_TWO];
1261         napi_value result = nullptr;
1262         NapiAsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartExtensionAbilityWithAccount",
1263             env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
1264         return result;
1265     }
1266 
OnStopExtensionAbility(napi_env env,NapiCallbackInfo & info)1267     napi_value OnStopExtensionAbility(napi_env env, NapiCallbackInfo& info)
1268     {
1269         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
1270         TAG_LOGI(AAFwkTag::SERVICE_EXT, "called");
1271         if (info.argc < ARGC_ONE) {
1272             TAG_LOGE(AAFwkTag::SERVICE_EXT, "invalid argc");
1273             ThrowTooFewParametersError(env);
1274             return CreateJsUndefined(env);
1275         }
1276         AAFwk::Want want;
1277         if (!AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want)) {
1278             ThrowInvalidParamError(env, "Parse param want failed, must be a Want.");
1279             return CreateJsUndefined(env);
1280         }
1281         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
1282         NapiAsyncTask::ExecuteCallback execute = [weak = context_, want, innerErrCode]() {
1283             auto context = weak.lock();
1284             if (!context) {
1285                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "context released");
1286                 *innerErrCode = static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
1287                 return;
1288             }
1289             *innerErrCode = context->StopServiceExtensionAbility(want);
1290         };
1291         NapiAsyncTask::CompleteCallback complete =
1292             [innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
1293                 if (*innerErrCode == ERR_OK) {
1294                     task.Resolve(env, CreateJsUndefined(env));
1295                 } else if (*innerErrCode == static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)) {
1296                     task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
1297                 } else {
1298                     task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
1299                 }
1300             };
1301 
1302         napi_value lastParam = (info.argc <= ARGC_ONE) ? nullptr : info.argv[ARGC_ONE];
1303         napi_value result = nullptr;
1304         NapiAsyncTask::Schedule("JSServiceExtensionContext::OnStopExtensionAbility",
1305             env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
1306         return result;
1307     }
1308 
OnStopExtensionAbilityWithAccount(napi_env env,NapiCallbackInfo & info)1309     napi_value OnStopExtensionAbilityWithAccount(napi_env env, NapiCallbackInfo& info)
1310     {
1311         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
1312         TAG_LOGI(AAFwkTag::SERVICE_EXT, "called");
1313         AAFwk::Want want;
1314         int32_t accountId = -1;
1315         size_t unwrapArgc = 0;
1316         if (!CheckStartAbilityWithAccountInputParam(env, info, want, accountId, unwrapArgc)) {
1317             return CreateJsUndefined(env);
1318         }
1319         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
1320         NapiAsyncTask::ExecuteCallback execute = [weak = context_, want, accountId, innerErrCode]() {
1321             auto context = weak.lock();
1322             if (!context) {
1323                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "context released");
1324                 *innerErrCode = static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
1325                 return;
1326             }
1327             *innerErrCode = context->StopServiceExtensionAbility(want, accountId);
1328         };
1329 
1330         NapiAsyncTask::CompleteCallback complete =
1331             [innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
1332                 if (*innerErrCode == ERR_OK) {
1333                     task.Resolve(env, CreateJsUndefined(env));
1334                 } else if (*innerErrCode == static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)) {
1335                     task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
1336                 } else {
1337                     task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
1338                 }
1339             };
1340 
1341         napi_value lastParam = (info.argc <= ARGC_TWO) ? nullptr : info.argv[ARGC_TWO];
1342         napi_value result = nullptr;
1343         NapiAsyncTask::Schedule("JSServiceExtensionContext::OnStopExtensionAbilityWithAccount",
1344             env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
1345         return result;
1346     }
1347 
OnRequestModalUIExtension(napi_env env,NapiCallbackInfo & info)1348     napi_value OnRequestModalUIExtension(napi_env env, NapiCallbackInfo& info)
1349     {
1350         TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
1351 
1352         if (info.argc < ARGC_ONE) {
1353             ThrowTooFewParametersError(env);
1354             return CreateJsUndefined(env);
1355         }
1356 
1357         AAFwk::Want want;
1358         if (!AppExecFwk::UnwrapWant(env, info.argv[0], want)) {
1359             TAG_LOGE(AAFwkTag::SERVICE_EXT, "parse want failed");
1360             ThrowInvalidParamError(env, "Parse param want failed, must be a Want.");
1361             return CreateJsUndefined(env);
1362         }
1363 
1364         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
1365         NapiAsyncTask::ExecuteCallback execute = [serviceContext = context_, want, innerErrCode]() {
1366             auto context = serviceContext.lock();
1367             if (!context) {
1368                 TAG_LOGE(AAFwkTag::APPKIT, "context released");
1369                 *innerErrCode = static_cast<int>(AbilityErrorCode::ERROR_CODE_INNER);
1370                 return;
1371             }
1372             *innerErrCode = AAFwk::AbilityManagerClient::GetInstance()->RequestModalUIExtension(want);
1373         };
1374         NapiAsyncTask::CompleteCallback complete = [innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
1375             if (*innerErrCode == ERR_OK) {
1376                 task.Resolve(env, CreateJsUndefined(env));
1377             } else {
1378                 TAG_LOGE(AAFwkTag::APPKIT, "OnRequestModalUIExtension failed %{public}d", *innerErrCode);
1379                 task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
1380             }
1381         };
1382 
1383         napi_value lastParam = (info.argc > ARGC_ONE) ? info.argv[ARGC_ONE] : nullptr;
1384         napi_value result = nullptr;
1385         NapiAsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnRequestModalUIExtension",
1386             env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
1387         return result;
1388     }
1389 
ParsePreStartMissionArgs(const napi_env & env,const NapiCallbackInfo & info,std::string & bundleName,std::string & moduleName,std::string & abilityName,std::string & startTime)1390     bool ParsePreStartMissionArgs(const napi_env &env, const NapiCallbackInfo &info, std::string& bundleName,
1391         std::string& moduleName, std::string& abilityName, std::string& startTime)
1392     {
1393         if (info.argc < ARGC_FOUR) {
1394             TAG_LOGE(AAFwkTag::SERVICE_EXT, "invalid argc");
1395             ThrowTooFewParametersError(env);
1396             return false;
1397         }
1398 
1399         std::string args[ARGC_FOUR];
1400         for (size_t i = 0; i < ARGC_FOUR; i++) {
1401             if (!CheckTypeForNapiValue(env, info.argv[i], napi_string)) {
1402                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "param must be string");
1403                 return false;
1404             }
1405             if (!ConvertFromJsValue(env, info.argv[i], args[i])) {
1406                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "param invalid");
1407                 return false;
1408             }
1409         }
1410 
1411         bundleName = args[INDEX_ZERO];
1412         moduleName = args[INDEX_ONE];
1413         abilityName = args[INDEX_TWO];
1414         startTime = args[INDEX_THREE];
1415 
1416         return true;
1417     }
1418 
OnPreStartMission(napi_env env,NapiCallbackInfo & info)1419     napi_value OnPreStartMission(napi_env env, NapiCallbackInfo& info)
1420     {
1421         TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
1422         if (info.argc < ARGC_FOUR) {
1423             ThrowTooFewParametersError(env);
1424             return CreateJsUndefined(env);
1425         }
1426 
1427         std::string bundleName;
1428         std::string moduleName;
1429         std::string abilityName;
1430         std::string startTime;
1431         if (!ParsePreStartMissionArgs(env, info, bundleName, moduleName, abilityName, startTime)) {
1432             TAG_LOGE(AAFwkTag::SERVICE_EXT, "parse preStartMission failed");
1433             ThrowInvalidParamError(env, "Parse params failed, params must be strings.");
1434             return CreateJsUndefined(env);
1435         }
1436 
1437         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
1438         NapiAsyncTask::ExecuteCallback execute = [weak = context_,
1439             bundleName, moduleName, abilityName, startTime, innerErrCode]() {
1440                 auto context = weak.lock();
1441                 if (!context) {
1442                     TAG_LOGW(AAFwkTag::SERVICE_EXT, "context released");
1443                     *innerErrCode = static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
1444                     return;
1445                 }
1446                 *innerErrCode = context->PreStartMission(bundleName, moduleName, abilityName, startTime);
1447             };
1448 
1449         NapiAsyncTask::CompleteCallback complete =
1450             [innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
1451                 if (*innerErrCode == ERR_OK) {
1452                     task.ResolveWithNoError(env, CreateJsUndefined(env));
1453                 } else if (*innerErrCode == static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)) {
1454                     task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
1455                 } else {
1456                     task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
1457                 }
1458             };
1459 
1460         napi_value result = nullptr;
1461         NapiAsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnPreStartMission",
1462             env, CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result));
1463         return result;
1464     }
1465 
GetStartAbilityExecFunc(const AAFwk::Want & want,const AAFwk::StartOptions & startOptions,int32_t userId,bool useOption,std::shared_ptr<int> retCode)1466     NapiAsyncTask::ExecuteCallback GetStartAbilityExecFunc(const AAFwk::Want &want,
1467         const AAFwk::StartOptions &startOptions, int32_t userId, bool useOption, std::shared_ptr<int> retCode)
1468     {
1469         return [weak = context_, want, startOptions, useOption, userId, retCode,
1470             &observer = freeInstallObserver_]() {
1471             TAG_LOGD(AAFwkTag::SERVICE_EXT, "startAbility exec begin");
1472             if (!retCode) {
1473                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "retCode null");
1474                 return;
1475             }
1476             auto context = weak.lock();
1477             if (!context) {
1478                 TAG_LOGW(AAFwkTag::SERVICE_EXT, "context released");
1479                 *retCode = static_cast<int>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
1480                 return;
1481             }
1482 
1483             useOption ? *retCode = context->StartAbilityWithAccount(want, userId, startOptions) :
1484                 *retCode = context->StartAbilityWithAccount(want, userId);
1485             if ((want.GetFlags() & Want::FLAG_INSTALL_ON_DEMAND) == Want::FLAG_INSTALL_ON_DEMAND &&
1486                 *retCode != 0 && observer != nullptr) {
1487                 std::string bundleName = want.GetElement().GetBundleName();
1488                 std::string abilityName = want.GetElement().GetAbilityName();
1489                 std::string startTime = want.GetStringParam(Want::PARAM_RESV_START_TIME);
1490                 observer->OnInstallFinished(bundleName, abilityName, startTime, *retCode);
1491             }
1492         };
1493     }
1494 
GetSimpleCompleteFunc(std::shared_ptr<int> retCode)1495     NapiAsyncTask::CompleteCallback GetSimpleCompleteFunc(std::shared_ptr<int> retCode)
1496     {
1497         return [retCode](napi_env env, NapiAsyncTask& task, int32_t) {
1498             if (!retCode) {
1499                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "StartAbility failed");
1500                 task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INNER));
1501                 return;
1502             }
1503             if (*retCode == 0) {
1504                 TAG_LOGD(AAFwkTag::SERVICE_EXT, "StartAbility success");
1505                 task.Resolve(env, CreateJsUndefined(env));
1506             } else {
1507                 task.Reject(env, CreateJsErrorByNativeErr(env, *retCode));
1508             }
1509         };
1510     }
1511 
GetConnectAbilityExecFunc(const AAFwk::Want & want,sptr<JSServiceExtensionConnection> connection,int64_t connectId,std::shared_ptr<int> innerErrorCode)1512     NapiAsyncTask::ExecuteCallback GetConnectAbilityExecFunc(const AAFwk::Want &want,
1513         sptr<JSServiceExtensionConnection> connection, int64_t connectId, std::shared_ptr<int> innerErrorCode)
1514     {
1515         return [weak = context_, want, connection, connectId, innerErrorCode]() {
1516             TAG_LOGI(AAFwkTag::SERVICE_EXT, "Connect ability: %{public}d",
1517                 static_cast<int32_t>(connectId));
1518 
1519             auto context = weak.lock();
1520             if (!context) {
1521                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "context released");
1522                 *innerErrorCode = static_cast<int>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
1523                 return;
1524             }
1525 
1526             *innerErrorCode = context->ConnectAbility(want, connection);
1527         };
1528     }
1529 };
1530 } // namespace
1531 
CreateJsServiceExtensionContext(napi_env env,std::shared_ptr<ServiceExtensionContext> context)1532 napi_value CreateJsServiceExtensionContext(napi_env env, std::shared_ptr<ServiceExtensionContext> context)
1533 {
1534     TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
1535     std::shared_ptr<OHOS::AppExecFwk::AbilityInfo> abilityInfo = nullptr;
1536     if (context) {
1537         abilityInfo = context->GetAbilityInfo();
1538     }
1539     napi_value object = CreateJsExtensionContext(env, context, abilityInfo);
1540 
1541     std::unique_ptr<JsServiceExtensionContext> jsContext = std::make_unique<JsServiceExtensionContext>(context);
1542     napi_wrap(env, object, jsContext.release(), JsServiceExtensionContext::Finalizer, nullptr, nullptr);
1543 
1544     const char *moduleName = "JsServiceExtensionContext";
1545     BindNativeFunction(env, object, "startAbility", moduleName, JsServiceExtensionContext::StartAbility);
1546     BindNativeFunction(env, object, "openLink", moduleName, JsServiceExtensionContext::OpenLink);
1547     BindNativeFunction(env, object, "startAbilityAsCaller",
1548         moduleName, JsServiceExtensionContext::StartAbilityAsCaller);
1549     BindNativeFunction(env, object, "terminateSelf", moduleName, JsServiceExtensionContext::TerminateAbility);
1550     BindNativeFunction(
1551         env, object, "connectServiceExtensionAbility", moduleName, JsServiceExtensionContext::ConnectAbility);
1552     BindNativeFunction(env, object, "disconnectAbility",
1553         moduleName, JsServiceExtensionContext::DisconnectAbility);
1554     BindNativeFunction(env, object, "disconnectServiceExtensionAbility",
1555         moduleName, JsServiceExtensionContext::DisconnectAbility);
1556     BindNativeFunction(env, object, "startAbilityWithAccount",
1557         moduleName, JsServiceExtensionContext::StartAbilityWithAccount);
1558     BindNativeFunction(env, object, "startUIAbilities", moduleName, JsServiceExtensionContext::StartUIAbilities);
1559     BindNativeFunction(env, object, "startAbilityByCall",
1560         moduleName, JsServiceExtensionContext::StartAbilityByCall);
1561     BindNativeFunction(
1562         env, object, "connectAbilityWithAccount", moduleName, JsServiceExtensionContext::ConnectAbilityWithAccount);
1563     BindNativeFunction(env, object,
1564         "connectServiceExtensionAbilityWithAccount", moduleName, JsServiceExtensionContext::ConnectAbilityWithAccount);
1565     BindNativeFunction(env, object, "startServiceExtensionAbility", moduleName,
1566         JsServiceExtensionContext::StartServiceExtensionAbility);
1567     BindNativeFunction(env, object, "startUIServiceExtensionAbility", moduleName,
1568         JsServiceExtensionContext::StartUIServiceExtensionAbility);
1569     BindNativeFunction(env, object, "startServiceExtensionAbilityWithAccount", moduleName,
1570         JsServiceExtensionContext::StartServiceExtensionAbilityWithAccount);
1571     BindNativeFunction(env, object, "stopServiceExtensionAbility", moduleName,
1572         JsServiceExtensionContext::StopServiceExtensionAbility);
1573     BindNativeFunction(env, object, "stopServiceExtensionAbilityWithAccount", moduleName,
1574         JsServiceExtensionContext::StopServiceExtensionAbilityWithAccount);
1575     BindNativeFunction(env, object, "startRecentAbility", moduleName,
1576         JsServiceExtensionContext::StartRecentAbility);
1577     BindNativeFunction(env, object, "requestModalUIExtension", moduleName,
1578         JsServiceExtensionContext::RequestModalUIExtension);
1579     BindNativeFunction(env, object, "preStartMission", moduleName,
1580         JsServiceExtensionContext::PreStartMission);
1581     BindNativeFunction(env, object, "openAtomicService", moduleName,
1582         JsServiceExtensionContext::OpenAtomicService);
1583     return object;
1584 }
1585 
JSServiceExtensionConnection(napi_env env)1586 JSServiceExtensionConnection::JSServiceExtensionConnection(napi_env env) : env_(env) {}
1587 
~JSServiceExtensionConnection()1588 JSServiceExtensionConnection::~JSServiceExtensionConnection()
1589 {
1590     if (jsConnectionObject_ == nullptr) {
1591         return;
1592     }
1593 
1594     uv_loop_t *loop = nullptr;
1595     napi_get_uv_event_loop(env_, &loop);
1596     if (loop == nullptr) {
1597         return;
1598     }
1599 
1600     uv_work_t *work = new (std::nothrow) uv_work_t;
1601     if (work == nullptr) {
1602         return;
1603     }
1604     work->data = reinterpret_cast<void *>(jsConnectionObject_.release());
1605     int ret = uv_queue_work(loop, work, [](uv_work_t *work) {},
1606     [](uv_work_t *work, int status) {
1607         if (work == nullptr) {
1608             return;
1609         }
1610         if (work->data == nullptr) {
1611             delete work;
1612             work = nullptr;
1613             return;
1614         }
1615         delete reinterpret_cast<NativeReference *>(work->data);
1616         work->data = nullptr;
1617         delete work;
1618         work = nullptr;
1619     });
1620     if (ret != 0) {
1621         delete reinterpret_cast<NativeReference *>(work->data);
1622         work->data = nullptr;
1623         delete work;
1624         work = nullptr;
1625     }
1626 }
1627 
SetConnectionId(int64_t id)1628 void JSServiceExtensionConnection::SetConnectionId(int64_t id)
1629 {
1630     connectionId_ = id;
1631 }
1632 
GetConnectionId()1633 int64_t JSServiceExtensionConnection::GetConnectionId()
1634 {
1635     return connectionId_;
1636 }
1637 
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)1638 void JSServiceExtensionConnection::OnAbilityConnectDone(const AppExecFwk::ElementName &element,
1639     const sptr<IRemoteObject> &remoteObject, int resultCode)
1640 {
1641     TAG_LOGD(AAFwkTag::SERVICE_EXT, "called, resultCode:%{public}d", resultCode);
1642     wptr<JSServiceExtensionConnection> connection = this;
1643     std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>
1644         ([connection, element, remoteObject, resultCode](napi_env env, NapiAsyncTask &task, int32_t status) {
1645             sptr<JSServiceExtensionConnection> connectionSptr = connection.promote();
1646             if (!connectionSptr) {
1647                 TAG_LOGE(AAFwkTag::SERVICE_EXT, "null connectionSptr");
1648                 return;
1649             }
1650             connectionSptr->HandleOnAbilityConnectDone(element, remoteObject, resultCode);
1651         });
1652 
1653     napi_ref callback = nullptr;
1654     std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
1655     NapiAsyncTask::Schedule("JSServiceExtensionConnection::OnAbilityConnectDone",
1656         env_, std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
1657 }
1658 
HandleOnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)1659 void JSServiceExtensionConnection::HandleOnAbilityConnectDone(const AppExecFwk::ElementName &element,
1660     const sptr<IRemoteObject> &remoteObject, int resultCode)
1661 {
1662     TAG_LOGD(AAFwkTag::SERVICE_EXT, "resultCode:%{public}d", resultCode);
1663     // wrap ElementName
1664     napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(env_, element);
1665 
1666     // wrap RemoteObject
1667     napi_value napiRemoteObject = NAPI_ohos_rpc_CreateJsRemoteObject(env_, remoteObject);
1668     napi_value argv[] = {napiElementName, napiRemoteObject};
1669     if (jsConnectionObject_ == nullptr) {
1670         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null jsConnectionObject_");
1671         return;
1672     }
1673     napi_value obj = jsConnectionObject_->GetNapiValue();
1674     if (!CheckTypeForNapiValue(env_, obj, napi_object)) {
1675         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get object error");
1676         return;
1677     }
1678     napi_value methodOnConnect = nullptr;
1679     napi_get_named_property(env_, obj, "onConnect", &methodOnConnect);
1680     if (methodOnConnect == nullptr) {
1681         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null methodOnConnect");
1682         return;
1683     }
1684     TAG_LOGI(AAFwkTag::SERVICE_EXT, "Call onConnect");
1685     napi_status status = napi_call_function(env_, obj, methodOnConnect, ARGC_TWO, argv, nullptr);
1686     if (status != napi_ok) {
1687         TAG_LOGE(AAFwkTag::SERVICE_EXT, "call js func failed %{public}d", status);
1688     }
1689 }
1690 
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)1691 void JSServiceExtensionConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode)
1692 {
1693     TAG_LOGD(AAFwkTag::SERVICE_EXT, "called, resultCode:%{public}d", resultCode);
1694     wptr<JSServiceExtensionConnection> connection = this;
1695     std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>
1696         ([connection, element, resultCode](napi_env env, NapiAsyncTask &task, int32_t status) {
1697             sptr<JSServiceExtensionConnection> connectionSptr = connection.promote();
1698             if (!connectionSptr) {
1699                 TAG_LOGI(AAFwkTag::SERVICE_EXT, "null connectionSptr");
1700                 return;
1701             }
1702             connectionSptr->HandleOnAbilityDisconnectDone(element, resultCode);
1703         });
1704     napi_ref callback = nullptr;
1705     std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
1706     NapiAsyncTask::Schedule("JSServiceExtensionConnection::OnAbilityDisconnectDone",
1707         env_, std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
1708 }
1709 
HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)1710 void JSServiceExtensionConnection::HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName &element,
1711     int resultCode)
1712 {
1713     TAG_LOGD(AAFwkTag::SERVICE_EXT, "called, resultCode:%{public}d", resultCode);
1714     napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(env_, element);
1715     napi_value argv[] = {napiElementName};
1716     if (jsConnectionObject_ == nullptr) {
1717         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null jsConnectionObject_");
1718         return;
1719     }
1720     napi_value obj = jsConnectionObject_->GetNapiValue();
1721     if (!CheckTypeForNapiValue(env_, obj, napi_object)) {
1722         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get object error");
1723         return;
1724     }
1725 
1726     napi_value method = nullptr;
1727     napi_get_named_property(env_, obj, "onDisconnect", &method);
1728     if (method == nullptr) {
1729         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null method");
1730         return;
1731     }
1732 
1733     // release connect
1734     {
1735         std::lock_guard guard(g_connectsMutex);
1736         TAG_LOGD(AAFwkTag::SERVICE_EXT, "OnAbilityDisconnectDone g_connects.size:%{public}zu", g_connects.size());
1737         std::string bundleName = element.GetBundleName();
1738         std::string abilityName = element.GetAbilityName();
1739         auto item = std::find_if(g_connects.begin(),
1740             g_connects.end(),
1741             [bundleName, abilityName, connectionId = connectionId_](
1742                 const auto &obj) {
1743                 return (bundleName == obj.first.want.GetBundle()) &&
1744                     (abilityName == obj.first.want.GetElement().GetAbilityName()) &&
1745                     connectionId == obj.first.id;
1746             });
1747         if (item != g_connects.end()) {
1748             // match bundlename && abilityname
1749             g_connects.erase(item);
1750             TAG_LOGD(
1751                 AAFwkTag::SERVICE_EXT, "OnAbilityDisconnectDone erase g_connects.size:%{public}zu", g_connects.size());
1752         }
1753     }
1754     TAG_LOGI(AAFwkTag::SERVICE_EXT, "Call onDisconnect");
1755     napi_status status = napi_call_function(env_, obj, method, ARGC_ONE, argv, nullptr);
1756     if (status != napi_ok) {
1757         TAG_LOGE(AAFwkTag::SERVICE_EXT, "call js func failed %{public}d", status);
1758     }
1759 }
1760 
SetJsConnectionObject(napi_value jsConnectionObject)1761 void JSServiceExtensionConnection::SetJsConnectionObject(napi_value jsConnectionObject)
1762 {
1763     napi_ref ref = nullptr;
1764     napi_create_reference(env_, jsConnectionObject, 1, &ref);
1765     jsConnectionObject_ = std::unique_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref));
1766 }
1767 
RemoveConnectionObject()1768 void JSServiceExtensionConnection::RemoveConnectionObject()
1769 {
1770     jsConnectionObject_.reset();
1771 }
1772 
CallJsFailed(int32_t errorCode)1773 void JSServiceExtensionConnection::CallJsFailed(int32_t errorCode)
1774 {
1775     TAG_LOGD(AAFwkTag::SERVICE_EXT, "called");
1776     if (jsConnectionObject_ == nullptr) {
1777         TAG_LOGE(AAFwkTag::SERVICE_EXT, "null jsConnectionObject_");
1778         return;
1779     }
1780     napi_value obj = jsConnectionObject_->GetNapiValue();
1781     if (!CheckTypeForNapiValue(env_, obj, napi_object)) {
1782         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get obj failed");
1783         return;
1784     }
1785 
1786     napi_value method = nullptr;
1787     napi_get_named_property(env_, obj, "onFailed", &method);
1788     if (method == nullptr) {
1789         TAG_LOGE(AAFwkTag::SERVICE_EXT, "get onFailed failed");
1790         return;
1791     }
1792     napi_value argv[] = {CreateJsValue(env_, errorCode)};
1793     napi_call_function(env_, obj, method, ARGC_ONE, argv, nullptr);
1794     TAG_LOGD(AAFwkTag::SERVICE_EXT, "end");
1795 }
1796 }  // namespace AbilityRuntime
1797 }  // namespace OHOS
1798