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