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