• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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