• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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_ui_service_extension_context.h"
17 
18 #include <chrono>
19 #include <cstdint>
20 #include "js_service_extension_context.h"
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 "start_options.h"
36 #include "hitrace_meter.h"
37 #include "js_free_install_observer.h"
38 
39 namespace OHOS {
40 namespace AbilityRuntime {
41 namespace {
42 constexpr int32_t INDEX_ZERO = 0;
43 constexpr int32_t INDEX_ONE = 1;
44 constexpr int32_t INDEX_TWO = 2;
45 constexpr int32_t ERROR_CODE_ONE = 1;
46 constexpr int32_t ERROR_CODE_TWO = 2;
47 constexpr size_t ARGC_ZERO = 0;
48 constexpr size_t ARGC_ONE = 1;
49 constexpr size_t ARGC_TWO = 2;
50 constexpr size_t ARGC_THREE = 3;
51 constexpr int32_t INVALID_PARAM = static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
52 
53 static std::mutex g_connectsMutex;
54 static std::map<ConnectionKey, sptr<JSUIServiceExtensionConnection>, key_compare> g_connects;
55 static int64_t g_serialNumber = 0;
56 
57 class JSUIServiceExtensionContext final {
58 public:
JSUIServiceExtensionContext(const std::shared_ptr<UIServiceExtensionContext> & context)59     explicit JSUIServiceExtensionContext(
60         const std::shared_ptr<UIServiceExtensionContext>& context) : context_(context) {}
61     ~JSUIServiceExtensionContext() = default;
62 
Finalizer(napi_env env,void * data,void * hint)63     static void Finalizer(napi_env env, void* data, void* hint)
64     {
65         TAG_LOGD(AAFwkTag::UISERVC_EXT, "JsAbilityContext::Finalizer is called");
66         std::unique_ptr<JSUIServiceExtensionContext>(static_cast<JSUIServiceExtensionContext*>(data));
67     }
68 
StartAbility(napi_env env,napi_callback_info info)69     static napi_value StartAbility(napi_env env, napi_callback_info info)
70     {
71         GET_NAPI_INFO_AND_CALL(env, info, JSUIServiceExtensionContext, OnStartAbility);
72     }
73 
TerminateSelf(napi_env env,napi_callback_info info)74     static napi_value TerminateSelf(napi_env env, napi_callback_info info)
75     {
76         GET_NAPI_INFO_AND_CALL(env, info, JSUIServiceExtensionContext, OnTerminateSelf);
77     }
78 
StartAbilityByType(napi_env env,napi_callback_info info)79     static napi_value StartAbilityByType(napi_env env, napi_callback_info info)
80     {
81         GET_NAPI_INFO_AND_CALL(env, info, JSUIServiceExtensionContext, OnStartAbilityByType);
82     }
83 
ConnectServiceExtensionAbility(napi_env env,napi_callback_info info)84     static napi_value ConnectServiceExtensionAbility(napi_env env, napi_callback_info info)
85     {
86         GET_NAPI_INFO_AND_CALL(env, info, JSUIServiceExtensionContext, OnConnectServiceExtensionAbility);
87     }
88 
DisConnectServiceExtensionAbility(napi_env env,napi_callback_info info)89     static napi_value DisConnectServiceExtensionAbility(napi_env env, napi_callback_info info)
90     {
91         GET_NAPI_INFO_AND_CALL(env, info, JSUIServiceExtensionContext, OnDisConnectServiceExtensionAbility);
92     }
93 
94 private:
95     std::weak_ptr<UIServiceExtensionContext> context_;
96 
97 #ifdef SUPPORT_SCREEN
InitDisplayId(AAFwk::Want & want,AAFwk::StartOptions & startOptions,napi_env & env,NapiCallbackInfo & info)98     void InitDisplayId(AAFwk::Want &want, AAFwk::StartOptions &startOptions, napi_env &env, NapiCallbackInfo& info)
99     {
100         auto context = context_.lock();
101         if (!context) {
102             TAG_LOGE(AAFwkTag::UISERVC_EXT, "null context");
103             return;
104         }
105 
106         auto window = context->GetWindow();
107         if (window == nullptr) {
108             TAG_LOGE(AAFwkTag::UISERVC_EXT, "null window");
109             return;
110         }
111 
112         int32_t displayId = 0;
113         if (info.argc > ARGC_ONE && CheckTypeForNapiValue(env, info.argv[1], napi_object)
114             && AppExecFwk::UnwrapInt32ByPropertyName(env, info.argv[1], "displayId", displayId)) {
115             TAG_LOGI(AAFwkTag::UISERVC_EXT, "startOption displayId %{public}d", startOptions.GetDisplayID());
116             return;
117         }
118 
119         TAG_LOGI(AAFwkTag::UISERVC_EXT, "window displayId %{public}" PRIu64, window->GetDisplayId());
120         startOptions.SetDisplayID(window->GetDisplayId());
121     }
122 #endif
123 
OnStartAbility(napi_env env,NapiCallbackInfo & info)124     napi_value OnStartAbility(napi_env env, NapiCallbackInfo& info)
125     {
126         HITRACE_METER_NAME(HITRACE_TAG_ABILITY_MANAGER, __PRETTY_FUNCTION__);
127         TAG_LOGI(AAFwkTag::UISERVC_EXT, "Call");
128         if (info.argc < ARGC_ONE) {
129             TAG_LOGE(AAFwkTag::UISERVC_EXT, "invalid argc");
130             ThrowTooFewParametersError(env);
131             return CreateJsUndefined(env);
132         }
133 
134         size_t unwrapArgc = 0;
135         AAFwk::Want want;
136         AAFwk::StartOptions startOptions;
137         if (!CheckStartAbilityInputParam(env, info, want, startOptions, unwrapArgc)) {
138             ThrowInvalidParamError(env, "Parse param want failed, want must be Want.");
139             return CreateJsUndefined(env);
140         }
141 #ifdef SUPPORT_SCREEN
142         InitDisplayId(want, startOptions, env, info);
143 #endif
144         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
145         NapiAsyncTask::ExecuteCallback execute = [weak = context_, want, startOptions, unwrapArgc, innerErrCode]() {
146             TAG_LOGD(AAFwkTag::UI_EXT, "JSUIServiceExtensionContext OnStartAbility");
147             auto context = weak.lock();
148             if (!context) {
149                 TAG_LOGE(AAFwkTag::UI_EXT, "null context");
150                 *innerErrCode = static_cast<int>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
151                 return;
152             }
153             *innerErrCode = context->StartAbility(want, startOptions);
154         };
155         NapiAsyncTask::CompleteCallback complete =
156         [innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
157             if (*innerErrCode == ERR_OK) {
158                 task.ResolveWithNoError(env, CreateJsUndefined(env));
159             } else if (*innerErrCode == static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)) {
160                 task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
161             } else {
162                 task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
163             }
164         };
165 
166     napi_value lastParam = nullptr;
167     napi_value result = nullptr;
168     NapiAsyncTask::ScheduleHighQos("JSUIServiceExtensionContext::OnStartAbility",
169         env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
170     return result;
171 }
172 
CheckStartAbilityInputParam(napi_env env,NapiCallbackInfo & info,AAFwk::Want & want,AAFwk::StartOptions & startOptions,size_t & unwrapArgc) const173     bool CheckStartAbilityInputParam(napi_env env, NapiCallbackInfo& info,
174         AAFwk::Want& want, AAFwk::StartOptions& startOptions, size_t& unwrapArgc) const
175     {
176         if (info.argc < ARGC_ONE) {
177             return false;
178         }
179         unwrapArgc = ARGC_ZERO;
180         // Check input want
181         if (!AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want)) {
182             return false;
183         }
184         ++unwrapArgc;
185         if (info.argc > ARGC_ONE && CheckTypeForNapiValue(env, info.argv[1], napi_object)) {
186             TAG_LOGD(AAFwkTag::UISERVC_EXT, "OnStartAbility start options is used.");
187             AppExecFwk::UnwrapStartOptions(env, info.argv[1], startOptions);
188             unwrapArgc++;
189         }
190         return true;
191     }
192 
OnTerminateSelf(napi_env env,NapiCallbackInfo & info)193     napi_value OnTerminateSelf(napi_env env, NapiCallbackInfo& info)
194     {
195         TAG_LOGI(AAFwkTag::UISERVC_EXT, "Call");
196         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
197         NapiAsyncTask::ExecuteCallback execute = [weak = context_, innerErrCode]() {
198             auto context = weak.lock();
199             if (!context) {
200                 TAG_LOGW(AAFwkTag::UISERVC_EXT, "null context");
201                 *innerErrCode = static_cast<int>(ERROR_CODE_ONE);
202                 return;
203             }
204             TAG_LOGD(AAFwkTag::UISERVC_EXT, "JSUIServiceExtensionContext OnTerminateSelf");
205             *innerErrCode= context->TerminateSelf();
206         };
207         NapiAsyncTask::CompleteCallback complete = [innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
208             if (*innerErrCode == ERR_OK) {
209                 task.Resolve(env, CreateJsUndefined(env));
210             } else if (*innerErrCode == ERROR_CODE_ONE) {
211                 task.Reject(env, CreateJsError(env, *innerErrCode, "Context is released"));
212             } else {
213                 task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
214             }
215         };
216         napi_value lastParam = nullptr;
217         napi_value result = nullptr;
218         NapiAsyncTask::ScheduleHighQos("JSUIServiceExtensionContext::OnTerminateSelf",
219             env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
220         return result;
221     }
222 
OnStartAbilityByType(napi_env env,NapiCallbackInfo & info)223     napi_value OnStartAbilityByType(napi_env env, NapiCallbackInfo& info)
224     {
225         TAG_LOGI(AAFwkTag::UISERVC_EXT, "Call");
226         if (info.argc < ARGC_THREE) {
227             TAG_LOGE(AAFwkTag::UISERVC_EXT, "not enough params");
228             ThrowTooFewParametersError(env);
229             return CreateJsUndefined(env);
230         }
231 
232         std::string type;
233         if (!ConvertFromJsValue(env, info.argv[INDEX_ZERO], type)) {
234             TAG_LOGE(AAFwkTag::UISERVC_EXT, "parse type failed");
235             ThrowError(env, INVALID_PARAM, "Incorrect parameter types, param type must be a string");
236             return CreateJsUndefined(env);
237         }
238 
239         AAFwk::WantParams wantParam;
240         if (!AppExecFwk::UnwrapWantParams(env, info.argv[INDEX_ONE], wantParam)) {
241             TAG_LOGE(AAFwkTag::UISERVC_EXT, "parse wantParam failed");
242             ThrowError(env, INVALID_PARAM, "Parameter error. The type of \"WantParams\" must be array");
243             return CreateJsUndefined(env);
244         }
245 
246         std::shared_ptr<JsUIExtensionCallback> callback = std::make_shared<JsUIExtensionCallback>(env);
247         callback->SetJsCallbackObject(info.argv[INDEX_TWO]);
248         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
249         NapiAsyncTask::ExecuteCallback execute = [weak = context_, type, wantParam, callback, innerErrCode]() mutable {
250             auto context = weak.lock();
251             if (!context) {
252                 TAG_LOGW(AAFwkTag::UISERVC_EXT, "null context");
253                 *innerErrCode = static_cast<int>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
254                 return;
255             }
256             TAG_LOGD(AAFwkTag::UISERVC_EXT, "JSUIServiceExtensionContext OnStartAbilityByType");
257             *innerErrCode = context->StartAbilityByType(type, wantParam, callback);
258         };
259         NapiAsyncTask::CompleteCallback complete =
260             [innerErrCode](napi_env env, NapiAsyncTask& task, int32_t status) {
261                 if (*innerErrCode == ERR_OK) {
262                     task.ResolveWithNoError(env, CreateJsUndefined(env));
263                 } else if (*innerErrCode == static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT)) {
264                     task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
265                 } else {
266                     task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
267                 }
268             };
269 
270         napi_value lastParam = nullptr;
271         napi_value result = nullptr;
272         NapiAsyncTask::ScheduleHighQos("JSUIServiceExtensionContext::OnStartAbilityByType",
273             env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
274         return result;
275     }
276 
CheckConnectionParam(napi_env env,napi_value value,sptr<JSUIServiceExtensionConnection> & connection,AAFwk::Want & want,int32_t accountId=-1) const277     bool CheckConnectionParam(napi_env env, napi_value value,
278         sptr<JSUIServiceExtensionConnection>& connection, AAFwk::Want& want, int32_t accountId = -1) const
279     {
280         if (!CheckTypeForNapiValue(env, value, napi_object)) {
281             TAG_LOGE(AAFwkTag::UISERVC_EXT, "get object failed");
282             return false;
283         }
284 
285         if (connection == nullptr) {
286             TAG_LOGE(AAFwkTag::UISERVC_EXT, "null connection");
287             return false;
288         }
289         connection->SetJsConnectionObject(value);
290         ConnectionKey key;
291         {
292             std::lock_guard guard(g_connectsMutex);
293             key.id = g_serialNumber;
294             key.want = want;
295             key.accountId = accountId;
296             connection->SetConnectionId(key.id);
297             g_connects.emplace(key, connection);
298             if (g_serialNumber < INT32_MAX) {
299                 g_serialNumber++;
300             } else {
301                 g_serialNumber = 0;
302             }
303         }
304         TAG_LOGD(AAFwkTag::UISERVC_EXT, "Unable to find connection, make new one");
305         return true;
306     }
307 
GetConnectAbilityExecFunc(const AAFwk::Want & want,sptr<JSUIServiceExtensionConnection> connection,int64_t connectId,std::shared_ptr<int> innerErrorCode)308     NapiAsyncTask::ExecuteCallback GetConnectAbilityExecFunc(const AAFwk::Want &want,
309         sptr<JSUIServiceExtensionConnection> connection, int64_t connectId, std::shared_ptr<int> innerErrorCode)
310     {
311         return [weak = context_, want, connection, connectId, innerErrorCode]() {
312             if (innerErrorCode == nullptr) {
313                 TAG_LOGE(AAFwkTag::UISERVC_EXT, "null innerErrorCode");
314                 return;
315             }
316 
317             auto context = weak.lock();
318             if (!context) {
319                 TAG_LOGE(AAFwkTag::UISERVC_EXT, "null context");
320                 *innerErrorCode = static_cast<int>(AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT);
321                 return;
322             }
323 
324             *innerErrorCode = context->ConnectServiceExtensionAbility(want, connection);
325         };
326     }
327 
FindConnection(AAFwk::Want & want,sptr<JSUIServiceExtensionConnection> & connection,int64_t & connectId,int32_t & accountId) const328     void FindConnection(AAFwk::Want& want, sptr<JSUIServiceExtensionConnection>& connection, int64_t& connectId,
329         int32_t &accountId) const
330     {
331         TAG_LOGI(AAFwkTag::UISERVC_EXT, "connection:%{public}d", static_cast<int32_t>(connectId));
332         std::lock_guard guard(g_connectsMutex);
333         auto item = std::find_if(g_connects.begin(),
334             g_connects.end(),
335             [&connectId](const auto &obj) {
336                 return connectId == obj.first.id;
337             });
338         if (item != g_connects.end()) {
339             // match id
340             want = item->first.want;
341             connection = item->second;
342             accountId = item->first.accountId;
343             TAG_LOGD(AAFwkTag::UISERVC_EXT, "find conn ability exist");
344         }
345         return;
346     }
347 
RemoveConnection(int64_t connectId)348     void RemoveConnection(int64_t connectId)
349     {
350         TAG_LOGD(AAFwkTag::UISERVC_EXT, "enter");
351         std::lock_guard guard(g_connectsMutex);
352         auto item = std::find_if(g_connects.begin(), g_connects.end(),
353         [&connectId](const auto &obj) {
354             return connectId == obj.first.id;
355         });
356         if (item != g_connects.end()) {
357             TAG_LOGD(AAFwkTag::UISERVC_EXT, "remove conn ability exist.");
358             if (item->second) {
359                 item->second->RemoveConnectionObject();
360             }
361             g_connects.erase(item);
362         } else {
363             TAG_LOGD(AAFwkTag::UISERVC_EXT, "remove conn ability not exist.");
364         }
365     }
366 
OnConnectServiceExtensionAbility(napi_env env,NapiCallbackInfo & info)367     napi_value OnConnectServiceExtensionAbility(napi_env env, NapiCallbackInfo& info)
368     {
369         TAG_LOGD(AAFwkTag::UISERVC_EXT, "Connect ServiceExtensionAbility called.");
370         // Check params count
371         if (info.argc < ARGC_TWO) {
372             TAG_LOGE(AAFwkTag::UISERVC_EXT, "not enough params");
373             ThrowTooFewParametersError(env);
374             return CreateJsUndefined(env);
375         }
376         // Unwrap want and connection
377         AAFwk::Want want;
378         sptr<JSUIServiceExtensionConnection> connection = new JSUIServiceExtensionConnection(env);
379         if (!AppExecFwk::UnwrapWant(env, info.argv[0], want)) {
380             ThrowInvalidParamError(env, "Parse param want failed, must be a Want.");
381             return CreateJsUndefined(env);
382         }
383         if (!CheckConnectionParam(env, info.argv[1], connection, want)) {
384             ThrowInvalidParamError(env, "Parse param options failed, must be a ConnectOptions.");
385             return CreateJsUndefined(env);
386         }
387         int64_t connectId = connection->GetConnectionId();
388         auto innerErrorCode = std::make_shared<int32_t>(ERR_OK);
389         auto execute = GetConnectAbilityExecFunc(want, connection, connectId, innerErrorCode);
390         NapiAsyncTask::CompleteCallback complete = [this, connection, connectId, innerErrorCode](napi_env env,
391             NapiAsyncTask& task, int32_t status) {
392             if (*innerErrorCode == 0) {
393                 TAG_LOGI(AAFwkTag::UISERVC_EXT, "connect ability success");
394                 task.ResolveWithNoError(env, CreateJsUndefined(env));
395                 return;
396             }
397 
398             TAG_LOGE(AAFwkTag::UISERVC_EXT, "connect ability failed");
399             int32_t errcode = static_cast<int32_t>(AbilityRuntime::GetJsErrorCodeByNativeError(*innerErrorCode));
400             if (errcode) {
401                 connection->CallJsFailed(errcode);
402                 this->RemoveConnection(connectId);
403             }
404         };
405         napi_value result = nullptr;
406         NapiAsyncTask::ScheduleHighQos("JSUIServiceExtensionContext::OnConnectServiceExtensionAbility",
407             env, CreateAsyncTaskWithLastParam(env, nullptr, std::move(execute), std::move(complete), &result));
408         return CreateJsValue(env, connectId);
409     }
410 
OnDisConnectServiceExtensionAbility(napi_env env,NapiCallbackInfo & info)411     napi_value OnDisConnectServiceExtensionAbility(napi_env env, NapiCallbackInfo& info)
412     {
413         TAG_LOGD(AAFwkTag::UISERVC_EXT, "DisConnect ServiceExtensionAbility start");
414         if (info.argc < ARGC_ONE) {
415             TAG_LOGE(AAFwkTag::UISERVC_EXT, "not enough params");
416             ThrowTooFewParametersError(env);
417             return CreateJsUndefined(env);
418         }
419         int64_t connectId = -1;
420         if (!AppExecFwk::UnwrapInt64FromJS2(env, info.argv[INDEX_ZERO], connectId)) {
421             ThrowInvalidParamError(env, "Parse param connection failed, must be a number.");
422             return CreateJsUndefined(env);
423         }
424         AAFwk::Want want;
425         sptr<JSUIServiceExtensionConnection> connection = nullptr;
426         int32_t accountId = -1;
427         FindConnection(want, connection, connectId, accountId);
428         // begin disconnect
429         auto innerErrCode = std::make_shared<ErrCode>(ERR_OK);
430         NapiAsyncTask::ExecuteCallback execute = [weak = context_, want, connection, accountId, innerErrCode]() {
431             auto context = weak.lock();
432             if (!context) {
433                 TAG_LOGW(AAFwkTag::UISERVC_EXT, "null context");
434                 *innerErrCode = ERROR_CODE_ONE;
435                 return;
436             }
437             if (!connection) {
438                 TAG_LOGW(AAFwkTag::UISERVC_EXT, "null connection");
439                 *innerErrCode = ERROR_CODE_TWO;
440                 return;
441             }
442             TAG_LOGD(AAFwkTag::UISERVC_EXT, "context->DisconnectServiceExtensionAbility");
443             *innerErrCode = context->DisConnectServiceExtensionAbility(want, connection, accountId);
444         };
445         NapiAsyncTask::CompleteCallback complete = [innerErrCode](
446             napi_env env, NapiAsyncTask& task, int32_t status) {
447                 if (*innerErrCode == ERROR_CODE_ONE) {
448                     task.Reject(env, CreateJsError(env, ERROR_CODE_ONE, "Context is released"));
449                     return;
450                 }
451                 if (*innerErrCode == ERROR_CODE_TWO) {
452                     task.Reject(env, CreateJsError(env, ERROR_CODE_TWO, "not found connection"));
453                     return;
454                 }
455                 if (*innerErrCode == ERR_OK) {
456                     task.ResolveWithNoError(env, CreateJsUndefined(env));
457                 } else {
458                     task.Reject(env, CreateJsErrorByNativeErr(env, *innerErrCode));
459                 }
460             };
461         napi_value lastParam = (info.argc == ARGC_ONE) ? nullptr : info.argv[INDEX_ONE];
462         napi_value result = nullptr;
463         NapiAsyncTask::Schedule("JSUIServiceExtensionContext::OnDisConnectServiceExtensionAbility",
464             env, CreateAsyncTaskWithLastParam(env, lastParam, std::move(execute), std::move(complete), &result));
465         return result;
466     }
467 };
468 } // namespace
469 
CreateJsUIServiceExtensionContext(napi_env env,std::shared_ptr<UIServiceExtensionContext> context)470 napi_value CreateJsUIServiceExtensionContext(napi_env env, std::shared_ptr<UIServiceExtensionContext> context)
471 {
472     TAG_LOGD(AAFwkTag::UISERVC_EXT, "Call");
473     std::shared_ptr<OHOS::AppExecFwk::AbilityInfo> abilityInfo = nullptr;
474     if (context) {
475         abilityInfo = context->GetAbilityInfo();
476     }
477     napi_value object = CreateJsExtensionContext(env, context, abilityInfo);
478 
479     std::unique_ptr<JSUIServiceExtensionContext> jsUIContext =
480         std::make_unique<JSUIServiceExtensionContext>(context);
481     napi_wrap(env, object, jsUIContext.release(), JSUIServiceExtensionContext::Finalizer, nullptr, nullptr);
482 
483     const char *moduleName = "JsUIServiceExtensionContext";
484     BindNativeFunction(env, object, "startAbility", moduleName, JSUIServiceExtensionContext::StartAbility);
485     BindNativeFunction(env, object, "terminateSelf", moduleName, JSUIServiceExtensionContext::TerminateSelf);
486     BindNativeFunction(env, object, "startAbilityByType", moduleName,
487         JSUIServiceExtensionContext::StartAbilityByType);
488     BindNativeFunction(env, object, "connectServiceExtensionAbility", moduleName,
489         JSUIServiceExtensionContext::ConnectServiceExtensionAbility);
490     BindNativeFunction(env, object, "disconnectServiceExtensionAbility", moduleName,
491         JSUIServiceExtensionContext::DisConnectServiceExtensionAbility);
492     return object;
493 }
494 
JSUIServiceExtensionConnection(napi_env env)495 JSUIServiceExtensionConnection::JSUIServiceExtensionConnection(napi_env env) : env_(env) {}
496 
~JSUIServiceExtensionConnection()497 JSUIServiceExtensionConnection::~JSUIServiceExtensionConnection()
498 {
499     if (jsConnectionObject_ == nullptr) {
500         return;
501     }
502 
503     uv_loop_t *loop = nullptr;
504     napi_get_uv_event_loop(env_, &loop);
505     if (loop == nullptr) {
506         return;
507     }
508 
509     uv_work_t *work = new (std::nothrow) uv_work_t;
510     if (work == nullptr) {
511         return;
512     }
513     work->data = reinterpret_cast<void *>(jsConnectionObject_.release());
514     int ret = uv_queue_work(loop, work, [](uv_work_t *work) {},
515     [](uv_work_t *work, int status) {
516         if (work == nullptr) {
517             return;
518         }
519         if (work->data == nullptr) {
520             delete work;
521             work = nullptr;
522             return;
523         }
524         delete reinterpret_cast<NativeReference *>(work->data);
525         work->data = nullptr;
526         delete work;
527         work = nullptr;
528     });
529     if (ret != 0) {
530         delete reinterpret_cast<NativeReference *>(work->data);
531         work->data = nullptr;
532         delete work;
533         work = nullptr;
534     }
535 }
536 
SetConnectionId(int64_t id)537 void JSUIServiceExtensionConnection::SetConnectionId(int64_t id)
538 {
539     connectionId_ = id;
540 }
541 
GetConnectionId()542 int64_t JSUIServiceExtensionConnection::GetConnectionId()
543 {
544     return connectionId_;
545 }
546 
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)547 void JSUIServiceExtensionConnection::OnAbilityConnectDone(const AppExecFwk::ElementName &element,
548     const sptr<IRemoteObject> &remoteObject, int resultCode)
549 {
550     TAG_LOGD(AAFwkTag::UISERVC_EXT, "OnAbilityConnectDone, resultCode:%{public}d", resultCode);
551     wptr<JSUIServiceExtensionConnection> connection = this;
552     std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>
553         ([connection, element, remoteObject, resultCode](napi_env env, NapiAsyncTask &task, int32_t status) {
554             sptr<JSUIServiceExtensionConnection> connectionSptr = connection.promote();
555             if (!connectionSptr) {
556                 TAG_LOGE(AAFwkTag::UISERVC_EXT, "null connectionSptr");
557                 return;
558             }
559             connectionSptr->HandleOnAbilityConnectDone(element, remoteObject, resultCode);
560         });
561 
562     napi_ref callback = nullptr;
563     std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
564     NapiAsyncTask::Schedule("JSUIServiceExtensionConnection::OnAbilityConnectDone",
565         env_, std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
566 }
567 
HandleOnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)568 void JSUIServiceExtensionConnection::HandleOnAbilityConnectDone(const AppExecFwk::ElementName &element,
569     const sptr<IRemoteObject> &remoteObject, int resultCode)
570 {
571     TAG_LOGD(AAFwkTag::UISERVC_EXT, "resultCode:%{public}d", resultCode);
572     // wrap ElementName
573     napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(env_, element);
574 
575     // wrap RemoteObject
576     napi_value napiRemoteObject = NAPI_ohos_rpc_CreateJsRemoteObject(env_, remoteObject);
577     napi_value argv[] = {napiElementName, napiRemoteObject};
578     if (jsConnectionObject_ == nullptr) {
579         TAG_LOGE(AAFwkTag::UISERVC_EXT, "null jsConnectionObject_");
580         return;
581     }
582     napi_value obj = jsConnectionObject_->GetNapiValue();
583     if (!CheckTypeForNapiValue(env_, obj, napi_object)) {
584         TAG_LOGE(AAFwkTag::UISERVC_EXT, "get object error");
585         return;
586     }
587     napi_value methodOnConnect = nullptr;
588     napi_get_named_property(env_, obj, "onConnect", &methodOnConnect);
589     if (methodOnConnect == nullptr) {
590         TAG_LOGE(AAFwkTag::UISERVC_EXT, "null methodOnConnect");
591         return;
592     }
593     napi_call_function(env_, obj, methodOnConnect, ARGC_TWO, argv, nullptr);
594 }
595 
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)596 void JSUIServiceExtensionConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode)
597 {
598     TAG_LOGD(AAFwkTag::UISERVC_EXT, "OnAbilityDisconnectDone, resultCode:%{public}d", resultCode);
599     wptr<JSUIServiceExtensionConnection> connection = this;
600     std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>
601         ([connection, element, resultCode](napi_env env, NapiAsyncTask &task, int32_t status) {
602             sptr<JSUIServiceExtensionConnection> connectionSptr = connection.promote();
603             if (!connectionSptr) {
604                 TAG_LOGI(AAFwkTag::UISERVC_EXT, "null connectionSptr");
605                 return;
606             }
607             connectionSptr->HandleOnAbilityDisconnectDone(element, resultCode);
608         });
609     napi_ref callback = nullptr;
610     std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
611     NapiAsyncTask::Schedule("JSUIServiceExtensionConnection::OnAbilityDisconnectDone",
612         env_, std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
613 }
614 
HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)615 void JSUIServiceExtensionConnection::HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName &element,
616     int resultCode)
617 {
618     TAG_LOGD(AAFwkTag::UISERVC_EXT, "HandleOnAbilityDisconnectDone, resultCode:%{public}d", resultCode);
619     napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(env_, element);
620     napi_value argv[] = {napiElementName};
621     if (jsConnectionObject_ == nullptr) {
622         TAG_LOGE(AAFwkTag::UISERVC_EXT, "null jsConnectionObject_");
623         return;
624     }
625     napi_value obj = jsConnectionObject_->GetNapiValue();
626     if (!CheckTypeForNapiValue(env_, obj, napi_object)) {
627         TAG_LOGE(AAFwkTag::UISERVC_EXT, "get object error");
628         return;
629     }
630 
631     napi_value method = nullptr;
632     napi_get_named_property(env_, obj, "onDisconnect", &method);
633     if (method == nullptr) {
634         TAG_LOGE(AAFwkTag::UISERVC_EXT, "null method");
635         return;
636     }
637 
638     // release connect
639     {
640         std::lock_guard guard(g_connectsMutex);
641         TAG_LOGD(AAFwkTag::UISERVC_EXT, "OnAbilityDisconnectDone g_connects.size:%{public}zu", g_connects.size());
642         std::string bundleName = element.GetBundleName();
643         std::string abilityName = element.GetAbilityName();
644         auto item = std::find_if(g_connects.begin(),
645             g_connects.end(),
646             [bundleName, abilityName, connectionId = connectionId_](
647                 const auto &obj) {
648                 return (bundleName == obj.first.want.GetBundle()) &&
649                     (abilityName == obj.first.want.GetElement().GetAbilityName()) &&
650                     connectionId == obj.first.id;
651             });
652         if (item != g_connects.end()) {
653             // match bundlename && abilityname
654             g_connects.erase(item);
655             TAG_LOGD(
656                 AAFwkTag::UISERVC_EXT, "OnAbilityDisconnectDone erase g_connects.size:%{public}zu", g_connects.size());
657         }
658     }
659     napi_call_function(env_, obj, method, ARGC_ONE, argv, nullptr);
660 }
661 
SetJsConnectionObject(napi_value jsConnectionObject)662 void JSUIServiceExtensionConnection::SetJsConnectionObject(napi_value jsConnectionObject)
663 {
664     napi_ref ref = nullptr;
665     napi_create_reference(env_, jsConnectionObject, 1, &ref);
666     jsConnectionObject_ = std::unique_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref));
667 }
668 
RemoveConnectionObject()669 void JSUIServiceExtensionConnection::RemoveConnectionObject()
670 {
671     jsConnectionObject_.reset();
672 }
673 
CallJsFailed(int32_t errorCode)674 void JSUIServiceExtensionConnection::CallJsFailed(int32_t errorCode)
675 {
676     TAG_LOGD(AAFwkTag::UISERVC_EXT, "CallJsFailed begin");
677     if (jsConnectionObject_ == nullptr) {
678         TAG_LOGE(AAFwkTag::UISERVC_EXT, "null jsConnectionObject_");
679         return;
680     }
681     napi_value obj = jsConnectionObject_->GetNapiValue();
682     if (!CheckTypeForNapiValue(env_, obj, napi_object)) {
683         TAG_LOGE(AAFwkTag::UISERVC_EXT, "get object wrong");
684         return;
685     }
686 
687     napi_value method = nullptr;
688     napi_get_named_property(env_, obj, "onFailed", &method);
689     if (method == nullptr) {
690         TAG_LOGE(AAFwkTag::UISERVC_EXT, "null method");
691         return;
692     }
693     napi_value argv[] = {CreateJsValue(env_, errorCode)};
694     napi_call_function(env_, obj, method, ARGC_ONE, argv, nullptr);
695     TAG_LOGD(AAFwkTag::UISERVC_EXT, "CallJsFailed end");
696 }
697 } // namespace AbilityRuntime
698 }  // namespace OHOS
699