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