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