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 }
378 want = item->first.want;
379 connection = item->second;
380 }
381 napi_value lastParam = (argc == ARGC_ONE) ? nullptr : argv[INDEX_ONE];
382 napi_value result = nullptr;
383 std::unique_ptr<NapiAsyncTask> napiAsyncTask = CreateEmptyAsyncTask(env, lastParam, &result);
384 auto asyncTask = [weak = context_, want, connection, env, task = napiAsyncTask.get()]() {
385 auto context = weak.lock();
386 if (!context) {
387 task->Reject(env, CreateJsError(env, ERROR_CODE_ONE, "Context is released"));
388 delete task;
389 return;
390 }
391 if (connection == nullptr) {
392 task->Reject(env, CreateJsError(env, ERROR_CODE_TWO, "not found connection."));
393 delete task;
394 return;
395 }
396 auto errcode = context->DisconnectAbility(want, connection);
397 errcode == 0 ? task->Resolve(env, CreateJsUndefined(env))
398 : task->Reject(env, CreateJsError(env, errcode, "Disconnect Ability failed!"));
399 delete task;
400 };
401 if (napi_status::napi_ok != napi_send_event(env, asyncTask, napi_eprio_immediate)) {
402 napiAsyncTask->Reject(
403 env, CreateJsErrorByNativeErr(
404 env, static_cast<int32_t>(AbilityErrorCode::ERROR_CODE_INNER), "send event failed!"));
405 } else {
406 napiAsyncTask.release();
407 }
408 return result;
409 }
410 };
411 } // namespace
412
CreateJsMetadata(napi_env env,const AppExecFwk::Metadata & info)413 napi_value CreateJsMetadata(napi_env env, const AppExecFwk::Metadata &info)
414 {
415 HILOG_INFO("CreateJsMetadata.");
416 napi_value objValue = nullptr;
417 napi_create_object(env, &objValue);
418
419 napi_set_named_property(env, objValue, "name", CreateJsValue(env, info.name));
420 napi_set_named_property(env, objValue, "value", CreateJsValue(env, info.value));
421 napi_set_named_property(env, objValue, "resource", CreateJsValue(env, info.resource));
422 return objValue;
423 }
424
CreateJsMetadataArray(napi_env env,const std::vector<AppExecFwk::Metadata> & info)425 napi_value CreateJsMetadataArray(napi_env env, const std::vector<AppExecFwk::Metadata> &info)
426 {
427 HILOG_INFO("CreateJsMetadataArray.");
428 napi_value arrayValue = nullptr;
429 napi_create_array_with_length(env, info.size(), &arrayValue);
430 uint32_t index = 0;
431 for (const auto &item : info) {
432 napi_set_element(env, arrayValue, index++, CreateJsMetadata(env, item));
433 }
434 return arrayValue;
435 }
436
CreateJsExtensionAbilityInfo(napi_env env,const AppExecFwk::ExtensionAbilityInfo & info)437 napi_value CreateJsExtensionAbilityInfo(napi_env env, const AppExecFwk::ExtensionAbilityInfo &info)
438 {
439 HILOG_INFO("CreateJsExtensionAbilityInfo.");
440 napi_value objValue = nullptr;
441 napi_create_object(env, &objValue);
442
443 napi_set_named_property(env, objValue, "bundleName", CreateJsValue(env, info.bundleName));
444 napi_set_named_property(env, objValue, "moduleName", CreateJsValue(env, info.moduleName));
445 napi_set_named_property(env, objValue, "name", CreateJsValue(env, info.name));
446 napi_set_named_property(env, objValue, "labelId", CreateJsValue(env, info.labelId));
447 napi_set_named_property(env, objValue, "descriptionId", CreateJsValue(env, info.descriptionId));
448 napi_set_named_property(env, objValue, "iconId", CreateJsValue(env, info.iconId));
449 napi_set_named_property(env, objValue, "isVisible", CreateJsValue(env, info.visible));
450 napi_set_named_property(env, objValue, "extensionAbilityType", CreateJsValue(env, info.type));
451
452 napi_value permissionArrayValue = nullptr;
453 napi_create_array_with_length(env, info.permissions.size(), &permissionArrayValue);
454
455 if (permissionArrayValue != nullptr) {
456 int32_t index = 0;
457 for (auto permission : info.permissions) {
458 napi_set_element(env, permissionArrayValue, index++, CreateJsValue(env, permission));
459 }
460 }
461 napi_set_named_property(env, objValue, "permissions", permissionArrayValue);
462 napi_set_named_property(env, objValue, "applicationInfo", CreateJsApplicationInfo(env, info.applicationInfo));
463 napi_set_named_property(env, objValue, "metadata", CreateJsMetadataArray(env, info.metadata));
464 napi_set_named_property(env, objValue, "enabled", CreateJsValue(env, info.enabled));
465 napi_set_named_property(env, objValue, "readPermission", CreateJsValue(env, info.readPermission));
466 napi_set_named_property(env, objValue, "writePermission", CreateJsValue(env, info.writePermission));
467 return objValue;
468 }
469
CreateJsWallpaperExtensionContext(napi_env env,std::shared_ptr<WallpaperExtensionContext> context)470 napi_value CreateJsWallpaperExtensionContext(napi_env env, std::shared_ptr<WallpaperExtensionContext> context)
471 {
472 HILOG_INFO("CreateJsWallpaperExtensionContext begin.");
473 napi_value objValue = CreateJsExtensionContext(env, context);
474
475 std::unique_ptr<JsWallpaperExtensionContext> jsContext = std::make_unique<JsWallpaperExtensionContext>(context);
476 napi_wrap(env, objValue, jsContext.release(), JsWallpaperExtensionContext::Finalizer, nullptr, nullptr);
477
478 // make handler
479 handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
480
481 const char *moduleName = "JsWallpaperExtensionContext";
482 BindNativeFunction(env, objValue, "startAbility", moduleName, JsWallpaperExtensionContext::StartAbility);
483 BindNativeFunction(env, objValue, "terminateSelf", moduleName, JsWallpaperExtensionContext::TerminateAbility);
484 BindNativeFunction(env, objValue, "connectAbility", moduleName, JsWallpaperExtensionContext::ConnectAbility);
485 BindNativeFunction(env, objValue, "disconnectAbility", moduleName, JsWallpaperExtensionContext::DisconnectAbility);
486 BindNativeFunction(
487 env, objValue, "startAbilityWithAccount", moduleName, JsWallpaperExtensionContext::StartAbilityWithAccount);
488 BindNativeFunction(env, objValue, "connectAbilityWithAccount", moduleName,
489 JsWallpaperExtensionContext::ConnectAbilityWithAccount);
490
491 if (context) {
492 HILOG_INFO("Set ExtensionAbilityInfo Property.");
493 auto abilityInfo = context->GetAbilityInfo();
494 auto hapModuleInfo = context->GetHapModuleInfo();
495 if (abilityInfo && hapModuleInfo) {
496 auto isExist = [&abilityInfo](const AppExecFwk::ExtensionAbilityInfo &info) {
497 HILOG_INFO("%{public}s, %{public}s", info.bundleName.c_str(), info.name.c_str());
498 return info.bundleName == abilityInfo->bundleName && info.name == abilityInfo->name;
499 };
500 auto infoIter =
501 std::find_if(hapModuleInfo->extensionInfos.begin(), hapModuleInfo->extensionInfos.end(), isExist);
502 if (infoIter == hapModuleInfo->extensionInfos.end()) {
503 HILOG_ERROR("Get target fail!");
504 return objValue;
505 }
506 napi_set_named_property(
507 env, objValue, "extensionAbilityInfo", CreateJsExtensionAbilityInfo(env, *infoIter));
508 }
509 }
510
511 return objValue;
512 }
513
JSWallpaperExtensionConnection(napi_env env)514 JSWallpaperExtensionConnection::JSWallpaperExtensionConnection(napi_env env) : env_(env)
515 {
516 }
517
518 JSWallpaperExtensionConnection::~JSWallpaperExtensionConnection() = default;
519
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int32_t resultCode)520 void JSWallpaperExtensionConnection::OnAbilityConnectDone(
521 const AppExecFwk::ElementName &element, const sptr<IRemoteObject> &remoteObject, int32_t resultCode)
522 {
523 HILOG_INFO("OnAbilityConnectDone begin, resultCode:%{public}d", resultCode);
524 if (handler_ == nullptr) {
525 HILOG_ERROR("handler_ nullptr.");
526 return;
527 }
528 wptr<JSWallpaperExtensionConnection> connection = this;
529 auto task = [connection, element, remoteObject, resultCode]() {
530 sptr<JSWallpaperExtensionConnection> connectionSptr = connection.promote();
531 if (!connectionSptr) {
532 HILOG_ERROR("connectionSptr nullptr.");
533 return;
534 }
535 connectionSptr->HandleOnAbilityConnectDone(element, remoteObject, resultCode);
536 };
537 handler_->PostTask(task, "OnAbilityConnectDone.");
538 }
539
HandleOnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int32_t resultCode)540 void JSWallpaperExtensionConnection::HandleOnAbilityConnectDone(
541 const AppExecFwk::ElementName &element, const sptr<IRemoteObject> &remoteObject, int32_t resultCode)
542 {
543 HILOG_INFO("HandleOnAbilityConnectDone begin, resultCode:%{public}d", resultCode);
544 // wrap ElementName
545 napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(env_, element);
546
547 // wrap RemoteObject
548 HILOG_INFO("OnAbilityConnectDone begin NAPI_ohos_rpc_CreateJsRemoteObject");
549 napi_value napiRemoteObject = NAPI_ohos_rpc_CreateJsRemoteObject(env_, remoteObject);
550 napi_value argv[] = { napiElementName, napiRemoteObject };
551
552 if (jsConnectionObject_ == nullptr) {
553 HILOG_ERROR("jsConnectionObject_ nullptr.");
554 return;
555 }
556 napi_value obj = jsConnectionObject_->GetNapiValue();
557 if (obj == nullptr) {
558 HILOG_ERROR("Failed to get object!");
559 return;
560 }
561 napi_value methodOnConnect = nullptr;
562 napi_get_named_property(env_, obj, "onConnect", &methodOnConnect);
563 if (methodOnConnect == nullptr) {
564 HILOG_ERROR("Failed to get onConnect from object!");
565 return;
566 }
567 napi_value callResult = nullptr;
568 napi_call_function(env_, obj, methodOnConnect, ARGC_TWO, argv, &callResult);
569 }
570
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int32_t resultCode)571 void JSWallpaperExtensionConnection::OnAbilityDisconnectDone(const AppExecFwk::ElementName &element, int32_t resultCode)
572 {
573 HILOG_INFO("OnAbilityDisconnectDone begin, resultCode:%{public}d", resultCode);
574 if (handler_ == nullptr) {
575 HILOG_ERROR("handler_ nullptr.");
576 return;
577 }
578 wptr<JSWallpaperExtensionConnection> connection = this;
579 auto task = [connection, element, resultCode]() {
580 sptr<JSWallpaperExtensionConnection> connectionSptr = connection.promote();
581 if (!connectionSptr) {
582 HILOG_ERROR("connectionSptr nullptr. ");
583 return;
584 }
585 connectionSptr->HandleOnAbilityDisconnectDone(element, resultCode);
586 };
587 handler_->PostTask(task, "OnAbilityDisconnectDone.");
588 }
589
HandleOnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int32_t resultCode)590 void JSWallpaperExtensionConnection::HandleOnAbilityDisconnectDone(
591 const AppExecFwk::ElementName &element, int32_t resultCode)
592 {
593 HILOG_INFO("HandleOnAbilityDisconnectDone begin, resultCode:%{public}d", resultCode);
594 napi_value napiElementName = OHOS::AppExecFwk::WrapElementName(env_, element);
595 napi_value argv[] = { napiElementName };
596 if (jsConnectionObject_ == nullptr) {
597 HILOG_ERROR("jsConnectionObject_ nullptr.");
598 return;
599 }
600 napi_value obj = jsConnectionObject_->GetNapiValue();
601 if (obj == nullptr) {
602 HILOG_ERROR("Failed to get object!");
603 return;
604 }
605
606 napi_value method = nullptr;
607 napi_get_named_property(env_, obj, "onDisconnect", &method);
608 if (method == nullptr) {
609 HILOG_ERROR("Failed to get onDisconnect from object!");
610 return;
611 }
612
613 // release connect
614 HILOG_INFO("OnAbilityDisconnectDone connects_.size:%{public}zu", connects_.size());
615 std::string bundleName = element.GetBundleName();
616 std::string abilityName = element.GetAbilityName();
617 {
618 std::lock_guard<std::mutex> lock(g_connectMapMtx);
619 auto item = std::find_if(connects_.begin(), connects_.end(),
620 [bundleName, abilityName](
621 const std::map<ConnecttionKey, sptr<JSWallpaperExtensionConnection>>::value_type &obj) {
622 return (bundleName == obj.first.want.GetBundle())
623 && (abilityName == obj.first.want.GetElement().GetAbilityName());
624 });
625 if (item != connects_.end()) {
626 // match bundlename && abilityname
627 connects_.erase(item);
628 HILOG_INFO("OnAbilityDisconnectDone erase connects_.size:%{public}zu", connects_.size());
629 }
630 }
631 napi_value callResult = nullptr;
632 napi_call_function(env_, obj, method, ARGC_TWO, argv, &callResult);
633 }
634
SetJsConnectionObject(napi_value jsConnectionObject)635 void JSWallpaperExtensionConnection::SetJsConnectionObject(napi_value jsConnectionObject)
636 {
637 napi_ref value = nullptr;
638 napi_create_reference(env_, jsConnectionObject, 1, &value);
639 jsConnectionObject_ = std::unique_ptr<NativeReference>(reinterpret_cast<NativeReference *>(value));
640 }
641
CallJsFailed(int32_t errorCode)642 void JSWallpaperExtensionConnection::CallJsFailed(int32_t errorCode)
643 {
644 HILOG_INFO("CallJsFailed begin.");
645 if (jsConnectionObject_ == nullptr) {
646 HILOG_ERROR("jsConnectionObject_ nullptr.");
647 return;
648 }
649 napi_value obj = jsConnectionObject_->GetNapiValue();
650 if (obj == nullptr) {
651 HILOG_ERROR("Failed to get object!");
652 return;
653 }
654
655 napi_value method = nullptr;
656 napi_get_named_property(env_, obj, "onFailed", &method);
657 if (method == nullptr) {
658 HILOG_ERROR("Failed to get onFailed from object!");
659 return;
660 }
661 napi_value result = nullptr;
662 napi_create_int32(env_, errorCode, &result);
663 napi_value argv[] = { result };
664
665 napi_value callResult = nullptr;
666 napi_call_function(env_, obj, method, ARGC_ONE, argv, &callResult);
667 }
668 } // namespace AbilityRuntime
669 } // namespace OHOS