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