1 /*
2 * Copyright (c) 2021-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 "form_runtime/js_form_extension_context.h"
17
18 #include <cinttypes>
19 #include <cstdint>
20
21 #include "hilog_tag_wrapper.h"
22 #include "form_mgr_errors.h"
23 #include "ipc_skeleton.h"
24 #include "js_extension_context.h"
25 #include "js_error_utils.h"
26 #include "js_runtime.h"
27 #include "js_runtime_utils.h"
28 #include "napi/native_api.h"
29 #include "napi_common_ability.h"
30 #include "napi_common_start_options.h"
31 #include "napi_common_want.h"
32 #include "napi_remote_object.h"
33 #include "napi_form_util.h"
34 #include "tokenid_kit.h"
35 #include <charconv>
36
37 namespace OHOS {
38 namespace AbilityRuntime {
39 namespace {
40 constexpr int32_t INDEX_ZERO = 0;
41 constexpr int32_t INDEX_ONE = 1;
42 constexpr size_t ARGC_ONE = 1;
43 constexpr size_t ARGC_TWO = 2;
44 const int UPDATE_FORM_PARAMS_SIZE = 2;
45
46 std::map<ConnectionKey, sptr<JSFormExtensionConnection>, key_compare> g_connects;
47 int64_t g_serialNumber = 0;
48
RemoveConnection(int64_t connectId)49 void RemoveConnection(int64_t connectId)
50 {
51 auto item = std::find_if(g_connects.begin(), g_connects.end(),
52 [&connectId](const auto &obj) {
53 return connectId == obj.first.id;
54 });
55 if (item != g_connects.end()) {
56 TAG_LOGD(AAFwkTag::FORM_EXT, "ability exist");
57 if (item->second) {
58 item->second->RemoveConnectionObject();
59 }
60 g_connects.erase(item);
61 } else {
62 TAG_LOGD(AAFwkTag::FORM_EXT, "ability not exist");
63 }
64 }
65 class JsFormExtensionContext final {
66 public:
JsFormExtensionContext(const std::shared_ptr<FormExtensionContext> & context)67 explicit JsFormExtensionContext(const std::shared_ptr<FormExtensionContext>& context) : context_(context) {}
68 ~JsFormExtensionContext() = default;
69
Finalizer(napi_env env,void * data,void * hint)70 static void Finalizer(napi_env env, void* data, void* hint)
71 {
72 TAG_LOGI(AAFwkTag::FORM_EXT, "called");
73 std::unique_ptr<JsFormExtensionContext>(static_cast<JsFormExtensionContext*>(data));
74 }
75
UpdateForm(napi_env env,napi_callback_info info)76 static napi_value UpdateForm(napi_env env, napi_callback_info info)
77 {
78 GET_NAPI_INFO_AND_CALL(env, info, JsFormExtensionContext, OnUpdateForm);
79 }
80
StartAbility(napi_env env,napi_callback_info info)81 static napi_value StartAbility(napi_env env, napi_callback_info info)
82 {
83 GET_NAPI_INFO_AND_CALL(env, info, JsFormExtensionContext, OnStartAbility);
84 }
85
ConnectAbility(napi_env env,napi_callback_info info)86 static napi_value ConnectAbility(napi_env env, napi_callback_info info)
87 {
88 GET_NAPI_INFO_AND_CALL(env, info, JsFormExtensionContext, OnConnectAbility);
89 }
90
DisconnectAbility(napi_env env,napi_callback_info info)91 static napi_value DisconnectAbility(napi_env env, napi_callback_info info)
92 {
93 GET_NAPI_INFO_AND_CALL(env, info, JsFormExtensionContext, OnDisconnectAbility);
94 }
95
96 private:
97 std::weak_ptr<FormExtensionContext> context_;
98
CheckCallerIsSystemApp() const99 bool CheckCallerIsSystemApp() const
100 {
101 auto selfToken = IPCSkeleton::GetSelfTokenID();
102 return Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(selfToken);
103 }
104
OnUpdateForm(napi_env env,NapiCallbackInfo & info)105 napi_value OnUpdateForm(napi_env env, NapiCallbackInfo& info)
106 {
107 TAG_LOGI(AAFwkTag::FORM_EXT, "called");
108 if (info.argc < UPDATE_FORM_PARAMS_SIZE) {
109 TAG_LOGE(AAFwkTag::FORM_EXT, "invalid argc");
110 return CreateJsUndefined(env);
111 }
112
113 std::string strFormId;
114 ConvertFromJsValue(env, info.argv[0], strFormId);
115 int64_t formId = -1;
116 auto res = std::from_chars(strFormId.c_str(), strFormId.c_str() + strFormId.size(), formId);
117 if (res.ec != std::errc()) {
118 TAG_LOGE(AAFwkTag::FORM_EXT, "from_chars error strFormId:%{public}s", strFormId.c_str());
119 formId = -1;
120 }
121
122 AppExecFwk::FormProviderData formProviderData;
123 std::string formDataStr = "{}";
124 if (CheckTypeForNapiValue(env, info.argv[1], napi_object)) {
125 napi_value nativeDataValue = nullptr;
126 napi_get_named_property(env, info.argv[1], "data", &nativeDataValue);
127 if (nativeDataValue == nullptr || !ConvertFromJsValue(env, nativeDataValue, formDataStr)) {
128 TAG_LOGE(AAFwkTag::FORM_EXT, "NativeDataValue null or ConvertFromJsValue failed");
129 }
130 } else {
131 TAG_LOGE(AAFwkTag::FORM_EXT, "Not object");
132 }
133
134 formProviderData = AppExecFwk::FormProviderData(formDataStr);
135 NapiAsyncTask::CompleteCallback complete =
136 [weak = context_, formId, formProviderData](napi_env env, NapiAsyncTask& task, int32_t status) {
137 auto context = weak.lock();
138 if (!context) {
139 TAG_LOGW(AAFwkTag::FORM_EXT, "Context released");
140 task.Reject(env, CreateJsError(env, 1, "Context is released"));
141 return;
142 }
143 auto errcode = context->UpdateForm(formId, formProviderData);
144 if (errcode == ERR_OK) {
145 task.Resolve(env, CreateJsUndefined(env));
146 } else {
147 task.Reject(env, CreateJsError(env, errcode, "update form failed."));
148 }
149 };
150
151 napi_value lastParam =
152 (info.argc == UPDATE_FORM_PARAMS_SIZE) ? nullptr : info.argv[info.argc - 1];
153 napi_value result = nullptr;
154 NapiAsyncTask::ScheduleHighQos("JsFormExtensionContext::OnUpdateForm",
155 env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result));
156 return result;
157 }
158
OnStartAbility(napi_env env,NapiCallbackInfo & info)159 napi_value OnStartAbility(napi_env env, NapiCallbackInfo& info)
160 {
161 TAG_LOGI(AAFwkTag::FORM_EXT, "called");
162 // only support one or two params
163 if (info.argc != ARGC_ONE && info.argc != ARGC_TWO) {
164 TAG_LOGE(AAFwkTag::FORM_EXT, "Not enough params");
165 NapiFormUtil::ThrowParamNumError(env, std::to_string(info.argc), "1 or 2");
166 return CreateJsUndefined(env);
167 }
168
169 decltype(info.argc) unwrapArgc = 0;
170 AAFwk::Want want;
171 bool unwrapResult = OHOS::AppExecFwk::UnwrapWant(env, info.argv[INDEX_ZERO], want);
172 if (!unwrapResult) {
173 TAG_LOGE(AAFwkTag::FORM_EXT, "unwrap want failed");
174 NapiFormUtil::ThrowParamTypeError(env, "want", "Want");
175 return CreateJsUndefined(env);
176 }
177 TAG_LOGI(AAFwkTag::FORM_EXT, "Start bundle: %{public}s ability: %{public}s",
178 want.GetBundle().c_str(),
179 want.GetElement().GetAbilityName().c_str());
180 unwrapArgc++;
181
182 NapiAsyncTask::CompleteCallback complete =
183 [weak = context_, want](napi_env env, NapiAsyncTask& task, int32_t status) {
184 TAG_LOGI(AAFwkTag::FORM_EXT, "startAbility begin");
185 auto context = weak.lock();
186 if (!context) {
187 TAG_LOGW(AAFwkTag::FORM_EXT, "context is released");
188 task.Reject(env, NapiFormUtil::CreateErrorByInternalErrorCode(
189 env, ERR_APPEXECFWK_FORM_COMMON_CODE));
190 return;
191 }
192
193 // entry to the core functionality.
194 ErrCode innerErrorCode = context->StartAbility(want);
195 if (innerErrorCode == ERR_OK) {
196 task.Resolve(env, CreateJsUndefined(env));
197 } else {
198 TAG_LOGE(AAFwkTag::FORM_EXT, "Start failed: %{public}d", innerErrorCode);
199 task.Reject(env, NapiFormUtil::CreateErrorByInternalErrorCode(env, innerErrorCode));
200 }
201 };
202
203 napi_value lastParam = (info.argc == unwrapArgc) ? nullptr : info.argv[unwrapArgc];
204 napi_value result = nullptr;
205 NapiAsyncTask::ScheduleHighQos("JsFormExtensionContext::OnStartAbility",
206 env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result));
207 return result;
208 }
209
OnConnectAbility(napi_env env,NapiCallbackInfo & info)210 napi_value OnConnectAbility(napi_env env, NapiCallbackInfo& info)
211 {
212 TAG_LOGD(AAFwkTag::FORM_EXT, "called");
213 if (!CheckCallerIsSystemApp()) {
214 TAG_LOGE(AAFwkTag::FORM_EXT, "not system app");
215 ThrowError(env, AbilityErrorCode::ERROR_CODE_NOT_SYSTEM_APP);
216 return CreateJsUndefined(env);
217 }
218 // Check params count
219 if (info.argc < ARGC_TWO) {
220 TAG_LOGE(AAFwkTag::FORM_EXT, "invalid argc");
221 ThrowTooFewParametersError(env);
222 return CreateJsUndefined(env);
223 }
224 // Unwrap want and connection
225 AAFwk::Want want;
226 sptr<JSFormExtensionConnection> connection = new JSFormExtensionConnection(env);
227 if (!AppExecFwk::UnwrapWant(env, info.argv[0], want) ||
228 !CheckConnectionParam(env, info.argv[1], connection, want)) {
229 ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
230 return CreateJsUndefined(env);
231 }
232 int64_t connectId = connection->GetConnectionId();
233 NapiAsyncTask::CompleteCallback complete =
234 [weak = context_, want, connection, connectId](napi_env env, NapiAsyncTask& task, int32_t status) {
235 auto context = weak.lock();
236 if (!context) {
237 TAG_LOGE(AAFwkTag::FORM_EXT, "Context is free");
238 task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
239 RemoveConnection(connectId);
240 return;
241 }
242 TAG_LOGD(AAFwkTag::FORM_EXT, "ConnectAbility connection:%{public}d", static_cast<int32_t>(connectId));
243 auto innerErrorCode = context->ConnectAbility(want, connection);
244 int32_t errcode = static_cast<int32_t>(AbilityRuntime::GetJsErrorCodeByNativeError(innerErrorCode));
245 if (errcode) {
246 connection->CallJsFailed(errcode);
247 RemoveConnection(connectId);
248 }
249 task.Resolve(env, CreateJsUndefined(env));
250 };
251 napi_value result = nullptr;
252 NapiAsyncTask::ScheduleHighQos("JSFormExtensionConnection::OnConnectAbility",
253 env, CreateAsyncTaskWithLastParam(env, nullptr, nullptr, std::move(complete), &result));
254 return CreateJsValue(env, connectId);
255 }
256
OnDisconnectAbility(napi_env env,NapiCallbackInfo & info)257 napi_value OnDisconnectAbility(napi_env env, NapiCallbackInfo& info)
258 {
259 TAG_LOGI(AAFwkTag::FORM_EXT, "DisconnectAbility");
260 if (!CheckCallerIsSystemApp()) {
261 TAG_LOGE(AAFwkTag::FORM_EXT, "not system app");
262 ThrowError(env, AbilityErrorCode::ERROR_CODE_NOT_SYSTEM_APP);
263 return CreateJsUndefined(env);
264 }
265 if (info.argc < ARGC_ONE) {
266 TAG_LOGE(AAFwkTag::FORM_EXT, "invalid argc");
267 ThrowTooFewParametersError(env);
268 return CreateJsUndefined(env);
269 }
270 int64_t connectId = -1;
271 if (!AppExecFwk::UnwrapInt64FromJS2(env, info.argv[INDEX_ZERO], connectId)) {
272 ThrowError(env, AbilityErrorCode::ERROR_CODE_INVALID_PARAM);
273 return CreateJsUndefined(env);
274 }
275
276 AAFwk::Want want;
277 sptr<JSFormExtensionConnection> connection = nullptr;
278 FindConnection(want, connection, connectId);
279 // begin disconnect
280 NapiAsyncTask::CompleteCallback complete =
281 [weak = context_, want, connection](
282 napi_env env, NapiAsyncTask& task, int32_t status) {
283 auto context = weak.lock();
284 if (!context) {
285 TAG_LOGW(AAFwkTag::FORM_EXT, "Release context");
286 task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INVALID_CONTEXT));
287 return;
288 }
289 if (connection == nullptr) {
290 TAG_LOGW(AAFwkTag::FORM_EXT, "Connection null");
291 task.Reject(env, CreateJsError(env, AbilityErrorCode::ERROR_CODE_INNER));
292 return;
293 }
294 auto innerErrorCode = context->DisconnectAbility(want, connection);
295 if (innerErrorCode == 0) {
296 task.Resolve(env, CreateJsUndefined(env));
297 } else {
298 task.Reject(env, CreateJsErrorByNativeErr(env, innerErrorCode));
299 }
300 };
301
302 napi_value lastParam = (info.argc == ARGC_ONE) ? nullptr : info.argv[INDEX_ONE];
303 napi_value result = nullptr;
304 NapiAsyncTask::Schedule("JSFormExtensionConnection::OnDisconnectAbility",
305 env, CreateAsyncTaskWithLastParam(env, lastParam, nullptr, std::move(complete), &result));
306 return result;
307 }
308
CheckConnectionParam(napi_env env,napi_value value,sptr<JSFormExtensionConnection> & connection,AAFwk::Want & want) const309 bool CheckConnectionParam(napi_env env, napi_value value,
310 sptr<JSFormExtensionConnection>& connection, AAFwk::Want& want) const
311 {
312 if (!CheckTypeForNapiValue(env, value, napi_object)) {
313 TAG_LOGE(AAFwkTag::FORM_EXT, "get connection object failed");
314 return false;
315 }
316 connection->SetJsConnectionObject(value);
317 ConnectionKey key;
318 key.id = g_serialNumber;
319 key.want = want;
320 connection->SetConnectionId(key.id);
321 g_connects.emplace(key, connection);
322 if (g_serialNumber < INT32_MAX) {
323 g_serialNumber++;
324 } else {
325 g_serialNumber = 0;
326 }
327 TAG_LOGD(AAFwkTag::FORM_EXT, "not find connection");
328 return true;
329 }
330
FindConnection(AAFwk::Want & want,sptr<JSFormExtensionConnection> & connection,int64_t & connectId) const331 void FindConnection(AAFwk::Want& want, sptr<JSFormExtensionConnection>& connection, int64_t& connectId) const
332 {
333 TAG_LOGD(AAFwkTag::FORM_EXT, "connection:%{public}d", static_cast<int32_t>(connectId));
334 auto item = std::find_if(g_connects.begin(),
335 g_connects.end(),
336 [&connectId](const auto &obj) {
337 return connectId == obj.first.id;
338 });
339 if (item != g_connects.end()) {
340 // match id
341 want = item->first.want;
342 connection = item->second;
343 TAG_LOGD(AAFwkTag::FORM_EXT, "ability not exist");
344 }
345 return;
346 }
347 };
348 } // namespace
349
CreateJsFormExtensionContext(napi_env env,std::shared_ptr<FormExtensionContext> context)350 napi_value CreateJsFormExtensionContext(napi_env env, std::shared_ptr<FormExtensionContext> context)
351 {
352 TAG_LOGD(AAFwkTag::FORM_EXT, "called");
353 std::shared_ptr<OHOS::AppExecFwk::AbilityInfo> abilityInfo = nullptr;
354 if (context) {
355 abilityInfo = context->GetAbilityInfo();
356 }
357 napi_value object = CreateJsExtensionContext(env, context, abilityInfo);
358
359 std::unique_ptr<JsFormExtensionContext> jsContext = std::make_unique<JsFormExtensionContext>(context);
360 napi_wrap(env, object, jsContext.release(), JsFormExtensionContext::Finalizer, nullptr, nullptr);
361
362 const char *moduleName = "JsFormExtensionContext";
363 BindNativeFunction(env, object, "updateForm", moduleName, JsFormExtensionContext::UpdateForm);
364 BindNativeFunction(env, object, "startAbility", moduleName, JsFormExtensionContext::StartAbility);
365 BindNativeFunction(
366 env, object, "connectServiceExtensionAbility", moduleName, JsFormExtensionContext::ConnectAbility);
367 BindNativeFunction(env, object, "disconnectServiceExtensionAbility",
368 moduleName, JsFormExtensionContext::DisconnectAbility);
369
370 return object;
371 }
372
JSFormExtensionConnection(napi_env env)373 JSFormExtensionConnection::JSFormExtensionConnection(napi_env env) : env_(env) {}
374
~JSFormExtensionConnection()375 JSFormExtensionConnection::~JSFormExtensionConnection()
376 {
377 if (jsConnectionObject_ == nullptr) {
378 return;
379 }
380
381 uv_loop_t *loop = nullptr;
382 napi_get_uv_event_loop(env_, &loop);
383 if (loop == nullptr) {
384 return;
385 }
386
387 uv_work_t *work = new (std::nothrow) uv_work_t;
388 if (work == nullptr) {
389 return;
390 }
391 work->data = reinterpret_cast<void *>(jsConnectionObject_.release());
392 int ret = uv_queue_work(loop, work, [](uv_work_t *work) {},
393 [](uv_work_t *work, int status) {
394 if (work == nullptr) {
395 return;
396 }
397 if (work->data == nullptr) {
398 delete work;
399 work = nullptr;
400 return;
401 }
402 delete reinterpret_cast<NativeReference *>(work->data);
403 work->data = nullptr;
404 delete work;
405 work = nullptr;
406 });
407 if (ret != 0) {
408 delete reinterpret_cast<NativeReference *>(work->data);
409 work->data = nullptr;
410 delete work;
411 work = nullptr;
412 }
413 }
414
SetConnectionId(int64_t id)415 void JSFormExtensionConnection::SetConnectionId(int64_t id)
416 {
417 connectionId_ = id;
418 }
419
GetConnectionId()420 int64_t JSFormExtensionConnection::GetConnectionId()
421 {
422 return connectionId_;
423 }
424
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)425 void JSFormExtensionConnection::OnAbilityConnectDone(const AppExecFwk::ElementName &element,
426 const sptr<IRemoteObject> &remoteObject, int resultCode)
427 {
428 TAG_LOGD(AAFwkTag::FORM_EXT, "called, resultCode:%{public}d", resultCode);
429 wptr<JSFormExtensionConnection> connection = this;
430 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>
431 ([connection, element, remoteObject, resultCode](napi_env env, NapiAsyncTask &task, int32_t status) {
432 sptr<JSFormExtensionConnection> connectionSptr = connection.promote();
433 if (!connectionSptr) {
434 TAG_LOGE(AAFwkTag::FORM_EXT, "connectionSptr null");
435 return;
436 }
437 connectionSptr->HandleOnAbilityConnectDone(element, remoteObject, resultCode);
438 });
439
440 napi_ref callback = nullptr;
441 std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
442 NapiAsyncTask::Schedule("JSFormExtensionConnection::OnAbilityConnectDone",
443 env_, std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
444 }
445
HandleOnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int resultCode)446 void JSFormExtensionConnection::HandleOnAbilityConnectDone(const AppExecFwk::ElementName &element,
447 const sptr<IRemoteObject> &remoteObject, int resultCode)
448 {
449 TAG_LOGI(AAFwkTag::FORM_EXT, "called, resultCode:%{public}d", resultCode);
450 // wrap ElementName
451 napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(env_, element);
452
453 // wrap RemoteObject
454 napi_value napiRemoteObject = NAPI_ohos_rpc_CreateJsRemoteObject(env_, remoteObject);
455 napi_value argv[] = {napiElementName, napiRemoteObject};
456 if (jsConnectionObject_ == nullptr) {
457 TAG_LOGE(AAFwkTag::FORM_EXT, "jsConnectionObject null");
458 return;
459 }
460 napi_value obj = jsConnectionObject_->GetNapiValue();
461 if (!CheckTypeForNapiValue(env_, obj, napi_object)) {
462 TAG_LOGE(AAFwkTag::FORM_EXT, "get object error");
463 return;
464 }
465 napi_value methodOnConnect = nullptr;
466 napi_get_named_property(env_, obj, "onConnect", &methodOnConnect);
467 if (methodOnConnect == nullptr) {
468 TAG_LOGE(AAFwkTag::FORM_EXT, "get onConnect error");
469 return;
470 }
471 napi_call_function(env_, obj, methodOnConnect, ARGC_TWO, argv, nullptr);
472 }
473
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)474 void JSFormExtensionConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int resultCode)
475 {
476 TAG_LOGD(AAFwkTag::FORM_EXT, "called, resultCode:%{public}d", resultCode);
477 wptr<JSFormExtensionConnection> connection = this;
478 std::unique_ptr<NapiAsyncTask::CompleteCallback> complete = std::make_unique<NapiAsyncTask::CompleteCallback>
479 ([connection, element, resultCode](napi_env env, NapiAsyncTask &task, int32_t status) {
480 sptr<JSFormExtensionConnection> connectionSptr = connection.promote();
481 if (!connectionSptr) {
482 TAG_LOGI(AAFwkTag::FORM_EXT, "connectionSptr null");
483 return;
484 }
485 connectionSptr->HandleOnAbilityDisconnectDone(element, resultCode);
486 });
487 napi_ref callback = nullptr;
488 std::unique_ptr<NapiAsyncTask::ExecuteCallback> execute = nullptr;
489 NapiAsyncTask::Schedule("JSFormExtensionConnection::OnAbilityDisconnectDone",
490 env_, std::make_unique<NapiAsyncTask>(callback, std::move(execute), std::move(complete)));
491 }
492
HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)493 void JSFormExtensionConnection::HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName &element,
494 int resultCode)
495 {
496 TAG_LOGI(AAFwkTag::FORM_EXT, "called, resultCode:%{public}d", resultCode);
497 napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(env_, element);
498 napi_value argv[] = {napiElementName};
499 if (jsConnectionObject_ == nullptr) {
500 TAG_LOGE(AAFwkTag::FORM_EXT, "jsConnectionObject null");
501 return;
502 }
503 napi_value obj = jsConnectionObject_->GetNapiValue();
504 if (!CheckTypeForNapiValue(env_, obj, napi_object)) {
505 TAG_LOGE(AAFwkTag::FORM_EXT, "get object fail");
506 return;
507 }
508
509 napi_value method = nullptr;
510 napi_get_named_property(env_, obj, "onDisconnect", &method);
511 if (method == nullptr) {
512 TAG_LOGE(AAFwkTag::FORM_EXT, "get onDisconnect error");
513 return;
514 }
515
516 // release connect
517 TAG_LOGD(AAFwkTag::FORM_EXT, "size:%{public}zu", g_connects.size());
518 std::string bundleName = element.GetBundleName();
519 std::string abilityName = element.GetAbilityName();
520 auto item = std::find_if(g_connects.begin(),
521 g_connects.end(),
522 [bundleName, abilityName, connectionId = connectionId_](
523 const auto &obj) {
524 return (bundleName == obj.first.want.GetBundle()) &&
525 (abilityName == obj.first.want.GetElement().GetAbilityName()) &&
526 connectionId == obj.first.id;
527 });
528 if (item != g_connects.end()) {
529 // match bundleName && abilityName
530 g_connects.erase(item);
531 TAG_LOGD(AAFwkTag::FORM_EXT, "erase size:%{public}zu", g_connects.size());
532 }
533 napi_call_function(env_, obj, method, ARGC_ONE, argv, nullptr);
534 }
535
SetJsConnectionObject(napi_value jsConnectionObject)536 void JSFormExtensionConnection::SetJsConnectionObject(napi_value jsConnectionObject)
537 {
538 napi_ref ref = nullptr;
539 napi_create_reference(env_, jsConnectionObject, 1, &ref);
540 jsConnectionObject_ = std::unique_ptr<NativeReference>(reinterpret_cast<NativeReference*>(ref));
541 }
542
RemoveConnectionObject()543 void JSFormExtensionConnection::RemoveConnectionObject()
544 {
545 jsConnectionObject_.reset();
546 }
547
CallJsFailed(int32_t errorCode)548 void JSFormExtensionConnection::CallJsFailed(int32_t errorCode)
549 {
550 TAG_LOGD(AAFwkTag::FORM_EXT, "called");
551 if (jsConnectionObject_ == nullptr) {
552 TAG_LOGE(AAFwkTag::FORM_EXT, "jsConnectionObject null");
553 return;
554 }
555 napi_value obj = jsConnectionObject_->GetNapiValue();
556 if (!CheckTypeForNapiValue(env_, obj, napi_object)) {
557 TAG_LOGE(AAFwkTag::FORM_EXT, "get object error");
558 return;
559 }
560
561 napi_value method = nullptr;
562 napi_get_named_property(env_, obj, "onFailed", &method);
563 if (method == nullptr) {
564 TAG_LOGE(AAFwkTag::FORM_EXT, "get onFailed error");
565 return;
566 }
567 napi_value argv[] = {CreateJsValue(env_, errorCode)};
568 napi_call_function(env_, obj, method, ARGC_ONE, argv, nullptr);
569 TAG_LOGD(AAFwkTag::FORM_EXT, "CallJsFailed exit");
570 }
571 } // namespace AbilityRuntime
572 } // namespace OHOS
573