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