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