1 /*
2 * Copyright (c) 2021 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 <cstdint>
17 #include <mutex>
18
19 #include "ability_business_error.h"
20 #include "hilog_wrapper.h"
21 #include "js_data_struct_converter.h"
22 #include "js_error_utils.h"
23 #include "js_extension_context.h"
24 #include "js_runtime.h"
25 #include "js_runtime_utils.h"
26 #include "js_wallpaper_extension_context.h"
27 #include "napi/native_api.h"
28 #include "napi/native_node_api.h"
29 #include "napi_common_start_options.h"
30 #include "napi_common_util.h"
31 #include "napi_common_want.h"
32 #include "napi_remote_object.h"
33 #include "start_options.h"
34 #include "want.h"
35
36 namespace OHOS {
37 namespace AbilityRuntime {
38 namespace {
39 constexpr int32_t INDEX_ZERO = 0;
40 constexpr int32_t INDEX_ONE = 1;
41 constexpr int32_t INDEX_TWO = 2;
42 constexpr int32_t ERROR_CODE_ONE = 1;
43 constexpr int32_t ERROR_CODE_TWO = 2;
44 constexpr size_t ARGC_ZERO = 0;
45 constexpr size_t ARGC_ONE = 1;
46 constexpr size_t ARGC_TWO = 2;
47 constexpr size_t ARGC_THREE = 3;
48 constexpr size_t ARGC_FOUR = 4;
49
50 static std::map<ConnecttionKey, sptr<JSWallpaperExtensionConnection>, key_compare> connects_;
51 static std::mutex g_connectMapMtx;
52 static int64_t g_serialNumber = 0;
53 static std::shared_ptr<AppExecFwk::EventHandler> handler_ = nullptr;
54
55 class JsWallpaperExtensionContext final {
56 public:
JsWallpaperExtensionContext(const std::shared_ptr<WallpaperExtensionContext> & context)57 explicit JsWallpaperExtensionContext(const std::shared_ptr<WallpaperExtensionContext> &context) : context_(context)
58 {
59 }
60 ~JsWallpaperExtensionContext() = default;
61 JsWallpaperExtensionContext() = default;
62
Finalizer(napi_env env,void * data,void * hint)63 static void Finalizer(napi_env env, void *data, void *hint)
64 {
65 HILOG_INFO("JsAbilityContext::Finalizer is called.");
66 std::unique_ptr<JsWallpaperExtensionContext>(static_cast<JsWallpaperExtensionContext *>(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_CB_INFO_AND_CALL(env, info, JsWallpaperExtensionContext, OnStartAbility);
72 }
73
StartAbilityWithAccount(napi_env env,napi_callback_info info)74 static napi_value StartAbilityWithAccount(napi_env env, napi_callback_info info)
75 {
76 GET_CB_INFO_AND_CALL(env, info, JsWallpaperExtensionContext, OnStartAbilityWithAccount);
77 }
78
ConnectAbilityWithAccount(napi_env env,napi_callback_info info)79 static napi_value ConnectAbilityWithAccount(napi_env env, napi_callback_info info)
80 {
81 GET_CB_INFO_AND_CALL(env, info, JsWallpaperExtensionContext, OnConnectAbilityWithAccount);
82 }
83
TerminateAbility(napi_env env,napi_callback_info info)84 static napi_value TerminateAbility(napi_env env, napi_callback_info info)
85 {
86 GET_CB_INFO_AND_CALL(env, info, JsWallpaperExtensionContext, OnTerminateAbility);
87 }
88
ConnectAbility(napi_env env,napi_callback_info info)89 static napi_value ConnectAbility(napi_env env, napi_callback_info info)
90 {
91 GET_CB_INFO_AND_CALL(env, info, JsWallpaperExtensionContext, OnConnectAbility);
92 }
93
DisconnectAbility(napi_env env,napi_callback_info info)94 static napi_value DisconnectAbility(napi_env env, napi_callback_info info)
95 {
96 GET_CB_INFO_AND_CALL(env, info, JsWallpaperExtensionContext, OnDisconnectAbility);
97 }
98
99 private:
100 std::weak_ptr<WallpaperExtensionContext> context_;
101
OnStartAbility(napi_env env,size_t argc,napi_value * argv)102 napi_value OnStartAbility(napi_env env, size_t argc, napi_value *argv)
103 {
104 HILOG_INFO("OnStartAbility is called.");
105 if (argc != ARGC_ONE && argc != ARGC_TWO && argc != ARGC_THREE) {
106 HILOG_ERROR("Not enough params!");
107 return CreateJsUndefined(env);
108 }
109 decltype(argc) unwrapArgc = 0;
110 AAFwk::Want want;
111 OHOS::AppExecFwk::UnwrapWant(env, argv[INDEX_ZERO], want);
112 HILOG_INFO("%{public}s bundlename:%{public}s abilityname:%{public}s", __func__, want.GetBundle().c_str(),
113 want.GetElement().GetAbilityName().c_str());
114 unwrapArgc++;
115 AAFwk::StartOptions startOptions;
116 napi_valuetype valueType = napi_undefined;
117 napi_typeof(env, argv[INDEX_ONE], &valueType);
118 if (argc > ARGC_ONE && valueType == napi_object) {
119 HILOG_INFO("OnStartAbility start options is used.");
120 AppExecFwk::UnwrapStartOptions(env, argv[INDEX_ONE], startOptions);
121 unwrapArgc++;
122 }
123 napi_value lastParam = (argc > unwrapArgc) ? argv[unwrapArgc] : nullptr;
124 napi_value result = nullptr;
125 std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
126 auto asyncTask = [weak = context_, want, startOptions, unwrapArgc, env, task = napiAsyncTask.get()]() {
127 auto context = weak.lock();
128 if (!context) {
129 HILOG_WARN("context is released");
130 task->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "Context is released"));
131 delete task;
132 return;
133 }
134 ErrCode errcode = ERR_OK;
135 (unwrapArgc == 1) ? errcode = context->StartAbility(want)
136 : errcode = context->StartAbility(want, startOptions);
137 if (errcode == 0) {
138 task->Resolve(env, CreateJsUndefined(env));
139 } else {
140 task->Reject(env, CreateJsError(env, errcode, "Start Ability failed!"));
141 }
142 delete task;
143 };
144 if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_immediate)) {
145 napiAsyncTask->Reject(
146 env, CreateJsErrorByNativeErr(
147 env, static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INNER), "send event failed!"));
148 } else {
149 napiAsyncTask.release();
150 }
151 return result;
152 }
153
OnStartAbilityWithAccount(napi_env env,size_t argc,napi_value * argv)154 napi_value OnStartAbilityWithAccount(napi_env env, size_t argc, napi_value *argv)
155 {
156 if (argc != ARGC_TWO && argc != ARGC_THREE && argc != ARGC_FOUR) {
157 return CreateJsUndefined(env);
158 }
159 decltype(argc) unwrapArgc = 0;
160 AAFwk::Want want;
161 OHOS::AppExecFwk::UnwrapWant(env, argv[INDEX_ZERO], want);
162 unwrapArgc++;
163 int32_t accountId = 0;
164 if (!OHOS::AppExecFwk::UnwrapInt32FromJS2(env, argv[INDEX_ONE], accountId)) {
165 return CreateJsUndefined(env);
166 }
167 unwrapArgc++;
168 AAFwk::StartOptions startOptions;
169 napi_valuetype valueType = napi_undefined;
170 napi_typeof(env, argv[INDEX_ONE], &valueType);
171 if (argc > ARGC_TWO && valueType == napi_object) {
172 AppExecFwk::UnwrapStartOptions(env, argv[INDEX_TWO], startOptions);
173 unwrapArgc++;
174 }
175 napi_value lastParam = (argc == unwrapArgc) ? nullptr : argv[unwrapArgc];
176 napi_value result = nullptr;
177 std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
178 auto asyncTask = [weak = context_, want, accountId, startOptions, unwrapArgc, env,
179 task = napiAsyncTask.get()]() {
180 auto context = weak.lock();
181 if (!context) {
182 task->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "Context is released"));
183 delete task;
184 return;
185 }
186 ErrCode errcode = ERR_OK;
187 (unwrapArgc == ARGC_TWO) ? errcode = context->StartAbilityWithAccount(want, accountId)
188 : errcode = context->StartAbilityWithAccount(want, accountId, startOptions);
189 if (errcode == 0) {
190 task->Resolve(env, CreateJsUndefined(env));
191 } else {
192 task->Reject(env, CreateJsError(env, errcode, "Start Ability failed!"));
193 }
194 delete task;
195 };
196 if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_immediate)) {
197 napiAsyncTask->Reject(
198 env, CreateJsErrorByNativeErr(
199 env, static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INNER), "send event failed!"));
200 } else {
201 napiAsyncTask.release();
202 }
203 return result;
204 }
205
OnTerminateAbility(napi_env env,size_t argc,napi_value * argv)206 napi_value OnTerminateAbility(napi_env env, size_t argc, napi_value *argv)
207 {
208 HILOG_INFO("OnTerminateAbility is called.");
209 // only support one or zero params
210 if (argc != ARGC_ZERO && argc != ARGC_ONE) {
211 HILOG_ERROR("Not enough params!");
212 return CreateJsUndefined(env);
213 }
214
215 napi_value lastParam = (argc == ARGC_ZERO) ? nullptr : argv[INDEX_ZERO];
216 napi_value result = nullptr;
217 std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
218 auto asyncTask = [weak = context_, env, task = napiAsyncTask.get()]() {
219 HILOG_INFO("TerminateAbility begin.");
220 auto context = weak.lock();
221 if (!context) {
222 HILOG_WARN("context is released");
223 task->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "Context is released"));
224 delete task;
225 return;
226 }
227 auto errcode = context->TerminateAbility();
228 if (errcode == 0) {
229 task->Resolve(env, CreateJsUndefined(env));
230 } else {
231 task->Reject(env, CreateJsError(env, errcode, "Terminate Ability failed!"));
232 }
233 delete task;
234 };
235 if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_immediate)) {
236 napiAsyncTask->Reject(
237 env, CreateJsErrorByNativeErr(
238 env, static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INNER), "send event failed!"));
239 } else {
240 napiAsyncTask.release();
241 }
242 return result;
243 }
244
OnConnectAbility(napi_env env,size_t argc,napi_value * argv)245 napi_value OnConnectAbility(napi_env env, size_t argc, napi_value *argv)
246 {
247 HILOG_INFO("OnConnectAbility is called.");
248 // only support two params
249 if (argc != ARGC_TWO) {
250 HILOG_ERROR("Not enough params!");
251 return CreateJsUndefined(env);
252 }
253
254 // unwrap want
255 AAFwk::Want want;
256 OHOS::AppExecFwk::UnwrapWant(env, argv[INDEX_ZERO], want);
257 HILOG_INFO("%{public}s bundlename:%{public}s abilityname:%{public}s", __func__, want.GetBundle().c_str(),
258 want.GetElement().GetAbilityName().c_str());
259 // unwarp connection
260 sptr<JSWallpaperExtensionConnection> connection = new JSWallpaperExtensionConnection(env);
261 int64_t connectId = GetConnectId(argv, want, connection);
262
263 napi_value result = nullptr;
264 std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, nullptr, &result);
265 auto asyncTask = [weak = context_, want, connection, connectId, env, task = napiAsyncTask.get()]() {
266 HILOG_INFO("OnConnectAbility begin.");
267 auto context = weak.lock();
268 if (!context) {
269 HILOG_WARN("context is released");
270 task->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "Context is released"));
271 delete task;
272 return;
273 }
274 if (!context->ConnectAbility(want, connection)) {
275 connection->CallJsFailed(ERROR_CODE_ONE);
276 }
277 task->Resolve(env, CreateJsUndefined(env));
278 delete task;
279 };
280 if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_immediate)) {
281 napiAsyncTask->Reject(
282 env, CreateJsErrorByNativeErr(
283 env, static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INNER), "send event failed!"));
284 } else {
285 napiAsyncTask.release();
286 }
287 napi_value connectResult = nullptr;
288 napi_create_int64(env, connectId, &connectResult);
289 return connectResult;
290 }
291
OnConnectAbilityWithAccount(napi_env env,size_t argc,napi_value * argv)292 napi_value OnConnectAbilityWithAccount(napi_env env, size_t argc, napi_value *argv)
293 {
294 HILOG_INFO("OnConnectAbilityWithAccount is called.");
295 if (argc != ARGC_THREE) {
296 HILOG_ERROR("Not enough params!");
297 return CreateJsUndefined(env);
298 }
299 AAFwk::Want want;
300 OHOS::AppExecFwk::UnwrapWant(env, argv[INDEX_ZERO], want);
301 HILOG_INFO("%{public}s bundlename:%{public}s abilityname:%{public}s", __func__, want.GetBundle().c_str(),
302 want.GetElement().GetAbilityName().c_str());
303 int32_t accountId = 0;
304 if (!OHOS::AppExecFwk::UnwrapInt32FromJS2(env, argv[INDEX_ONE], accountId)) {
305 HILOG_ERROR("%{public}s called, the second parameter is invalid.", __func__);
306 return CreateJsUndefined(env);
307 }
308 sptr<JSWallpaperExtensionConnection> connection = new JSWallpaperExtensionConnection(env);
309 int64_t connectId = GetConnectId(argv, want, connection);
310 napi_value result = nullptr;
311 std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, nullptr, &result);
312 auto asyncTask = [weak = context_, want, accountId, connection, connectId, env, task = napiAsyncTask.get()]() {
313 HILOG_INFO("OnConnectAbilityWithAccount begin.");
314 auto context = weak.lock();
315 if (!context) {
316 HILOG_WARN("context is released");
317 task->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "Context is released"));
318 delete task;
319 return;
320 }
321 if (!context->ConnectAbilityWithAccount(want, accountId, connection)) {
322 connection->CallJsFailed(ERROR_CODE_ONE);
323 }
324 task->Resolve(env, CreateJsUndefined(env));
325 delete task;
326 };
327 if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_immediate)) {
328 napiAsyncTask->Reject(
329 env, CreateJsErrorByNativeErr(
330 env, static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INNER), "send event failed!"));
331 } else {
332 napiAsyncTask.release();
333 }
334 napi_value connectResult = nullptr;
335 napi_create_int64(env, connectId, &connectResult);
336 return connectResult;
337 }
338
GetConnectId(const napi_value * argv,const AAFwk::Want & want,const sptr<JSWallpaperExtensionConnection> & connection)339 static int64_t GetConnectId(
340 const napi_value *argv, const AAFwk::Want &want, const sptr<JSWallpaperExtensionConnection> &connection)
341 {
342 connection->SetJsConnectionObject(argv[1]);
343 int64_t connectId = g_serialNumber;
344 ConnecttionKey key;
345 key.id = g_serialNumber;
346 key.want = want;
347 {
348 std::lock_guard<std::mutex> lock(g_connectMapMtx);
349 connects_.emplace(key, connection);
350 }
351 if (g_serialNumber < INT64_MAX) {
352 g_serialNumber++;
353 } else {
354 g_serialNumber = 0;
355 }
356 HILOG_INFO("%{public}s not find connection, make new one.", __func__);
357 return connectId;
358 }
359
OnDisconnectAbility(napi_env env,size_t argc,napi_value * argv)360 napi_value OnDisconnectAbility(napi_env env, size_t argc, napi_value *argv)
361 {
362 if (argc != ARGC_ONE && argc != ARGC_TWO) {
363 return CreateJsUndefined(env);
364 }
365 AAFwk::Want want;
366 int64_t connectId = -1;
367 sptr<JSWallpaperExtensionConnection> connection = nullptr;
368 napi_get_value_int64(env, reinterpret_cast<napi_value>(argv[INDEX_ZERO]), &connectId);
369 {
370 std::lock_guard<std::mutex> lock(g_connectMapMtx);
371 auto item = std::find_if(connects_.begin(), connects_.end(),
372 [&connectId](const std::map<ConnecttionKey, sptr<JSWallpaperExtensionConnection>>::value_type &obj) {
373 return connectId == obj.first.id;
374 });
375 if (item == connects_.end()) {
376 HILOG_INFO("%{public}s not find conn exist.", __func__);
377 } else {
378 want = item->first.want;
379 connection = item->second;
380 }
381 }
382 napi_value lastParam = (argc == ARGC_ONE) ? nullptr : argv[INDEX_ONE];
383 napi_value result = nullptr;
384 std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
385 auto asyncTask = [weak = context_, want, connection, env, task = napiAsyncTask.get()]() {
386 auto context = weak.lock();
387 if (!context) {
388 task->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "Context is released"));
389 delete task;
390 return;
391 }
392 if (connection == nullptr) {
393 task->Reject(env, CreateJsError(env, ERROR_CODE_TWO, "not found connection."));
394 delete task;
395 return;
396 }
397 auto errcode = context->DisconnectAbility(want, connection);
398 errcode == 0 ? task->Resolve(env, CreateJsUndefined(env))
399 : task->Reject(env, CreateJsError(env, errcode, "Disconnect Ability failed!"));
400 delete task;
401 };
402 if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_immediate)) {
403 napiAsyncTask->Reject(
404 env, CreateJsErrorByNativeErr(
405 env, static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INNER), "send event failed!"));
406 } else {
407 napiAsyncTask.release();
408 }
409 return result;
410 }
411 };
412 } // namespace
413
CreateJsMetadata(napi_env env,const AppExecFwk::Metadata & info)414 napi_value CreateJsMetadata(napi_env env, const AppExecFwk::Metadata &info)
415 {
416 HILOG_INFO("CreateJsMetadata.");
417 napi_value objValue = nullptr;
418 napi_create_object(env, &objValue);
419
420 napi_set_named_property(env, objValue, "name", CreateJsValue(env, info.name));
421 napi_set_named_property(env, objValue, "value", CreateJsValue(env, info.value));
422 napi_set_named_property(env, objValue, "resource", CreateJsValue(env, info.resource));
423 return objValue;
424 }
425
CreateJsMetadataArray(napi_env env,const std::vector<AppExecFwk::Metadata> & info)426 napi_value CreateJsMetadataArray(napi_env env, const std::vector<AppExecFwk::Metadata> &info)
427 {
428 HILOG_INFO("CreateJsMetadataArray.");
429 napi_value arrayValue = nullptr;
430 napi_create_array_with_length(env, info.size(), &arrayValue);
431 uint32_t index = 0;
432 for (const auto &item : info) {
433 napi_set_element(env, arrayValue, index++, CreateJsMetadata(env, item));
434 }
435 return arrayValue;
436 }
437
CreateJsExtensionAbilityInfo(napi_env env,const AppExecFwk::ExtensionAbilityInfo & info)438 napi_value CreateJsExtensionAbilityInfo(napi_env env, const AppExecFwk::ExtensionAbilityInfo &info)
439 {
440 HILOG_INFO("CreateJsExtensionAbilityInfo.");
441 napi_value objValue = nullptr;
442 napi_create_object(env, &objValue);
443
444 napi_set_named_property(env, objValue, "bundleName", CreateJsValue(env, info.bundleName));
445 napi_set_named_property(env, objValue, "moduleName", CreateJsValue(env, info.moduleName));
446 napi_set_named_property(env, objValue, "name", CreateJsValue(env, info.name));
447 napi_set_named_property(env, objValue, "labelId", CreateJsValue(env, info.labelId));
448 napi_set_named_property(env, objValue, "descriptionId", CreateJsValue(env, info.descriptionId));
449 napi_set_named_property(env, objValue, "iconId", CreateJsValue(env, info.iconId));
450 napi_set_named_property(env, objValue, "isVisible", CreateJsValue(env, info.visible));
451 napi_set_named_property(env, objValue, "extensionAbilityType", CreateJsValue(env, info.type));
452
453 napi_value permissionArrayValue = nullptr;
454 napi_create_array_with_length(env, info.permissions.size(), &permissionArrayValue);
455
456 if (permissionArrayValue != nullptr) {
457 int32_t index = 0;
458 for (auto permission : info.permissions) {
459 napi_set_element(env, permissionArrayValue, index++, CreateJsValue(env, permission));
460 }
461 }
462 napi_set_named_property(env, objValue, "permissions", permissionArrayValue);
463 napi_set_named_property(env, objValue, "applicationInfo", CreateJsApplicationInfo(env, info.applicationInfo));
464 napi_set_named_property(env, objValue, "metadata", CreateJsMetadataArray(env, info.metadata));
465 napi_set_named_property(env, objValue, "enabled", CreateJsValue(env, info.enabled));
466 napi_set_named_property(env, objValue, "readPermission", CreateJsValue(env, info.readPermission));
467 napi_set_named_property(env, objValue, "writePermission", CreateJsValue(env, info.writePermission));
468 return objValue;
469 }
470
CreateJsWallpaperExtensionContext(napi_env env,std::shared_ptr<WallpaperExtensionContext> context)471 napi_value CreateJsWallpaperExtensionContext(napi_env env, std::shared_ptr<WallpaperExtensionContext> context)
472 {
473 HILOG_INFO("CreateJsWallpaperExtensionContext begin.");
474 napi_value objValue = CreateJsExtensionContext(env, context);
475
476 std::unique_ptr<JsWallpaperExtensionContext> jsContext = std::make_unique<JsWallpaperExtensionContext>(context);
477 napi_wrap(env, objValue, jsContext.release(), JsWallpaperExtensionContext::Finalizer, nullptr, nullptr);
478
479 // make handler
480 handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
481
482 const char *moduleName = "JsWallpaperExtensionContext";
483 BindNativeFunction(env, objValue, "startAbility", moduleName, JsWallpaperExtensionContext::StartAbility);
484 BindNativeFunction(env, objValue, "terminateSelf", moduleName, JsWallpaperExtensionContext::TerminateAbility);
485 BindNativeFunction(env, objValue, "connectAbility", moduleName, JsWallpaperExtensionContext::ConnectAbility);
486 BindNativeFunction(env, objValue, "disconnectAbility", moduleName, JsWallpaperExtensionContext::DisconnectAbility);
487 BindNativeFunction(
488 env, objValue, "startAbilityWithAccount", moduleName, JsWallpaperExtensionContext::StartAbilityWithAccount);
489 BindNativeFunction(env, objValue, "connectAbilityWithAccount", moduleName,
490 JsWallpaperExtensionContext::ConnectAbilityWithAccount);
491
492 if (context) {
493 HILOG_INFO("Set ExtensionAbilityInfo Property.");
494 auto abilityInfo = context->GetAbilityInfo();
495 auto hapModuleInfo = context->GetHapModuleInfo();
496 if (abilityInfo && hapModuleInfo) {
497 auto isExist = [&abilityInfo](const AppExecFwk::ExtensionAbilityInfo &info) {
498 HILOG_INFO("%{public}s, %{public}s", info.bundleName.c_str(), info.name.c_str());
499 return info.bundleName == abilityInfo->bundleName && info.name == abilityInfo->name;
500 };
501 auto infoIter =
502 std::find_if(hapModuleInfo->extensionInfos.begin(), hapModuleInfo->extensionInfos.end(), isExist);
503 if (infoIter == hapModuleInfo->extensionInfos.end()) {
504 HILOG_ERROR("Get target fail!");
505 return objValue;
506 }
507 napi_set_named_property(
508 env, objValue, "extensionAbilityInfo", CreateJsExtensionAbilityInfo(env, *infoIter));
509 }
510 }
511
512 return objValue;
513 }
514
JSWallpaperExtensionConnection(napi_env env)515 JSWallpaperExtensionConnection::JSWallpaperExtensionConnection(napi_env env) : env_(env)
516 {
517 }
518
519 JSWallpaperExtensionConnection::~JSWallpaperExtensionConnection() = default;
520
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int32_t resultCode)521 void JSWallpaperExtensionConnection::OnAbilityConnectDone(
522 const AppExecFwk::ElementName &element, const sptr<IRemoteObject> &remoteObject, int32_t resultCode)
523 {
524 HILOG_INFO("OnAbilityConnectDone begin, resultCode:%{public}d", resultCode);
525 if (handler_ == nullptr) {
526 HILOG_ERROR("handler_ nullptr.");
527 return;
528 }
529 wptr<JSWallpaperExtensionConnection> connection = this;
530 auto task = [connection, element, remoteObject, resultCode]() {
531 sptr<JSWallpaperExtensionConnection> connectionSptr = connection.promote();
532 if (!connectionSptr) {
533 HILOG_ERROR("connectionSptr nullptr.");
534 return;
535 }
536 connectionSptr->HandleOnAbilityConnectDone(element, remoteObject, resultCode);
537 };
538 handler_->PostTask(task, "OnAbilityConnectDone.");
539 }
540
HandleOnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int32_t resultCode)541 void JSWallpaperExtensionConnection::HandleOnAbilityConnectDone(
542 const AppExecFwk::ElementName &element, const sptr<IRemoteObject> &remoteObject, int32_t resultCode)
543 {
544 HILOG_INFO("HandleOnAbilityConnectDone begin, resultCode:%{public}d", resultCode);
545 // wrap ElementName
546 napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(env_, element);
547
548 // wrap RemoteObject
549 HILOG_INFO("OnAbilityConnectDone begin NAPI_ohos_rpc_CreateJsRemoteObject");
550 napi_value napiRemoteObject = NAPI_ohos_rpc_CreateJsRemoteObject(env_, remoteObject);
551 napi_value argv[] = { napiElementName, napiRemoteObject };
552
553 if (jsConnectionObject_ == nullptr) {
554 HILOG_ERROR("jsConnectionObject_ nullptr.");
555 return;
556 }
557 napi_value obj = jsConnectionObject_->GetNapiValue();
558 if (obj == nullptr) {
559 HILOG_ERROR("Failed to get object!");
560 return;
561 }
562 napi_value methodOnConnect = nullptr;
563 napi_get_named_property(env_, obj, "onConnect", &methodOnConnect);
564 if (methodOnConnect == nullptr) {
565 HILOG_ERROR("Failed to get onConnect from object!");
566 return;
567 }
568 napi_value callResult = nullptr;
569 napi_call_function(env_, obj, methodOnConnect, ARGC_TWO, argv, &callResult);
570 }
571
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int32_t resultCode)572 void JSWallpaperExtensionConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int32_t resultCode)
573 {
574 HILOG_INFO("OnAbilityDisconnectDone begin, resultCode:%{public}d", resultCode);
575 if (handler_ == nullptr) {
576 HILOG_ERROR("handler_ nullptr.");
577 return;
578 }
579 wptr<JSWallpaperExtensionConnection> connection = this;
580 auto task = [connection, element, resultCode]() {
581 sptr<JSWallpaperExtensionConnection> connectionSptr = connection.promote();
582 if (!connectionSptr) {
583 HILOG_ERROR("connectionSptr nullptr. ");
584 return;
585 }
586 connectionSptr->HandleOnAbilityDisconnectDone(element, resultCode);
587 };
588 handler_->PostTask(task, "OnAbilityDisconnectDone.");
589 }
590
HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int32_t resultCode)591 void JSWallpaperExtensionConnection::HandleOnAbilityDisconnectDone(
592 const AppExecFwk::ElementName &element, int32_t resultCode)
593 {
594 HILOG_INFO("HandleOnAbilityDisconnectDone begin, resultCode:%{public}d", resultCode);
595 napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(env_, element);
596 napi_value argv[] = { napiElementName };
597 if (jsConnectionObject_ == nullptr) {
598 HILOG_ERROR("jsConnectionObject_ nullptr.");
599 return;
600 }
601 napi_value obj = jsConnectionObject_->GetNapiValue();
602 if (obj == nullptr) {
603 HILOG_ERROR("Failed to get object!");
604 return;
605 }
606
607 napi_value method = nullptr;
608 napi_get_named_property(env_, obj, "onDisconnect", &method);
609 if (method == nullptr) {
610 HILOG_ERROR("Failed to get onDisconnect from object!");
611 return;
612 }
613
614 // release connect
615 HILOG_INFO("OnAbilityDisconnectDone connects_.size:%{public}zu", connects_.size());
616 std::string bundleName = element.GetBundleName();
617 std::string abilityName = element.GetAbilityName();
618 {
619 std::lock_guard<std::mutex> lock(g_connectMapMtx);
620 auto item = std::find_if(connects_.begin(), connects_.end(),
621 [bundleName, abilityName](
622 const std::map<ConnecttionKey, sptr<JSWallpaperExtensionConnection>>::value_type &obj) {
623 return (bundleName == obj.first.want.GetBundle())
624 && (abilityName == obj.first.want.GetElement().GetAbilityName());
625 });
626 if (item != connects_.end()) {
627 // match bundlename && abilityname
628 connects_.erase(item);
629 HILOG_INFO("OnAbilityDisconnectDone erase connects_.size:%{public}zu", connects_.size());
630 }
631 }
632 napi_value callResult = nullptr;
633 napi_call_function(env_, obj, method, ARGC_TWO, argv, &callResult);
634 }
635
SetJsConnectionObject(napi_value jsConnectionObject)636 void JSWallpaperExtensionConnection::SetJsConnectionObject(napi_value jsConnectionObject)
637 {
638 napi_ref value = nullptr;
639 napi_create_reference(env_, jsConnectionObject, 1, &value);
640 jsConnectionObject_ = std::unique_ptr<NativeReference>(reinterpret_cast<NativeReference *>(value));
641 }
642
CallJsFailed(int32_t errorCode)643 void JSWallpaperExtensionConnection::CallJsFailed(int32_t errorCode)
644 {
645 HILOG_INFO("CallJsFailed begin.");
646 if (jsConnectionObject_ == nullptr) {
647 HILOG_ERROR("jsConnectionObject_ nullptr.");
648 return;
649 }
650 napi_value obj = jsConnectionObject_->GetNapiValue();
651 if (obj == nullptr) {
652 HILOG_ERROR("Failed to get object!");
653 return;
654 }
655
656 napi_value method = nullptr;
657 napi_get_named_property(env_, obj, "onFailed", &method);
658 if (method == nullptr) {
659 HILOG_ERROR("Failed to get onFailed from object!");
660 return;
661 }
662 napi_value result = nullptr;
663 napi_create_int32(env_, errorCode, &result);
664 napi_value argv[] = { result };
665
666 napi_value callResult = nullptr;
667 napi_call_function(env_, obj, method, ARGC_ONE, argv, &callResult);
668 }
669 } // namespace AbilityRuntime
670 } // namespace OHOS