• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2023 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_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 "start_options.h"
36 #include "hitrace_meter.h"
37 
38 namespace OHOS {
39 namespace AbilityRuntime {
40 namespace {
41 constexpr int32_t INDEX_ZERO = 0;
42 constexpr int32_t INDEX_ONE = 1;
43 constexpr int32_t INDEX_TWO = 2;
44 constexpr int32_t ERROR_CODE_ONE = 1;
45 constexpr int32_t ERROR_CODE_TWO = 2;
46 constexpr size_t ARGC_ZERO = 0;
47 constexpr size_t ARGC_ONE = 1;
48 constexpr size_t ARGC_TWO = 2;
49 constexpr size_t ARGC_THREE = 3;
50 
51 class StartAbilityByCallParameters {
52 public:
53     int err = 0;
54     sptr<IRemoteObject> remoteCallee = nullptr;
55     std::shared_ptr<CallerCallBack> callerCallBack = nullptr;
56     std::mutex mutexlock;
57     std::condition_variable condition;
58 };
59 
60 static std::map<ConnectionKey, sptr<JSServiceExtensionConnection>, key_compare> g_connects;
61 static int64_t g_serialNumber = 0;
62 
RemoveConnection(int64_t connectId)63 void RemoveConnection(int64_t connectId)
64 {
65     auto item = std::find_if(g_connects.begin(), g_connects.end(),
66     [&connectId](const auto &obj) {
67         return connectId == obj.first.id;
68     });
69     if (item != g_connects.end()) {
70         HILOG_DEBUG("remove conn ability exist");
71         if (item->second) {
72             item->second->RemoveConnectionObject();
73         }
74         g_connects.erase(item);
75     } else {
76         HILOG_DEBUG("remove conn ability not exist");
77     }
78 }
79 
80 class JsServiceExtensionContext final {
81 public:
JsServiceExtensionContext(const std::shared_ptr<ServiceExtensionContext> & context)82     explicit JsServiceExtensionContext(const std::shared_ptr<ServiceExtensionContext>& context) : context_(context) {}
83     ~JsServiceExtensionContext() = default;
84 
Finalizer(NativeEngine * engine,void * data,void * hint)85     static void Finalizer(NativeEngine* engine, void* data, void* hint)
86     {
87         HILOG_DEBUG("JsAbilityContext::Finalizer is called");
88         std::unique_ptr<JsServiceExtensionContext>(static_cast<JsServiceExtensionContext*>(data));
89     }
90 
StartAbility(NativeEngine * engine,NativeCallbackInfo * info)91     static NativeValue* StartAbility(NativeEngine* engine, NativeCallbackInfo* info)
92     {
93         JsServiceExtensionContext* me = CheckParamsAndGetThis<JsServiceExtensionContext>(engine, info);
94         return (me != nullptr) ? me->OnStartAbility(*engine, *info) : nullptr;
95     }
96 
StartAbilityAsCaller(NativeEngine * engine,NativeCallbackInfo * info)97     static NativeValue* StartAbilityAsCaller(NativeEngine* engine, NativeCallbackInfo* info)
98     {
99         JsServiceExtensionContext* me = CheckParamsAndGetThis<JsServiceExtensionContext>(engine, info);
100         return (me != nullptr) ? me->OnStartAbilityAsCaller(*engine, *info) : nullptr;
101     }
102 
StartRecentAbility(NativeEngine * engine,NativeCallbackInfo * info)103     static NativeValue* StartRecentAbility(NativeEngine* engine, NativeCallbackInfo* info)
104     {
105         JsServiceExtensionContext* me = CheckParamsAndGetThis<JsServiceExtensionContext>(engine, info);
106         return (me != nullptr) ? me->OnStartAbility(*engine, *info, true) : nullptr;
107     }
108 
StartAbilityByCall(NativeEngine * engine,NativeCallbackInfo * info)109     static NativeValue* StartAbilityByCall(NativeEngine* engine, NativeCallbackInfo* info)
110     {
111         JsServiceExtensionContext* me = CheckParamsAndGetThis<JsServiceExtensionContext>(engine, info);
112         return (me != nullptr) ? me->OnStartAbilityByCall(*engine, *info) : nullptr;
113     }
114 
StartAbilityWithAccount(NativeEngine * engine,NativeCallbackInfo * info)115     static NativeValue* StartAbilityWithAccount(NativeEngine* engine, NativeCallbackInfo* info)
116     {
117         JsServiceExtensionContext* me = CheckParamsAndGetThis<JsServiceExtensionContext>(engine, info);
118         return (me != nullptr) ? me->OnStartAbilityWithAccount(*engine, *info) : nullptr;
119     }
120 
ConnectAbilityWithAccount(NativeEngine * engine,NativeCallbackInfo * info)121     static NativeValue* ConnectAbilityWithAccount(NativeEngine* engine, NativeCallbackInfo* info)
122     {
123         JsServiceExtensionContext* me = CheckParamsAndGetThis<JsServiceExtensionContext>(engine, info);
124         return (me != nullptr) ? me->OnConnectAbilityWithAccount(*engine, *info) : nullptr;
125     }
126 
TerminateAbility(NativeEngine * engine,NativeCallbackInfo * info)127     static NativeValue* TerminateAbility(NativeEngine* engine, NativeCallbackInfo* info)
128     {
129         JsServiceExtensionContext* me = CheckParamsAndGetThis<JsServiceExtensionContext>(engine, info);
130         return (me != nullptr) ? me->OnTerminateAbility(*engine, *info) : nullptr;
131     }
132 
ConnectAbility(NativeEngine * engine,NativeCallbackInfo * info)133     static NativeValue* ConnectAbility(NativeEngine* engine, NativeCallbackInfo* info)
134     {
135         JsServiceExtensionContext* me = CheckParamsAndGetThis<JsServiceExtensionContext>(engine, info);
136         return (me != nullptr) ? me->OnConnectAbility(*engine, *info) : nullptr;
137     }
138 
DisconnectAbility(NativeEngine * engine,NativeCallbackInfo * info)139     static NativeValue* DisconnectAbility(NativeEngine* engine, NativeCallbackInfo* info)
140     {
141         JsServiceExtensionContext* me = CheckParamsAndGetThis<JsServiceExtensionContext>(engine, info);
142         return (me != nullptr) ? me->OnDisconnectAbility(*engine, *info) : nullptr;
143     }
144 
StartServiceExtensionAbility(NativeEngine * engine,NativeCallbackInfo * info)145     static NativeValue* StartServiceExtensionAbility(NativeEngine* engine, NativeCallbackInfo* info)
146     {
147         JsServiceExtensionContext* me = CheckParamsAndGetThis<JsServiceExtensionContext>(engine, info);
148         return (me != nullptr) ? me->OnStartExtensionAbility(*engine, *info) : nullptr;
149     }
150 
StartServiceExtensionAbilityWithAccount(NativeEngine * engine,NativeCallbackInfo * info)151     static NativeValue* StartServiceExtensionAbilityWithAccount(NativeEngine* engine, NativeCallbackInfo* info)
152     {
153         JsServiceExtensionContext* me = CheckParamsAndGetThis<JsServiceExtensionContext>(engine, info);
154         return (me != nullptr) ? me->OnStartExtensionAbilityWithAccount(*engine, *info) : nullptr;
155     }
156 
StopServiceExtensionAbility(NativeEngine * engine,NativeCallbackInfo * info)157     static NativeValue* StopServiceExtensionAbility(NativeEngine* engine, NativeCallbackInfo* info)
158     {
159         JsServiceExtensionContext* me = CheckParamsAndGetThis<JsServiceExtensionContext>(engine, info);
160         return (me != nullptr) ? me->OnStopExtensionAbility(*engine, *info) : nullptr;
161     }
162 
StopServiceExtensionAbilityWithAccount(NativeEngine * engine,NativeCallbackInfo * info)163     static NativeValue* StopServiceExtensionAbilityWithAccount(NativeEngine* engine, NativeCallbackInfo* info)
164     {
165         JsServiceExtensionContext* me = CheckParamsAndGetThis<JsServiceExtensionContext>(engine, info);
166         return (me != nullptr) ? me->OnStopExtensionAbilityWithAccount(*engine, *info) : nullptr;
167     }
168 
169 private:
170     std::weak_ptr<ServiceExtensionContext> context_;
171     sptr<JsFreeInstallObserver> freeInstallObserver_ = nullptr;
ClearFailedCallConnection(const std::weak_ptr<ServiceExtensionContext> & serviceContext,const std::shared_ptr<CallerCallBack> & callback)172     static void ClearFailedCallConnection(
173         const std::weak_ptr<ServiceExtensionContext>& serviceContext, const std::shared_ptr<CallerCallBack> &callback)
174     {
175         HILOG_DEBUG("clear failed call of startup is called.");
176         auto context = serviceContext.lock();
177         if (context == nullptr || callback == nullptr) {
178             HILOG_ERROR("clear failed call of startup input param is nullptr.");
179             return;
180         }
181 
182         context->ClearFailedCallConnection(callback);
183     }
184 
AddFreeInstallObserver(NativeEngine & engine,const AAFwk::Want & want,NativeValue * callback)185     void AddFreeInstallObserver(NativeEngine& engine, const AAFwk::Want &want, NativeValue* callback)
186     {
187         // adapter free install async return install and start result
188         int ret = 0;
189         if (freeInstallObserver_ == nullptr) {
190             freeInstallObserver_ = new JsFreeInstallObserver(engine);
191             ret = AAFwk::AbilityManagerClient::GetInstance()->AddFreeInstallObserver(freeInstallObserver_);
192         }
193 
194         if (ret != ERR_OK) {
195             HILOG_ERROR("AddFreeInstallObserver failed.");
196         } else {
197             // build a callback observer with last param
198             std::string bundleName = want.GetElement().GetBundleName();
199             std::string abilityName = want.GetElement().GetAbilityName();
200             std::string startTime = want.GetStringParam(Want::PARAM_RESV_START_TIME);
201             freeInstallObserver_->AddJsObserverObject(bundleName, abilityName, startTime, callback);
202         }
203     }
204 
OnStartAbility(NativeEngine & engine,NativeCallbackInfo & info,bool isStartRecent=false)205     NativeValue* OnStartAbility(NativeEngine& engine, NativeCallbackInfo& info, bool isStartRecent = false)
206     {
207         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
208         HILOG_INFO("StartAbility");
209         if (info.argc < ARGC_ONE) {
210             HILOG_ERROR("Start ability failed, not enough params.");
211             ThrowTooFewParametersError(engine);
212             return engine.CreateUndefined();
213         }
214 
215         size_t unwrapArgc = 0;
216         AAFwk::Want want;
217         AAFwk::StartOptions startOptions;
218         if (!CheckStartAbilityInputParam(engine, info, want, startOptions, unwrapArgc)) {
219             ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
220             return engine.CreateUndefined();
221         }
222 
223         if (isStartRecent) {
224             HILOG_DEBUG("OnStartRecentAbility is called");
225             want.SetParam(Want::PARAM_RESV_START_RECENT, true);
226         }
227 
228         if ((want.GetFlags() & Want::FLAG_INSTALL_ON_DEMAND) == Want::FLAG_INSTALL_ON_DEMAND) {
229             std::string startTime = std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
230                 system_clock::now().time_since_epoch()).count());
231             want.SetParam(Want::PARAM_RESV_START_TIME, startTime);
232         }
233 
234         auto innerErrorCode = std::make_shared<int>(ERR_OK);
235         AsyncTask::ExecuteCallback execute = [weak = context_, want, startOptions, unwrapArgc, innerErrorCode,
236             &observer = freeInstallObserver_]() {
237             HILOG_DEBUG("startAbility begin");
238             auto context = weak.lock();
239             if (!context) {
240                 HILOG_WARN("context is released");
241                 *innerErrorCode = static_cast<int>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
242                 return;
243             }
244 
245             (unwrapArgc == 1) ? *innerErrorCode = context->StartAbility(want) :
246                 *innerErrorCode = context->StartAbility(want, startOptions);
247             if ((want.GetFlags() & Want::FLAG_INSTALL_ON_DEMAND) == Want::FLAG_INSTALL_ON_DEMAND &&
248                 *innerErrorCode != 0 && observer != nullptr) {
249                 std::string bundleName = want.GetElement().GetBundleName();
250                 std::string abilityName = want.GetElement().GetAbilityName();
251                 std::string startTime = want.GetStringParam(Want::PARAM_RESV_START_TIME);
252                 observer->OnInstallFinished(bundleName, abilityName, startTime, *innerErrorCode);
253             }
254         };
255 
256         AsyncTask::CompleteCallback complete =
257             [innerErrorCode](NativeEngine& engine, AsyncTask& task, int32_t status) {
258                 if (*innerErrorCode == 0) {
259                     task.Resolve(engine, engine.CreateUndefined());
260                 } else {
261                     task.Reject(engine, CreateJsErrorByNativeErr(engine, *innerErrorCode));
262                 }
263             };
264 
265         NativeValue* lastParam = (info.argc == unwrapArgc) ? nullptr : info.argv[unwrapArgc];
266         NativeValue* result = nullptr;
267         if ((want.GetFlags() & Want::FLAG_INSTALL_ON_DEMAND) == Want::FLAG_INSTALL_ON_DEMAND) {
268             AddFreeInstallObserver(engine, want, lastParam);
269             AsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartAbility", engine,
270                 CreateAsyncTaskWithLastParam(engine, nullptr, std::move(execute), nullptr, &result));
271         } else {
272             AsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartAbility", engine,
273                 CreateAsyncTaskWithLastParam(engine, lastParam, std::move(execute), std::move(complete), &result));
274         }
275         return result;
276     }
277 
OnStartAbilityAsCaller(NativeEngine & engine,NativeCallbackInfo & info)278     NativeValue* OnStartAbilityAsCaller(NativeEngine& engine, NativeCallbackInfo& info)
279     {
280         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
281         HILOG_INFO("StartAbilityAsCaller");
282         if (info.argc < ARGC_ONE) {
283             HILOG_ERROR("Start ability as caller failed, not enough params.");
284             ThrowTooFewParametersError(engine);
285             return engine.CreateUndefined();
286         }
287 
288         size_t unwrapArgc = 0;
289         AAFwk::Want want;
290         AAFwk::StartOptions startOptions;
291         if (!CheckStartAbilityInputParam(engine, info, want, startOptions, unwrapArgc)) {
292             ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
293             return engine.CreateUndefined();
294         }
295 
296         AsyncTask::CompleteCallback complete =
297             [weak = context_, want, startOptions, unwrapArgc](NativeEngine& engine, AsyncTask& task, int32_t status) {
298                 HILOG_DEBUG("startAbility begin");
299                 auto context = weak.lock();
300                 if (!context) {
301                     HILOG_WARN("context is released");
302                     task.Reject(engine, CreateJsError(engine, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
303                     return;
304                 }
305 
306                 ErrCode innerErrorCode = ERR_OK;
307                 (unwrapArgc == 1) ? innerErrorCode = context->StartAbilityAsCaller(want) :
308                     innerErrorCode = context->StartAbilityAsCaller(want, startOptions);
309                 if (innerErrorCode == 0) {
310                     task.Resolve(engine, engine.CreateUndefined());
311                 } else {
312                     task.Reject(engine, CreateJsErrorByNativeErr(engine, innerErrorCode));
313                 }
314             };
315 
316         NativeValue* lastParam = (info.argc == unwrapArgc) ? nullptr : info.argv[unwrapArgc];
317         NativeValue* result = nullptr;
318         AsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartAbilityAsCaller",
319             engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
320         return result;
321     }
322 
CheckStartAbilityInputParam(NativeEngine & engine,NativeCallbackInfo & info,AAFwk::Want & want,AAFwk::StartOptions & startOptions,size_t & unwrapArgc) const323     bool CheckStartAbilityInputParam(
324         NativeEngine& engine, NativeCallbackInfo& info,
325         AAFwk::Want& want, AAFwk::StartOptions& startOptions, size_t& unwrapArgc) const
326     {
327         if (info.argc < ARGC_ONE) {
328             return false;
329         }
330         unwrapArgc = ARGC_ZERO;
331         // Check input want
332         if (!CheckWantParam(engine, info.argv[INDEX_ZERO], want)) {
333             return false;
334         }
335         ++unwrapArgc;
336         if (info.argc > ARGC_ONE && info.argv[1]->TypeOf() == NATIVE_OBJECT) {
337             HILOG_DEBUG("OnStartAbility start options is used.");
338             AppExecFwk::UnwrapStartOptions(reinterpret_cast<napi_env>(&engine),
339                 reinterpret_cast<napi_value>(info.argv[1]), startOptions);
340             unwrapArgc++;
341         }
342         return true;
343     }
344 
OnStartAbilityByCall(NativeEngine & engine,const NativeCallbackInfo & info)345     NativeValue* OnStartAbilityByCall(NativeEngine& engine, const NativeCallbackInfo& info)
346     {
347         HILOG_INFO("StartAbilityByCall");
348         if (info.argc < ARGC_ONE) {
349             HILOG_ERROR("Start ability by call failed, not enough params.");
350             ThrowTooFewParametersError(engine);
351             return engine.CreateUndefined();
352         }
353         AAFwk::Want want;
354         int32_t accountId = DEFAULT_INVAL_VALUE;
355         if (!CheckStartAbilityByCallInputParam(engine, info, want, accountId)) {
356             ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
357             return engine.CreateUndefined();
358         }
359 
360         std::shared_ptr<StartAbilityByCallParameters> calls = std::make_shared<StartAbilityByCallParameters>();
361         NativeValue* retsult = nullptr;
362         calls->callerCallBack = std::make_shared<CallerCallBack>();
363         calls->callerCallBack->SetCallBack(GetCallBackDone(calls));
364         calls->callerCallBack->SetOnRelease(GetReleaseListen());
365 
366         auto context = context_.lock();
367         if (context == nullptr) {
368             HILOG_ERROR("OnStartAbilityByCall context is nullptr");
369             ThrowError(engine, AbilityErrorCode::ERROR_CODE_INNER);
370             return engine.CreateUndefined();
371         }
372 
373         auto ret = context->StartAbilityByCall(want, calls->callerCallBack, accountId);
374         if (ret) {
375             HILOG_ERROR("OnStartAbilityByCall is failed");
376             ThrowErrorByNativeErr(engine, ret);
377             return engine.CreateUndefined();
378         }
379 
380         if (calls->remoteCallee == nullptr) {
381             HILOG_DEBUG("OnStartAbilityByCall async wait execute");
382             AsyncTask::ScheduleHighQos("JsAbilityContext::OnStartAbilityByCall", engine,
383                 CreateAsyncTaskWithLastParam(
384                     engine, nullptr, GetCallExecute(calls), GetCallComplete(calls), &retsult));
385         } else {
386             AsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartAbilityByCall", engine,
387                 CreateAsyncTaskWithLastParam(engine, nullptr, nullptr, GetCallComplete(calls), &retsult));
388         }
389         return retsult;
390     }
391 
CheckStartAbilityByCallInputParam(NativeEngine & engine,const NativeCallbackInfo & info,AAFwk::Want & want,int32_t & accountId)392     bool CheckStartAbilityByCallInputParam(
393         NativeEngine& engine, const NativeCallbackInfo& info, AAFwk::Want& want, int32_t& accountId)
394     {
395         if (!CheckWantParam(engine, info.argv[INDEX_ZERO], want)) {
396             return false;
397         }
398 
399         if (info.argc > static_cast<size_t>(INDEX_ONE)) {
400             if (info.argv[INDEX_ONE]->TypeOf() == NativeValueType::NATIVE_NUMBER) {
401                 if (!ConvertFromJsValue(engine, info.argv[1], accountId)) {
402                     HILOG_ERROR("check input param accountId failed");
403                     return false;
404                 }
405             } else {
406                 HILOG_ERROR("input param type invalid");
407                 return false;
408             }
409         }
410 
411         HILOG_INFO("CheckStartAbilityByCallInputParam, callee:%{public}s.%{public}s.",
412             want.GetBundle().c_str(),
413             want.GetElement().GetAbilityName().c_str());
414         return true;
415     }
416 
GetCallComplete(std::shared_ptr<StartAbilityByCallParameters> calls)417     AsyncTask::CompleteCallback GetCallComplete(std::shared_ptr<StartAbilityByCallParameters> calls)
418     {
419         auto callComplete = [weak = context_, calldata = calls] (
420             NativeEngine& engine, AsyncTask& task, int32_t) {
421             if (calldata->err != 0) {
422                 HILOG_ERROR("OnStartAbilityByCall callComplete err is %{public}d", calldata->err);
423                 ClearFailedCallConnection(weak, calldata->callerCallBack);
424                 task.Reject(engine, CreateJsError(engine, calldata->err, "callComplete err."));
425                 return;
426             }
427 
428             auto context = weak.lock();
429             if (context != nullptr && calldata->callerCallBack != nullptr && calldata->remoteCallee != nullptr) {
430                 auto releaseCallFunc = [weak] (
431                     const std::shared_ptr<CallerCallBack> &callback) -> ErrCode {
432                     auto contextForRelease = weak.lock();
433                     if (contextForRelease == nullptr) {
434                         HILOG_ERROR("releaseCallFunction, context is nullptr");
435                         return -1;
436                     }
437                     return contextForRelease->ReleaseCall(callback);
438                 };
439                 task.Resolve(engine,
440                     CreateJsCallerComplex(
441                         engine, releaseCallFunc, calldata->remoteCallee, calldata->callerCallBack));
442             } else {
443                 HILOG_ERROR("OnStartAbilityByCall callComplete params error %{public}s is nullptr",
444                     context == nullptr ? "context" :
445                         (calldata->remoteCallee == nullptr ? "remoteCallee" : "callerCallBack"));
446                 task.Reject(engine, CreateJsError(engine, -1, "Create Call Failed."));
447             }
448 
449             HILOG_DEBUG("OnStartAbilityByCall callComplete end");
450         };
451         return callComplete;
452     }
453 
GetCallExecute(std::shared_ptr<StartAbilityByCallParameters> calls)454     AsyncTask::ExecuteCallback GetCallExecute(std::shared_ptr<StartAbilityByCallParameters> calls)
455     {
456         auto callExecute = [calldata = calls] () {
457             constexpr int callerTimeOut = 10; // 10s
458             std::unique_lock<std::mutex> lock(calldata->mutexlock);
459             if (calldata->remoteCallee != nullptr) {
460                 HILOG_INFO("OnStartAbilityByCall callExecute callee isn`t nullptr");
461                 return;
462             }
463 
464             if (calldata->condition.wait_for(lock, std::chrono::seconds(callerTimeOut)) == std::cv_status::timeout) {
465                 HILOG_ERROR("OnStartAbilityByCall callExecute waiting callee timeout");
466                 calldata->err = -1;
467             }
468             HILOG_DEBUG("OnStartAbilityByCall callExecute end");
469         };
470         return callExecute;
471     }
472 
GetCallBackDone(std::shared_ptr<StartAbilityByCallParameters> calls)473     CallerCallBack::CallBackClosure GetCallBackDone(std::shared_ptr<StartAbilityByCallParameters> calls)
474     {
475         auto callBackDone = [calldata = calls] (const sptr<IRemoteObject> &obj) {
476             HILOG_DEBUG("OnStartAbilityByCall callBackDone mutexlock");
477             std::unique_lock<std::mutex> lock(calldata->mutexlock);
478             HILOG_DEBUG("OnStartAbilityByCall callBackDone remoteCallee assignment");
479             calldata->remoteCallee = obj;
480             calldata->condition.notify_all();
481             HILOG_INFO("OnStartAbilityByCall callBackDone is called end");
482         };
483         return callBackDone;
484     }
485 
GetReleaseListen()486     CallerCallBack::OnReleaseClosure GetReleaseListen()
487     {
488         auto releaseListen = [](const std::string &str) {
489             HILOG_DEBUG("OnStartAbilityByCall releaseListen is called %{public}s", str.c_str());
490         };
491         return releaseListen;
492     }
493 
OnStartAbilityWithAccount(NativeEngine & engine,NativeCallbackInfo & info)494     NativeValue* OnStartAbilityWithAccount(NativeEngine& engine, NativeCallbackInfo& info)
495     {
496         HILOG_INFO("StartAbilityWithAccount");
497         if (info.argc < ARGC_TWO) {
498             HILOG_ERROR("Start ability with account failed, not enough params.");
499             ThrowTooFewParametersError(engine);
500             return engine.CreateUndefined();
501         }
502 
503         size_t unwrapArgc = 0;
504         AAFwk::Want want;
505         int32_t accountId = 0;
506         if (!CheckStartAbilityWithAccountInputParam(engine, info, want, accountId, unwrapArgc)) {
507             ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
508             return engine.CreateUndefined();
509         }
510 
511         AAFwk::StartOptions startOptions;
512         if (info.argc > ARGC_TWO && info.argv[INDEX_TWO]->TypeOf() == NATIVE_OBJECT) {
513             HILOG_DEBUG("OnStartAbilityWithAccount start options is used.");
514             AppExecFwk::UnwrapStartOptions(reinterpret_cast<napi_env>(&engine),
515                 reinterpret_cast<napi_value>(info.argv[INDEX_TWO]), startOptions);
516             unwrapArgc++;
517         }
518 
519         if ((want.GetFlags() & Want::FLAG_INSTALL_ON_DEMAND) == Want::FLAG_INSTALL_ON_DEMAND) {
520             std::string startTime = std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::
521                 system_clock::now().time_since_epoch()).count());
522             want.SetParam(Want::PARAM_RESV_START_TIME, startTime);
523         }
524         auto innerErrorCode = std::make_shared<int>(ERR_OK);
525         AsyncTask::ExecuteCallback execute = [weak = context_, want, accountId, startOptions, unwrapArgc,
526             innerErrorCode, &observer = freeInstallObserver_]() {
527             auto context = weak.lock();
528             if (!context) {
529                 HILOG_WARN("context is released");
530                 *innerErrorCode = static_cast<int>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
531                 return;
532             }
533 
534             (unwrapArgc == ARGC_TWO) ? *innerErrorCode = context->StartAbilityWithAccount(want, accountId) :
535                 *innerErrorCode = context->StartAbilityWithAccount(want, accountId, startOptions);
536             if ((want.GetFlags() & Want::FLAG_INSTALL_ON_DEMAND) == Want::FLAG_INSTALL_ON_DEMAND &&
537                 *innerErrorCode != 0 && observer != nullptr) {
538                 std::string bundleName = want.GetElement().GetBundleName();
539                 std::string abilityName = want.GetElement().GetAbilityName();
540                 std::string startTime = want.GetStringParam(Want::PARAM_RESV_START_TIME);
541                 observer->OnInstallFinished(bundleName, abilityName, startTime, *innerErrorCode);
542             }
543         };
544 
545         AsyncTask::CompleteCallback complete =
546             [innerErrorCode](NativeEngine& engine, AsyncTask& task, int32_t status) {
547                 if (*innerErrorCode == 0) {
548                     task.Resolve(engine, engine.CreateUndefined());
549                 } else {
550                     task.Reject(engine, CreateJsErrorByNativeErr(engine, *innerErrorCode));
551                 }
552             };
553 
554         NativeValue* lastParam = (info.argc == unwrapArgc) ? nullptr : info.argv[unwrapArgc];
555         NativeValue* result = nullptr;
556         if ((want.GetFlags() & Want::FLAG_INSTALL_ON_DEMAND) == Want::FLAG_INSTALL_ON_DEMAND) {
557             AddFreeInstallObserver(engine, want, lastParam);
558             AsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartAbilityWithAccount", engine,
559                 CreateAsyncTaskWithLastParam(engine, nullptr, std::move(execute), nullptr, &result));
560         } else {
561             AsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartAbilityWithAccount", engine,
562                 CreateAsyncTaskWithLastParam(engine, lastParam, std::move(execute), std::move(complete), &result));
563         }
564         return result;
565     }
566 
CheckStartAbilityWithAccountInputParam(NativeEngine & engine,NativeCallbackInfo & info,AAFwk::Want & want,int32_t & accountId,size_t & unwrapArgc) const567     bool CheckStartAbilityWithAccountInputParam(
568         NativeEngine& engine, NativeCallbackInfo& info,
569         AAFwk::Want& want, int32_t& accountId, size_t& unwrapArgc) const
570     {
571         if (info.argc < ARGC_TWO) {
572             return false;
573         }
574         unwrapArgc = ARGC_ZERO;
575         // Check input want
576         if (!CheckWantParam(engine, info.argv[INDEX_ZERO], want)) {
577             return false;
578         }
579         ++unwrapArgc;
580         if (!CheckAccountIdParam(engine, info.argv[INDEX_ONE], accountId)) {
581             return false;
582         }
583         ++unwrapArgc;
584         return true;
585     }
586 
CheckAccountIdParam(NativeEngine & engine,NativeValue * value,int32_t & accountId) const587     bool CheckAccountIdParam(NativeEngine& engine, NativeValue* value, int32_t& accountId) const
588     {
589         if (!OHOS::AppExecFwk::UnwrapInt32FromJS2(reinterpret_cast<napi_env>(&engine),
590             reinterpret_cast<napi_value>(value), accountId)) {
591             HILOG_ERROR("The input accountId is invalid.");
592             return false;
593         }
594         HILOG_DEBUG("%{public}d accountId:", accountId);
595         return true;
596     }
597 
OnTerminateAbility(NativeEngine & engine,const NativeCallbackInfo & info)598     NativeValue* OnTerminateAbility(NativeEngine& engine, const NativeCallbackInfo& info)
599     {
600         HILOG_INFO("TerminateAbility");
601 
602         AsyncTask::CompleteCallback complete =
603             [weak = context_](NativeEngine& engine, AsyncTask& task, int32_t status) {
604                 auto context = weak.lock();
605                 if (!context) {
606                     HILOG_WARN("context is released");
607                     task.Reject(engine, CreateJsError(engine, ERROR_CODE_ONE, "Context is released"));
608                     return;
609                 }
610 
611                 ErrCode innerErrorCode = context->TerminateAbility();
612                 if (innerErrorCode == 0) {
613                     task.Resolve(engine, engine.CreateUndefined());
614                 } else {
615                     task.Reject(engine, CreateJsErrorByNativeErr(engine, innerErrorCode));
616                 }
617             };
618 
619         NativeValue* lastParam = (info.argc == ARGC_ZERO) ? nullptr : info.argv[INDEX_ZERO];
620         NativeValue* result = nullptr;
621         AsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnTerminateAbility",
622             engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
623         return result;
624     }
625 
OnConnectAbility(NativeEngine & engine,NativeCallbackInfo & info)626     NativeValue* OnConnectAbility(NativeEngine& engine, NativeCallbackInfo& info)
627     {
628         HILOG_DEBUG("ConnectAbility called.");
629         // Check params count
630         if (info.argc < ARGC_TWO) {
631             HILOG_ERROR("Connect ability failed, not enough params.");
632             ThrowTooFewParametersError(engine);
633             return engine.CreateUndefined();
634         }
635         // Unwrap want and connection
636         AAFwk::Want want;
637         sptr<JSServiceExtensionConnection> connection = new JSServiceExtensionConnection(engine);
638         if (!CheckWantParam(engine, info.argv[0], want) ||
639             !CheckConnectionParam(engine, info.argv[1], connection, want)) {
640             ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
641             return engine.CreateUndefined();
642         }
643         int64_t connectId = connection->GetConnectionId();
644         AsyncTask::CompleteCallback complete =
645             [weak = context_, want, connection, connectId](NativeEngine& engine, AsyncTask& task, int32_t status) {
646                 auto context = weak.lock();
647                 if (!context) {
648                     HILOG_ERROR("context is released");
649                     task.Reject(engine, CreateJsError(engine, ERROR_CODE_ONE, "Context is released"));
650                     RemoveConnection(connectId);
651                     return;
652                 }
653                 HILOG_DEBUG("ConnectAbility connection:%{public}d", static_cast<int32_t>(connectId));
654                 auto innerErrorCode = context->ConnectAbility(want, connection);
655                 int32_t errcode = static_cast<int32_t>(AbilityRuntime::GetJsErrorCodeByNativeError(innerErrorCode));
656                 if (errcode) {
657                     connection->CallJsFailed(errcode);
658                     RemoveConnection(connectId);
659                 }
660                 task.Resolve(engine, engine.CreateUndefined());
661             };
662         NativeValue* result = nullptr;
663         AsyncTask::ScheduleHighQos("JSServiceExtensionConnection::OnConnectAbility",
664             engine, CreateAsyncTaskWithLastParam(engine, nullptr, nullptr, std::move(complete), &result));
665         return engine.CreateNumber(connectId);
666     }
667 
OnConnectAbilityWithAccount(NativeEngine & engine,NativeCallbackInfo & info)668     NativeValue* OnConnectAbilityWithAccount(NativeEngine& engine, NativeCallbackInfo& info)
669     {
670         HILOG_INFO("ConnectAbilityWithAccount");
671         // Check params count
672         if (info.argc < ARGC_THREE) {
673             HILOG_ERROR("Connect ability failed, not enough params.");
674             ThrowTooFewParametersError(engine);
675             return engine.CreateUndefined();
676         }
677         // Unwrap want, accountId and connection
678         AAFwk::Want want;
679         int32_t accountId = 0;
680         sptr<JSServiceExtensionConnection> connection = new JSServiceExtensionConnection(engine);
681         if (!CheckWantParam(engine, info.argv[INDEX_ZERO], want) ||
682             !CheckAccountIdParam(engine, info.argv[INDEX_ONE], accountId) ||
683             !CheckConnectionParam(engine, info.argv[INDEX_TWO], connection, want)) {
684             ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
685             return engine.CreateUndefined();
686         }
687         int64_t connectId = connection->GetConnectionId();
688         AsyncTask::CompleteCallback complete =
689             [weak = context_, want, accountId, connection, connectId](
690                 NativeEngine& engine, AsyncTask& task, int32_t status) {
691                     auto context = weak.lock();
692                     if (!context) {
693                         HILOG_ERROR("context is released");
694                         task.Reject(engine, CreateJsError(engine, ERROR_CODE_ONE, "Context is released"));
695                         RemoveConnection(connectId);
696                         return;
697                     }
698                     HILOG_DEBUG("ConnectAbilityWithAccount connection:%{public}d", static_cast<int32_t>(connectId));
699                     auto innerErrorCode = context->ConnectAbilityWithAccount(want, accountId, connection);
700                     int32_t errcode = static_cast<int32_t>(AbilityRuntime::GetJsErrorCodeByNativeError(innerErrorCode));
701                     if (errcode) {
702                         connection->CallJsFailed(errcode);
703                         RemoveConnection(connectId);
704                     }
705                     task.Resolve(engine, engine.CreateUndefined());
706                 };
707         NativeValue* result = nullptr;
708         AsyncTask::ScheduleHighQos("JSServiceExtensionConnection::OnConnectAbilityWithAccount",
709             engine, CreateAsyncTaskWithLastParam(engine, nullptr, nullptr, std::move(complete), &result));
710         return engine.CreateNumber(connectId);
711     }
712 
CheckWantParam(NativeEngine & engine,NativeValue * value,AAFwk::Want & want) const713     bool CheckWantParam(NativeEngine& engine, NativeValue* value, AAFwk::Want& want) const
714     {
715         if (!OHOS::AppExecFwk::UnwrapWant(reinterpret_cast<napi_env>(&engine),
716             reinterpret_cast<napi_value>(value), want)) {
717             HILOG_ERROR("The input want is invalid.");
718             return false;
719         }
720         HILOG_INFO("UnwrapWant, BundleName: %{public}s, AbilityName: %{public}s.",
721             want.GetBundle().c_str(),
722             want.GetElement().GetAbilityName().c_str());
723         return true;
724     }
725 
CheckConnectionParam(NativeEngine & engine,NativeValue * value,sptr<JSServiceExtensionConnection> & connection,AAFwk::Want & want) const726     bool CheckConnectionParam(
727         NativeEngine& engine, NativeValue* value,
728         sptr<JSServiceExtensionConnection>& connection, AAFwk::Want& want) const
729     {
730         if (ConvertNativeValueTo<NativeObject>(value) == nullptr) {
731             HILOG_ERROR("Failed to get connection object");
732             return false;
733         }
734         connection->SetJsConnectionObject(value);
735         ConnectionKey key;
736         key.id = g_serialNumber;
737         key.want = want;
738         connection->SetConnectionId(key.id);
739         g_connects.emplace(key, connection);
740         if (g_serialNumber < INT32_MAX) {
741             g_serialNumber++;
742         } else {
743             g_serialNumber = 0;
744         }
745         HILOG_DEBUG("not find connection, make new one");
746         return true;
747     }
748 
OnDisconnectAbility(NativeEngine & engine,NativeCallbackInfo & info)749     NativeValue* OnDisconnectAbility(NativeEngine& engine, NativeCallbackInfo& info)
750     {
751         HILOG_INFO("DisconnectAbility");
752         if (info.argc < ARGC_ONE) {
753             HILOG_ERROR("Disconnect ability failed, not enough params.");
754             ThrowTooFewParametersError(engine);
755             return engine.CreateUndefined();
756         }
757         int64_t connectId = -1;
758         if (!CheckOnDisconnectAbilityParam(engine, info, connectId)) {
759             ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
760             return engine.CreateUndefined();
761         }
762 
763         AAFwk::Want want;
764         sptr<JSServiceExtensionConnection> connection = nullptr;
765         FindConnection(engine, info, want, connection, connectId);
766         // begin disconnect
767         AsyncTask::CompleteCallback complete =
768             [weak = context_, want, connection](
769                 NativeEngine& engine, AsyncTask& task, int32_t status) {
770                 auto context = weak.lock();
771                 if (!context) {
772                     HILOG_WARN("context is released");
773                     task.Reject(engine, CreateJsError(engine, ERROR_CODE_ONE, "Context is released"));
774                     return;
775                 }
776                 if (connection == nullptr) {
777                     HILOG_WARN("connection nullptr");
778                     task.Reject(engine, CreateJsError(engine, ERROR_CODE_TWO, "not found connection"));
779                     return;
780                 }
781                 HILOG_DEBUG("context->DisconnectAbility");
782                 auto innerErrorCode = context->DisconnectAbility(want, connection);
783                 if (innerErrorCode == 0) {
784                     task.Resolve(engine, engine.CreateUndefined());
785                 } else {
786                     task.Reject(engine, CreateJsErrorByNativeErr(engine, innerErrorCode));
787                 }
788             };
789 
790         NativeValue* lastParam = (info.argc == ARGC_ONE) ? nullptr : info.argv[INDEX_ONE];
791         NativeValue* result = nullptr;
792         AsyncTask::Schedule("JSServiceExtensionConnection::OnDisconnectAbility",
793             engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
794         return result;
795     }
796 
CheckOnDisconnectAbilityParam(NativeEngine & engine,NativeCallbackInfo & info,int64_t & connectId) const797     bool CheckOnDisconnectAbilityParam(NativeEngine& engine, NativeCallbackInfo& info, int64_t& connectId) const
798     {
799         // Check input connection is number type
800         if (!AppExecFwk::UnwrapInt64FromJS2(
801             reinterpret_cast<napi_env>(&engine), reinterpret_cast<napi_value>(info.argv[INDEX_ZERO]), connectId)) {
802             HILOG_ERROR("The input connection id is not number type.");
803             return false;
804         }
805         return true;
806     }
807 
FindConnection(NativeEngine & engine,NativeCallbackInfo & info,AAFwk::Want & want,sptr<JSServiceExtensionConnection> & connection,int64_t & connectId) const808     void FindConnection(
809         NativeEngine& engine, NativeCallbackInfo& info,
810         AAFwk::Want& want, sptr<JSServiceExtensionConnection>& connection, int64_t& connectId) const
811     {
812         HILOG_INFO("Disconnect ability begin, connection:%{public}d.", static_cast<int32_t>(connectId));
813         auto item = std::find_if(g_connects.begin(),
814             g_connects.end(),
815             [&connectId](const auto &obj) {
816                 return connectId == obj.first.id;
817             });
818         if (item != g_connects.end()) {
819             // match id
820             want = item->first.want;
821             connection = item->second;
822             HILOG_DEBUG("find conn ability exist");
823         }
824         return;
825     }
826 
OnStartExtensionAbility(NativeEngine & engine,NativeCallbackInfo & info)827     NativeValue* OnStartExtensionAbility(NativeEngine& engine, NativeCallbackInfo& info)
828     {
829         HILOG_INFO("StartExtensionAbility");
830         if (info.argc < ARGC_ONE) {
831             HILOG_ERROR("Start extension failed, not enough params.");
832             ThrowTooFewParametersError(engine);
833             return engine.CreateUndefined();
834         }
835         AAFwk::Want want;
836         if (!CheckWantParam(engine, info.argv[INDEX_ZERO], want)) {
837             ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
838             return engine.CreateUndefined();
839         }
840 
841         AsyncTask::CompleteCallback complete =
842             [weak = context_, want](NativeEngine& engine, AsyncTask& task, int32_t status) {
843                 auto context = weak.lock();
844                 if (!context) {
845                     HILOG_WARN("context is released");
846                     task.Reject(engine, CreateJsError(engine, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
847                     return;
848                 }
849                 auto innerErrorCode = context->StartServiceExtensionAbility(want);
850                 if (innerErrorCode == 0) {
851                     task.Resolve(engine, engine.CreateUndefined());
852                 } else {
853                     task.Reject(engine, CreateJsErrorByNativeErr(engine, innerErrorCode));
854                 }
855             };
856 
857         NativeValue* lastParam = (info.argc <= ARGC_ONE) ? nullptr : info.argv[ARGC_ONE];
858         NativeValue* result = nullptr;
859         AsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartExtensionAbility",
860             engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
861         return result;
862     }
863 
OnStartExtensionAbilityWithAccount(NativeEngine & engine,NativeCallbackInfo & info)864     NativeValue* OnStartExtensionAbilityWithAccount(NativeEngine& engine, NativeCallbackInfo& info)
865     {
866         HILOG_INFO("StartExtensionAbilityWithAccount");
867         if (info.argc < ARGC_TWO) {
868             HILOG_ERROR("Stop extension failed, not enough params.");
869             ThrowTooFewParametersError(engine);
870             return engine.CreateUndefined();
871         }
872         AAFwk::Want want;
873         int32_t accountId = -1;
874         if (!CheckWantParam(engine, info.argv[INDEX_ZERO], want) ||
875             !CheckAccountIdParam(engine, info.argv[INDEX_ONE], accountId)) {
876             ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
877             return engine.CreateUndefined();
878         }
879 
880         AsyncTask::CompleteCallback complete =
881             [weak = context_, want, accountId](NativeEngine& engine, AsyncTask& task, int32_t status) {
882                 auto context = weak.lock();
883                 if (!context) {
884                     HILOG_WARN("context is released");
885                     task.Reject(engine, CreateJsError(engine, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
886                     return;
887                 }
888                 auto innerErrorCode = context->StartServiceExtensionAbility(want, accountId);
889                 if (innerErrorCode == 0) {
890                     task.Resolve(engine, engine.CreateUndefined());
891                 } else {
892                     task.Reject(engine, CreateJsErrorByNativeErr(engine, innerErrorCode));
893                 }
894             };
895 
896         NativeValue* lastParam = (info.argc <= ARGC_TWO) ? nullptr : info.argv[ARGC_TWO];
897         NativeValue* result = nullptr;
898         AsyncTask::ScheduleHighQos("JSServiceExtensionContext::OnStartExtensionAbilityWithAccount",
899             engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
900         return result;
901     }
902 
OnStopExtensionAbility(NativeEngine & engine,NativeCallbackInfo & info)903     NativeValue* OnStopExtensionAbility(NativeEngine& engine, NativeCallbackInfo& info)
904     {
905         HILOG_INFO("StopExtensionAbility");
906         if (info.argc < ARGC_ONE) {
907             HILOG_ERROR("Start extension failed, not enough params.");
908             ThrowTooFewParametersError(engine);
909             return engine.CreateUndefined();
910         }
911         AAFwk::Want want;
912         if (!CheckWantParam(engine, info.argv[INDEX_ZERO], want)) {
913             ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
914             return engine.CreateUndefined();
915         }
916 
917         AsyncTask::CompleteCallback complete =
918             [weak = context_, want](NativeEngine& engine, AsyncTask& task, int32_t status) {
919                 auto context = weak.lock();
920                 if (!context) {
921                     HILOG_WARN("context is released");
922                     task.Reject(engine, CreateJsError(engine, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
923                     return;
924                 }
925                 auto innerErrorCode = context->StopServiceExtensionAbility(want);
926                 if (innerErrorCode == 0) {
927                     task.Resolve(engine, engine.CreateUndefined());
928                 } else {
929                     task.Reject(engine, CreateJsErrorByNativeErr(engine, innerErrorCode));
930                 }
931             };
932 
933         NativeValue* lastParam = (info.argc <= ARGC_ONE) ? nullptr : info.argv[ARGC_ONE];
934         NativeValue* result = nullptr;
935         AsyncTask::Schedule("JSServiceExtensionContext::OnStopExtensionAbility",
936             engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
937         return result;
938     }
939 
OnStopExtensionAbilityWithAccount(NativeEngine & engine,const NativeCallbackInfo & info)940     NativeValue* OnStopExtensionAbilityWithAccount(NativeEngine& engine, const NativeCallbackInfo& info)
941     {
942         HILOG_INFO("StopExtensionAbilityWithAccount");
943         if (info.argc < ARGC_TWO) {
944             HILOG_ERROR("Stop extension failed, not enough params.");
945             ThrowTooFewParametersError(engine);
946             return engine.CreateUndefined();
947         }
948         AAFwk::Want want;
949         int32_t accountId = -1;
950         if (!CheckWantParam(engine, info.argv[INDEX_ZERO], want) ||
951             !CheckAccountIdParam(engine, info.argv[INDEX_ONE], accountId)) {
952             ThrowError(engine, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
953             return engine.CreateUndefined();
954         }
955 
956         AsyncTask::CompleteCallback complete =
957             [weak = context_, want, accountId](NativeEngine& engine, AsyncTask& task, int32_t status) {
958                 auto context = weak.lock();
959                 if (!context) {
960                     HILOG_WARN("context is released");
961                     task.Reject(engine, CreateJsError(engine, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
962                     return;
963                 }
964                 auto innerErrorCode = context->StopServiceExtensionAbility(want, accountId);
965                 if (innerErrorCode == 0) {
966                     task.Resolve(engine, engine.CreateUndefined());
967                 } else {
968                     task.Reject(engine, CreateJsErrorByNativeErr(engine, innerErrorCode));
969                 }
970             };
971 
972         NativeValue* lastParam = (info.argc <= ARGC_TWO) ? nullptr : info.argv[ARGC_TWO];
973         NativeValue* result = nullptr;
974         AsyncTask::Schedule("JSServiceExtensionContext::OnStopExtensionAbilityWithAccount",
975             engine, CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
976         return result;
977     }
978 };
979 } // namespace
980 
CreateJsServiceExtensionContext(NativeEngine & engine,std::shared_ptr<ServiceExtensionContext> context)981 NativeValue* CreateJsServiceExtensionContext(NativeEngine& engine, std::shared_ptr<ServiceExtensionContext> context)
982 {
983     HILOG_DEBUG("CreateJsServiceExtensionContext");
984     std::shared_ptr<OHOS::AppExecFwk::AbilityInfo> abilityInfo = nullptr;
985     if (context) {
986         abilityInfo = context->GetAbilityInfo();
987     }
988     NativeValue* objValue = CreateJsExtensionContext(engine, context, abilityInfo);
989     NativeObject* object = ConvertNativeValueTo<NativeObject>(objValue);
990 
991     std::unique_ptr<JsServiceExtensionContext> jsContext = std::make_unique<JsServiceExtensionContext>(context);
992     object->SetNativePointer(jsContext.release(), JsServiceExtensionContext::Finalizer, nullptr);
993 
994     const char *moduleName = "JsServiceExtensionContext";
995     BindNativeFunction(engine, *object, "startAbility", moduleName, JsServiceExtensionContext::StartAbility);
996     BindNativeFunction(engine, *object, "startAbilityAsCaller",
997         moduleName, JsServiceExtensionContext::StartAbilityAsCaller);
998     BindNativeFunction(engine, *object, "terminateSelf", moduleName, JsServiceExtensionContext::TerminateAbility);
999     BindNativeFunction(engine, *object, "connectAbility", moduleName, JsServiceExtensionContext::ConnectAbility);
1000     BindNativeFunction(
1001         engine, *object, "connectServiceExtensionAbility", moduleName, JsServiceExtensionContext::ConnectAbility);
1002     BindNativeFunction(engine, *object, "disconnectAbility",
1003         moduleName, JsServiceExtensionContext::DisconnectAbility);
1004     BindNativeFunction(engine, *object, "disconnectServiceExtensionAbility",
1005         moduleName, JsServiceExtensionContext::DisconnectAbility);
1006     BindNativeFunction(engine, *object, "startAbilityWithAccount",
1007         moduleName, JsServiceExtensionContext::StartAbilityWithAccount);
1008     BindNativeFunction(engine, *object, "startAbilityByCall",
1009         moduleName, JsServiceExtensionContext::StartAbilityByCall);
1010     BindNativeFunction(
1011         engine, *object, "connectAbilityWithAccount", moduleName, JsServiceExtensionContext::ConnectAbilityWithAccount);
1012     BindNativeFunction(
1013         engine, *object,
1014         "connectServiceExtensionAbilityWithAccount", moduleName, JsServiceExtensionContext::ConnectAbilityWithAccount);
1015     BindNativeFunction(engine, *object, "startServiceExtensionAbility", moduleName,
1016         JsServiceExtensionContext::StartServiceExtensionAbility);
1017     BindNativeFunction(engine, *object, "startServiceExtensionAbilityWithAccount", moduleName,
1018         JsServiceExtensionContext::StartServiceExtensionAbilityWithAccount);
1019     BindNativeFunction(engine, *object, "stopServiceExtensionAbility", moduleName,
1020         JsServiceExtensionContext::StopServiceExtensionAbility);
1021     BindNativeFunction(engine, *object, "stopServiceExtensionAbilityWithAccount", moduleName,
1022         JsServiceExtensionContext::StopServiceExtensionAbilityWithAccount);
1023     BindNativeFunction(engine, *object, "startRecentAbility", moduleName,
1024         JsServiceExtensionContext::StartRecentAbility);
1025 
1026     return objValue;
1027 }
1028 
JSServiceExtensionConnection(NativeEngine & engine)1029 JSServiceExtensionConnection::JSServiceExtensionConnection(NativeEngine& engine) : engine_(engine) {}
1030 
~JSServiceExtensionConnection()1031 JSServiceExtensionConnection::~JSServiceExtensionConnection()
1032 {
1033     if (jsConnectionObject_ == nullptr) {
1034         return;
1035     }
1036 
1037     uv_loop_t *loop = engine_.GetUVLoop();
1038     if (loop == nullptr) {
1039         return;
1040     }
1041 
1042     uv_work_t *work = new (std::nothrow) uv_work_t;
1043     if (work == nullptr) {
1044         return;
1045     }
1046     work->data = reinterpret_cast<void *>(jsConnectionObject_.release());
1047     int ret = uv_queue_work(loop, work, [](uv_work_t *work) {},
1048     [](uv_work_t *work, int status) {
1049         if (work == nullptr) {
1050             return;
1051         }
1052         if (work->data == nullptr) {
1053             delete work;
1054             work = nullptr;
1055             return;
1056         }
1057         delete reinterpret_cast<NativeReference *>(work->data);
1058         work->data = nullptr;
1059         delete work;
1060         work = nullptr;
1061     });
1062     if (ret != 0) {
1063         delete reinterpret_cast<NativeReference *>(work->data);
1064         work->data = nullptr;
1065         delete work;
1066         work = nullptr;
1067     }
1068 }
1069 
SetConnectionId(int64_t id)1070 void JSServiceExtensionConnection::SetConnectionId(int64_t id)
1071 {
1072     connectionId_ = id;
1073 }
1074 
GetConnectionId()1075 int64_t JSServiceExtensionConnection::GetConnectionId()
1076 {
1077     return connectionId_;
1078 }
1079 
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)1080 void JSServiceExtensionConnection::OnAbilityConnectDone(const AppExecFwk::ElementName &element,
1081     const sptr<IRemoteObject> &remoteObject, int resultCode)
1082 {
1083     HILOG_DEBUG("OnAbilityConnectDone, resultCode:%{public}d", resultCode);
1084     wptr<JSServiceExtensionConnection> connection = this;
1085     std::unique_ptr<AsyncTask::CompleteCallback> complete = std::make_unique<AsyncTask::CompleteCallback>
1086         ([connection, element, remoteObject, resultCode](NativeEngine &engine, AsyncTask &task, int32_t status) {
1087             sptr<JSServiceExtensionConnection> connectionSptr = connection.promote();
1088             if (!connectionSptr) {
1089                 HILOG_ERROR("connectionSptr nullptr");
1090                 return;
1091             }
1092             connectionSptr->HandleOnAbilityConnectDone(element, remoteObject, resultCode);
1093         });
1094 
1095     NativeReference* callback = nullptr;
1096     std::unique_ptr<AsyncTask::ExecuteCallback> execute = nullptr;
1097     AsyncTask::Schedule("JSServiceExtensionConnection::OnAbilityConnectDone",
1098         engine_, std::make_unique<AsyncTask>(callback, std::move(execute), std::move(complete)));
1099 }
1100 
HandleOnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)1101 void JSServiceExtensionConnection::HandleOnAbilityConnectDone(const AppExecFwk::ElementName &element,
1102     const sptr<IRemoteObject> &remoteObject, int resultCode)
1103 {
1104     HILOG_INFO("HandleOnAbilityConnectDone, resultCode:%{public}d", resultCode);
1105     // wrap ElementName
1106     napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(reinterpret_cast<napi_env>(&engine_), element);
1107     NativeValue* nativeElementName = reinterpret_cast<NativeValue*>(napiElementName);
1108 
1109     // wrap RemoteObject
1110     napi_value napiRemoteObject = NAPI_ohos_rpc_CreateJsRemoteObject(
1111         reinterpret_cast<napi_env>(&engine_), remoteObject);
1112     NativeValue* nativeRemoteObject = reinterpret_cast<NativeValue*>(napiRemoteObject);
1113     NativeValue* argv[] = {nativeElementName, nativeRemoteObject};
1114     if (jsConnectionObject_ == nullptr) {
1115         HILOG_ERROR("jsConnectionObject_ nullptr");
1116         return;
1117     }
1118     NativeValue* value = jsConnectionObject_->Get();
1119     NativeObject* obj = ConvertNativeValueTo<NativeObject>(value);
1120     if (obj == nullptr) {
1121         HILOG_ERROR("Failed to get object");
1122         return;
1123     }
1124     NativeValue* methodOnConnect = obj->GetProperty("onConnect");
1125     if (methodOnConnect == nullptr) {
1126         HILOG_ERROR("Failed to get onConnect from object");
1127         return;
1128     }
1129     engine_.CallFunction(value, methodOnConnect, argv, ARGC_TWO);
1130 }
1131 
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)1132 void JSServiceExtensionConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode)
1133 {
1134     HILOG_DEBUG("OnAbilityDisconnectDone, resultCode:%{public}d", resultCode);
1135     wptr<JSServiceExtensionConnection> connection = this;
1136     std::unique_ptr<AsyncTask::CompleteCallback> complete = std::make_unique<AsyncTask::CompleteCallback>
1137         ([connection, element, resultCode](NativeEngine &engine, AsyncTask &task, int32_t status) {
1138             sptr<JSServiceExtensionConnection> connectionSptr = connection.promote();
1139             if (!connectionSptr) {
1140                 HILOG_INFO("connectionSptr nullptr");
1141                 return;
1142             }
1143             connectionSptr->HandleOnAbilityDisconnectDone(element, resultCode);
1144         });
1145     NativeReference* callback = nullptr;
1146     std::unique_ptr<AsyncTask::ExecuteCallback> execute = nullptr;
1147     AsyncTask::Schedule("JSServiceExtensionConnection::OnAbilityDisconnectDone",
1148         engine_, std::make_unique<AsyncTask>(callback, std::move(execute), std::move(complete)));
1149 }
1150 
HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)1151 void JSServiceExtensionConnection::HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName &element,
1152     int resultCode)
1153 {
1154     HILOG_INFO("HandleOnAbilityDisconnectDone, resultCode:%{public}d", resultCode);
1155     napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(reinterpret_cast<napi_env>(&engine_), element);
1156     NativeValue* nativeElementName = reinterpret_cast<NativeValue*>(napiElementName);
1157     NativeValue* argv[] = {nativeElementName};
1158     if (jsConnectionObject_ == nullptr) {
1159         HILOG_ERROR("jsConnectionObject_ nullptr");
1160         return;
1161     }
1162     NativeValue* value = jsConnectionObject_->Get();
1163     NativeObject* obj = ConvertNativeValueTo<NativeObject>(value);
1164     if (obj == nullptr) {
1165         HILOG_ERROR("Failed to get object");
1166         return;
1167     }
1168 
1169     NativeValue* method = obj->GetProperty("onDisconnect");
1170     if (method == nullptr) {
1171         HILOG_ERROR("Failed to get onDisconnect from object");
1172         return;
1173     }
1174 
1175     // release connect
1176     HILOG_DEBUG("OnAbilityDisconnectDone g_connects.size:%{public}zu", g_connects.size());
1177     std::string bundleName = element.GetBundleName();
1178     std::string abilityName = element.GetAbilityName();
1179     auto item = std::find_if(g_connects.begin(),
1180         g_connects.end(),
1181         [bundleName, abilityName, connectionId = connectionId_](
1182             const auto &obj) {
1183             return (bundleName == obj.first.want.GetBundle()) &&
1184                    (abilityName == obj.first.want.GetElement().GetAbilityName()) &&
1185                    connectionId == obj.first.id;
1186         });
1187     if (item != g_connects.end()) {
1188         // match bundlename && abilityname
1189         g_connects.erase(item);
1190         HILOG_DEBUG("OnAbilityDisconnectDone erase g_connects.size:%{public}zu", g_connects.size());
1191     }
1192     engine_.CallFunction(value, method, argv, ARGC_ONE);
1193 }
1194 
SetJsConnectionObject(NativeValue * jsConnectionObject)1195 void JSServiceExtensionConnection::SetJsConnectionObject(NativeValue* jsConnectionObject)
1196 {
1197     jsConnectionObject_ = std::unique_ptr<NativeReference>(engine_.CreateReference(jsConnectionObject, 1));
1198 }
1199 
RemoveConnectionObject()1200 void JSServiceExtensionConnection::RemoveConnectionObject()
1201 {
1202     jsConnectionObject_.reset();
1203 }
1204 
CallJsFailed(int32_t errorCode)1205 void JSServiceExtensionConnection::CallJsFailed(int32_t errorCode)
1206 {
1207     HILOG_DEBUG("CallJsFailed begin");
1208     if (jsConnectionObject_ == nullptr) {
1209         HILOG_ERROR("jsConnectionObject_ nullptr");
1210         return;
1211     }
1212     NativeValue* value = jsConnectionObject_->Get();
1213     NativeObject* obj = ConvertNativeValueTo<NativeObject>(value);
1214     if (obj == nullptr) {
1215         HILOG_ERROR("Failed to get object");
1216         return;
1217     }
1218 
1219     NativeValue* method = obj->GetProperty("onFailed");
1220     if (method == nullptr) {
1221         HILOG_ERROR("Failed to get onFailed from object");
1222         return;
1223     }
1224     NativeValue* argv[] = {engine_.CreateNumber(errorCode)};
1225     engine_.CallFunction(value, method, argv, ARGC_ONE);
1226     HILOG_DEBUG("CallJsFailed end");
1227 }
1228 }  // namespace AbilityRuntime
1229 }  // namespace OHOS
1230