1 /*
2  * Copyright (c) 2022 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 "js_print_extension_context.h"
17 
18 #include "js_data_struct_converter.h"
19 #include "js_extension_context.h"
20 #include "js_print_extension_connection.h"
21 #include "js_runtime.h"
22 #include "js_runtime_utils.h"
23 #include "napi/native_api.h"
24 #include "napi_common_start_options.h"
25 #include "napi_common_util.h"
26 #include "napi_common_want.h"
27 #include "napi_print_utils.h"
28 #include "napi_remote_object.h"
29 #include "print_log.h"
30 #include "start_options.h"
31 #include <shared_mutex>
32 
33 using namespace OHOS::Print;
34 using noneType = void*;
35 
36 namespace OHOS {
37 namespace AbilityRuntime {
38 static constexpr int32_t E_PRINT_INVALID_CONTEXT = 1;
39 static constexpr int32_t E_PRINT_INVALID_CONNECTION = 2;
40 
41 class JsPrintExtensionContext final {
42 public:
JsPrintExtensionContext(const std::shared_ptr<PrintExtensionContext> & context)43     explicit JsPrintExtensionContext(const std::shared_ptr<PrintExtensionContext>& context) : context_(context) {}
44     ~JsPrintExtensionContext() = default;
45 
Finalizer(napi_env engine,noneType data,noneType hint)46     static void Finalizer(napi_env engine, noneType data, noneType hint)
47     {
48         PRINT_HILOGD("JsAbilityContext::Finalizer is called");
49         std::unique_ptr<JsPrintExtensionContext>(static_cast<JsPrintExtensionContext*>(data));
50     }
51 
StartAbility(napi_env engine,napi_callback_info info)52     static napi_value StartAbility(napi_env engine, napi_callback_info info)
53     {
54         JsPrintExtensionContext* me = CheckParamsAndGetThis<JsPrintExtensionContext>(engine, info);
55         return (me != nullptr) ? me->OnStartAbility(engine, info) : nullptr;
56     }
57 
StartAbilityWithAccount(napi_env engine,napi_callback_info info)58     static napi_value StartAbilityWithAccount(napi_env engine, napi_callback_info info)
59     {
60         JsPrintExtensionContext* me = CheckParamsAndGetThis<JsPrintExtensionContext>(engine, info);
61         return (me != nullptr) ? me->OnStartAbilityWithAccount(engine, info) : nullptr;
62     }
63 
ConnectAbilityWithAccount(napi_env engine,napi_callback_info info)64     static napi_value ConnectAbilityWithAccount(napi_env engine, napi_callback_info info)
65     {
66         JsPrintExtensionContext* me = CheckParamsAndGetThis<JsPrintExtensionContext>(engine, info);
67         return (me != nullptr) ? me->OnConnectAbilityWithAccount(engine, info) : nullptr;
68     }
69 
TerminateAbility(napi_env engine,napi_callback_info info)70     static napi_value TerminateAbility(napi_env engine, napi_callback_info info)
71     {
72         JsPrintExtensionContext* me = CheckParamsAndGetThis<JsPrintExtensionContext>(engine, info);
73         return (me != nullptr) ? me->OnTerminateAbility(engine, info) : nullptr;
74     }
75 
ConnectAbility(napi_env engine,napi_callback_info info)76     static napi_value ConnectAbility(napi_env engine, napi_callback_info info)
77     {
78         JsPrintExtensionContext* me = CheckParamsAndGetThis<JsPrintExtensionContext>(engine, info);
79         return (me != nullptr) ? me->OnConnectAbility(engine, info) : nullptr;
80     }
81 
DisconnectAbility(napi_env engine,napi_callback_info info)82     static napi_value DisconnectAbility(napi_env engine, napi_callback_info info)
83     {
84         JsPrintExtensionContext* me = CheckParamsAndGetThis<JsPrintExtensionContext>(engine, info);
85         return (me != nullptr) ? me->OnDisconnectAbility(engine, info) : nullptr;
86     }
87 
88 private:
89     std::weak_ptr<PrintExtensionContext> context_;
90     std::shared_timed_mutex managersMutex_;
91 
GetUndefinedValue(napi_env & engine)92     napi_value GetUndefinedValue(napi_env &engine)
93     {
94         PRINT_HILOGE("params count or value is error");
95         napi_value undefineResult = nullptr;
96         napi_get_undefined(engine, &undefineResult);
97         return undefineResult;
98     }
99 
GetNapiValueType(napi_env & engine,napi_value & argv)100     napi_valuetype GetNapiValueType(napi_env &engine, napi_value &argv)
101     {
102         napi_valuetype valueType = napi_undefined;
103         napi_typeof(engine, argv, &valueType);
104         return valueType;
105     }
106 
OnStartAbility(napi_env & engine,napi_callback_info & info)107     napi_value OnStartAbility(napi_env &engine, napi_callback_info &info)
108     {
109         PRINT_HILOGD("OnStartAbility is called");
110         size_t argc = NapiPrintUtils::MAX_ARGC;
111         napi_value argv[NapiPrintUtils::MAX_ARGC] = { nullptr };
112         napi_get_cb_info(engine, info, &argc, argv, nullptr, nullptr);
113         if (argc != NapiPrintUtils::ARGC_ONE && argc != NapiPrintUtils::ARGC_TWO &&
114             argc != NapiPrintUtils::ARGC_THREE) {
115             return GetUndefinedValue(engine);
116         }
117 
118         decltype(argc) unwrapArgc = 0;
119         AAFwk::Want want;
120         OHOS::AppExecFwk::UnwrapWant(engine, argv[NapiPrintUtils::INDEX_ZERO], want);
121         PRINT_HILOGD("%{public}s bundlename:%{public}s abilityname:%{public}s", __func__, want.GetBundle().c_str(),
122             want.GetElement().GetAbilityName().c_str());
123         unwrapArgc++;
124 
125         AAFwk::StartOptions startOptions;
126         if (argc > NapiPrintUtils::ARGC_ONE && GetNapiValueType(engine, argv[1]) == napi_object) {
127             PRINT_HILOGD("OnStartAbility start options is used.");
128             AppExecFwk::UnwrapStartOptions(engine, argv[1], startOptions);
129             unwrapArgc++;
130         }
131 
132         NapiAsyncTask::CompleteCallback complete = [weak = context_, want, startOptions, unwrapArgc](
133                                                    napi_env engine, NapiAsyncTask &task, int32_t status) {
134             PRINT_HILOGD("startAbility begin");
135             auto context = weak.lock();
136             if (!context) {
137                 PRINT_HILOGW("context is released");
138                     task.Reject(engine, CreateJsError(engine, E_PRINT_INVALID_CONTEXT, "Context is released"));
139                 return;
140             }
141 
142             ErrCode errcode = ERR_OK;
143             (unwrapArgc == 1) ? errcode = context->StartAbility(want)
144                               : errcode = context->StartAbility(want, startOptions);
145             if (errcode == 0) {
146                 napi_value undefineResult = nullptr;
147                 napi_get_undefined(engine, &undefineResult);
148                 task.Resolve(engine, undefineResult);
149             } else {
150                 task.Reject(engine, CreateJsError(engine, errcode, "Start Ability failed."));
151             }
152         };
153 
154         napi_value lastParam = (argc == unwrapArgc) ? nullptr : argv[unwrapArgc];
155         napi_value result = nullptr;
156         NapiAsyncTask::Schedule("PrintExtensionContext::OnStartAbility", engine,
157             CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
158         return result;
159     }
160 
OnStartAbilityWithAccount(napi_env & engine,napi_callback_info & info)161     napi_value OnStartAbilityWithAccount(napi_env &engine, napi_callback_info &info)
162     {
163         size_t argc = NapiPrintUtils::MAX_ARGC;
164         napi_value argv[NapiPrintUtils::MAX_ARGC] = { nullptr };
165         napi_get_cb_info(engine, info, &argc, argv, nullptr, nullptr);
166         if (argc != NapiPrintUtils::ARGC_TWO && argc != NapiPrintUtils::ARGC_THREE &&
167             argc != NapiPrintUtils::ARGC_FOUR) {
168             return GetUndefinedValue(engine);
169         }
170 
171         decltype(argc) unwrapArgc = 0;
172         AAFwk::Want want;
173         OHOS::AppExecFwk::UnwrapWant(engine, argv[0], want);
174         PRINT_HILOGD("%{public}s bundlename:%{public}s abilityname:%{public}s", __func__, want.GetBundle().c_str(),
175             want.GetElement().GetAbilityName().c_str());
176         unwrapArgc++;
177 
178         int32_t accountId = 0;
179         if (!OHOS::AppExecFwk::UnwrapInt32FromJS2(engine, argv[1], accountId)) {
180             return GetUndefinedValue(engine);
181         }
182         PRINT_HILOGD("%{public}d accountId:", accountId);
183         unwrapArgc++;
184 
185         AAFwk::StartOptions startOptions;
186         if (static_cast<uint32_t>(argc) > NapiPrintUtils::INDEX_TWO &&
187             GetNapiValueType(engine, argv[NapiPrintUtils::INDEX_TWO]) == napi_object) {
188             AppExecFwk::UnwrapStartOptions(engine, argv[NapiPrintUtils::INDEX_TWO], startOptions);
189             unwrapArgc++;
190         }
191 
192         NapiAsyncTask::CompleteCallback complete = [weak = context_, want, accountId, startOptions, unwrapArgc](
193                                                    napi_env engine, NapiAsyncTask &task, int32_t status) {
194             auto context = weak.lock();
195             if (!context) {
196                 task.Reject(engine, CreateJsError(engine, E_PRINT_INVALID_CONTEXT, "Context is released"));
197                 return;
198             }
199 
200             ErrCode errcode = ERR_OK;
201             (unwrapArgc == NapiPrintUtils::ARGC_TWO) ? errcode = context->StartAbilityWithAccount(want, accountId)
202                 : errcode = context->StartAbilityWithAccount(want, accountId, startOptions);
203             if (errcode == 0) {
204                 napi_value undefineResult = nullptr;
205                 napi_get_undefined(engine, &undefineResult);
206                 task.Resolve(engine, undefineResult);
207             } else {
208                 task.Reject(engine, CreateJsError(engine, errcode, "Start Ability failed."));
209             }
210         };
211 
212         napi_value lastParam = (argc == unwrapArgc) ? nullptr : argv[unwrapArgc];
213         napi_value result = nullptr;
214         NapiAsyncTask::Schedule("PrintExtensionContext::OnStartAbilityWithAccount", engine,
215             CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
216         return result;
217     }
218 
OnTerminateAbility(napi_env & engine,napi_callback_info & info)219     napi_value OnTerminateAbility(napi_env &engine, napi_callback_info &info)
220     {
221         PRINT_HILOGD("OnTerminateAbility is called");
222         size_t argc = NapiPrintUtils::MAX_ARGC;
223         napi_value argv[NapiPrintUtils::MAX_ARGC] = { nullptr };
224         napi_get_cb_info(engine, info, &argc, argv, nullptr, nullptr);
225         if (argc != NapiPrintUtils::ARGC_ZERO && argc != NapiPrintUtils::ARGC_ONE) {
226             return GetUndefinedValue(engine);
227         }
228 
229         NapiAsyncTask::CompleteCallback complete = [weak = context_](
230                                                    napi_env engine, NapiAsyncTask &task, int32_t status) {
231             PRINT_HILOGD("TerminateAbility begin");
232             auto context = weak.lock();
233             if (!context) {
234                 PRINT_HILOGW("context is released");
235                 task.Reject(engine, CreateJsError(engine, E_PRINT_INVALID_CONTEXT, "Context is released"));
236                 return;
237             }
238 
239             auto errcode = context->TerminateAbility();
240             if (errcode == 0) {
241                 napi_value undefineResult = nullptr;
242                 napi_get_undefined(engine, &undefineResult);
243                 task.Resolve(engine, undefineResult);
244             } else {
245                 task.Reject(engine, CreateJsError(engine, errcode, "Terminate Ability failed."));
246             }
247         };
248 
249         napi_value lastParam = (argc == NapiPrintUtils::ARGC_ZERO) ? nullptr : argv[0];
250         napi_value result = nullptr;
251         NapiAsyncTask::Schedule("PrintExtensionContext::OnTerminateAbility", engine,
252             CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
253         return result;
254     }
255 
OnConnectAbility(napi_env & engine,napi_callback_info & info)256     napi_value OnConnectAbility(napi_env &engine, napi_callback_info &info)
257     {
258         PRINT_HILOGD("OnConnectAbility is called");
259         size_t argc = NapiPrintUtils::MAX_ARGC;
260         napi_value argv[NapiPrintUtils::MAX_ARGC] = { nullptr };
261         napi_get_cb_info(engine, info, &argc, argv, nullptr, nullptr);
262         if (argc != NapiPrintUtils::ARGC_TWO) {
263             return GetUndefinedValue(engine);
264         }
265 
266         AAFwk::Want want;
267         OHOS::AppExecFwk::UnwrapWant(engine, argv[0], want);
268         PRINT_HILOGD("%{public}s bundlename:%{public}s abilityname:%{public}s", __func__, want.GetBundle().c_str(),
269             want.GetElement().GetAbilityName().c_str());
270 
271         sptr<JSPrintExtensionConnection> connection = new JSPrintExtensionConnection(engine);
272         connection->SetJsConnectionObject(argv[1]);
273         int64_t connectId = serialNumber_;
274         ConnecttionKey key;
275         key.id = serialNumber_;
276         key.want = want;
277         std::unique_lock<std::shared_timed_mutex> lock(managersMutex_);
278         connects_.emplace(key, connection);
279         (serialNumber_ < INT64_MAX) ? serialNumber_++ : serialNumber_ = 0;
280         NapiAsyncTask::CompleteCallback complete = [weak = context_, want, connection, connectId](
281                                                    napi_env engine, NapiAsyncTask &task, int32_t status) {
282             PRINT_HILOGD("OnConnectAbility begin");
283             auto context = weak.lock();
284             if (!context) {
285                 PRINT_HILOGW("context is released");
286                     task.Reject(engine, CreateJsError(engine, E_PRINT_INVALID_CONTEXT, "Context is released"));
287                 return;
288             }
289             PRINT_HILOGD("context->ConnectAbility connection:%{public}d", (int32_t)connectId);
290             if (!context->ConnectAbility(want, connection)) {
291                     connection->CallJsFailed(E_PRINT_INVALID_CONTEXT);
292             }
293             napi_value undefineResult = nullptr;
294             napi_get_undefined(engine, &undefineResult);
295             task.Resolve(engine, undefineResult);
296         };
297         napi_value result = nullptr;
298         NapiAsyncTask::Schedule("PrintExtensionContext::OnConnectAbility", engine,
299             CreateAsyncTaskWithLastParam(engine, nullptr, nullptr, std::move(complete), &result));
300         napi_value numberResult = nullptr;
301         napi_create_double(engine, connectId, &numberResult);
302         return numberResult;
303     }
304 
OnConnectAbilityWithAccount(napi_env & engine,napi_callback_info & info)305     napi_value OnConnectAbilityWithAccount(napi_env &engine, napi_callback_info &info)
306     {
307         PRINT_HILOGD("OnConnectAbilityWithAccount is called");
308         size_t argc = NapiPrintUtils::MAX_ARGC;
309         napi_value argv[NapiPrintUtils::MAX_ARGC] = { nullptr };
310         napi_get_cb_info(engine, info, &argc, argv, nullptr, nullptr);
311         if (argc != NapiPrintUtils::ARGC_THREE) {
312             return GetUndefinedValue(engine);
313         }
314 
315         AAFwk::Want want;
316         OHOS::AppExecFwk::UnwrapWant(engine, argv[0], want);
317         PRINT_HILOGD("%{public}s bundlename:%{public}s abilityname:%{public}s", __func__, want.GetBundle().c_str(),
318             want.GetElement().GetAbilityName().c_str());
319 
320         int32_t accountId = 0;
321         if (!OHOS::AppExecFwk::UnwrapInt32FromJS2(engine, argv[1], accountId)) {
322             PRINT_HILOGD("%{public}s called, the second parameter is invalid.", __func__);
323             return GetUndefinedValue(engine);
324         }
325 
326         sptr<JSPrintExtensionConnection> connection = new JSPrintExtensionConnection(engine);
327         connection->SetJsConnectionObject(argv[1]);
328         int64_t connectId = serialNumber_;
329         ConnecttionKey key;
330         key.id = serialNumber_;
331         key.want = want;
332         std::unique_lock<std::shared_timed_mutex> lock(managersMutex_);
333         connects_.emplace(key, connection);
334         (serialNumber_ < INT64_MAX) ? serialNumber_++ : serialNumber_ = 0;
335         NapiAsyncTask::CompleteCallback complete = [weak = context_, want, accountId, connection, connectId](
336                                                    napi_env engine, NapiAsyncTask &task, int32_t status) {
337             PRINT_HILOGD("OnConnectAbilityWithAccount begin");
338             auto context = weak.lock();
339             if (!context) {
340                 PRINT_HILOGW("context is released");
341                 task.Reject(engine, CreateJsError(engine, E_PRINT_INVALID_CONTEXT, "Context is released"));
342                 return;
343             }
344             PRINT_HILOGD("context->ConnectAbilityWithAccount connection:%{public}d", (int32_t)connectId);
345             if (!context->ConnectAbilityWithAccount(want, accountId, connection)) {
346                 connection->CallJsFailed(E_PRINT_INVALID_CONTEXT);
347             }
348             napi_value undefineResult = nullptr;
349             napi_get_undefined(engine, &undefineResult);
350             task.Resolve(engine, undefineResult);
351         };
352         napi_value result = nullptr;
353         NapiAsyncTask::Schedule("PrintExtensionContext::OnConnectAbilityWithAccount", engine,
354             CreateAsyncTaskWithLastParam(engine, nullptr, nullptr, std::move(complete), &result));
355         napi_value numberResult = nullptr;
356         napi_create_double(engine, connectId, &numberResult);
357         return numberResult;
358     }
359 
OnDisconnectAbility(napi_env & engine,napi_callback_info & info)360     napi_value OnDisconnectAbility(napi_env &engine, napi_callback_info &info)
361     {
362         PRINT_HILOGD("OnDisconnectAbility is called");
363         size_t argc = NapiPrintUtils::MAX_ARGC;
364         napi_value argv[NapiPrintUtils::MAX_ARGC] = { nullptr };
365         napi_get_cb_info(engine, info, &argc, argv, nullptr, nullptr);
366         if (argc != NapiPrintUtils::ARGC_ONE && argc != NapiPrintUtils::ARGC_TWO) {
367             return GetUndefinedValue(engine);
368         }
369 
370         AAFwk::Want want;
371         int64_t connectId = -1;
372         sptr<JSPrintExtensionConnection> connection = nullptr;
373         napi_get_value_int64(engine, argv[NapiPrintUtils::INDEX_ZERO], &connectId);
374         PRINT_HILOGD("OnDisconnectAbility connection:%{public}d", static_cast<int32_t>(connectId));
375         auto item = std::find_if(connects_.begin(), connects_.end(),
376             [&connectId](const std::map<ConnecttionKey, sptr<JSPrintExtensionConnection>>::value_type &obj) {
377                 return connectId == obj.first.id;
378             });
379         if (item != connects_.end()) {
380             // match id
381             want = item->first.want;
382             connection = item->second;
383         } else {
384             PRINT_HILOGD("%{public}s not find conn exist.", __func__);
385         }
386         NapiAsyncTask::CompleteCallback complete = [weak = context_, want, connection](
387                                                    napi_env engine, NapiAsyncTask &task, int32_t status) {
388             PRINT_HILOGD("OnDisconnectAbility begin");
389             auto context = weak.lock();
390             if (!context) {
391                 PRINT_HILOGW("context is released");
392                 task.Reject(engine, CreateJsError(engine, E_PRINT_INVALID_CONTEXT, "Context is released"));
393                 return;
394             }
395             if (connection == nullptr) {
396                 PRINT_HILOGW("connection nullptr");
397                 task.Reject(engine, CreateJsError(engine, E_PRINT_INVALID_CONNECTION, "not found connection"));
398                 return;
399             }
400             PRINT_HILOGD("context->DisconnectAbility");
401             auto errcode = context->DisconnectAbility(want, connection);
402             napi_value undefineResult = nullptr;
403             napi_get_undefined(engine, &undefineResult);
404             errcode == 0 ? task.Resolve(engine, undefineResult)
405                          : task.Reject(engine, CreateJsError(engine, errcode, "Disconnect Ability failed."));
406         };
407 
408         napi_value lastParam = (argc == NapiPrintUtils::ARGC_ONE) ? nullptr : argv[1];
409         napi_value result = nullptr;
410         NapiAsyncTask::Schedule("PrintExtensionContext::OnDisconnectAbility", engine,
411             CreateAsyncTaskWithLastParam(engine, lastParam, nullptr, std::move(complete), &result));
412         return result;
413     }
414 };
415 
CreateJsMetadata(napi_env & engine,const AppExecFwk::Metadata & Info)416 napi_value CreateJsMetadata(napi_env &engine, const AppExecFwk::Metadata &Info)
417 {
418     PRINT_HILOGD("CreateJsMetadata");
419     napi_value object = nullptr;
420     napi_create_object(engine, &object);
421 
422     napi_set_named_property(engine, object, "name", CreateJsValue(engine, Info.name));
423     napi_set_named_property(engine, object, "value", CreateJsValue(engine, Info.value));
424     napi_set_named_property(engine, object, "resource", CreateJsValue(engine, Info.resource));
425     return object;
426 }
427 
CreateJsMetadataArray(napi_env & engine,const std::vector<AppExecFwk::Metadata> & info)428 napi_value CreateJsMetadataArray(napi_env &engine, const std::vector<AppExecFwk::Metadata> &info)
429 {
430     PRINT_HILOGD("CreateJsMetadataArray");
431     napi_value arrayValue = nullptr;
432     napi_status ret = napi_create_array_with_length(engine, info.size(), &arrayValue);
433     if (ret != napi_ok && arrayValue != nullptr) {
434         uint32_t index = 0;
435         for (const auto &item: info) {
436             napi_set_element(engine, arrayValue, index++, CreateJsMetadata(engine, item));
437         }
438     }
439     return arrayValue;
440 }
441 
CreateJsExtensionAbilityInfoMessage(napi_env & engine,const AppExecFwk::ExtensionAbilityInfo & info)442 napi_value CreateJsExtensionAbilityInfoMessage(napi_env &engine, const AppExecFwk::ExtensionAbilityInfo &info)
443 {
444     PRINT_HILOGD("CreateJsExtensionAbilityInfoMessage");
445     napi_value object = nullptr;
446     napi_create_object(engine, &object);
447     napi_set_named_property(engine, object, "bundleName", CreateJsValue(engine, info.bundleName));
448     napi_set_named_property(engine, object, "moduleName", CreateJsValue(engine, info.moduleName));
449     napi_set_named_property(engine, object, "name", CreateJsValue(engine, info.name));
450     napi_set_named_property(engine, object, "labelId", CreateJsValue(engine, info.labelId));
451     napi_set_named_property(engine, object, "descriptionId", CreateJsValue(engine, info.descriptionId));
452     napi_set_named_property(engine, object, "iconId", CreateJsValue(engine, info.iconId));
453     napi_set_named_property(engine, object, "isVisible", CreateJsValue(engine, info.visible));
454     napi_set_named_property(engine, object, "extensionAbilityType", CreateJsValue(engine, info.type));
455 
456     napi_value permissionArrayValue = nullptr;
457     napi_create_array_with_length(engine, info.permissions.size(), &permissionArrayValue);
458     if (permissionArrayValue != nullptr) {
459         uint32_t index = 0;
460         for (auto permission : info.permissions) {
461             napi_set_element(engine, permissionArrayValue, index++, CreateJsValue(engine, permission));
462         }
463     }
464     napi_set_named_property(engine, object, "permissions", permissionArrayValue);
465     napi_set_named_property(engine, object, "applicationInfo", CreateJsApplicationInfo(engine, info.applicationInfo));
466     napi_set_named_property(engine, object, "metadata", CreateJsMetadataArray(engine, info.metadata));
467     napi_set_named_property(engine, object, "enabled", CreateJsValue(engine, info.enabled));
468     napi_set_named_property(engine, object, "readPermission", CreateJsValue(engine, info.readPermission));
469     napi_set_named_property(engine, object, "writePermission", CreateJsValue(engine, info.writePermission));
470     return object;
471 }
472 
CreateJsPrintExtensionContext(napi_env engine,std::shared_ptr<PrintExtensionContext> context,std::string & extensionId)473 napi_value CreateJsPrintExtensionContext(napi_env engine,
474     std::shared_ptr<PrintExtensionContext> context, std::string &extensionId)
475 {
476     PRINT_HILOGD("CreateJsPrintExtensionContext begin");
477     napi_value objValue = CreateJsExtensionContext(engine, context);
478     napi_value object = objValue;
479 
480     std::unique_ptr<JsPrintExtensionContext> jsContext = std::make_unique<JsPrintExtensionContext>(context);
481     napi_wrap(engine, object, jsContext.release(), JsPrintExtensionContext::Finalizer, nullptr, nullptr);
482 
483     // make handler
484     handler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
485     const char *moduleName = "JsPrintExtensionContext";
486     BindNativeFunction(engine, object, "startAbility", moduleName, JsPrintExtensionContext::StartAbility);
487     BindNativeFunction(engine, object, "terminateSelf", moduleName, JsPrintExtensionContext::TerminateAbility);
488     BindNativeFunction(engine, object, "connectAbility", moduleName, JsPrintExtensionContext::ConnectAbility);
489     BindNativeFunction(engine, object, "disconnectAbility", moduleName, JsPrintExtensionContext::DisconnectAbility);
490     BindNativeFunction(
491         engine, object, "startAbilityWithAccount", moduleName, JsPrintExtensionContext::StartAbilityWithAccount);
492     BindNativeFunction(
493         engine, object, "connectAbilityWithAccount", moduleName, JsPrintExtensionContext::ConnectAbilityWithAccount);
494     if (context) {
495         PRINT_HILOGD("Set ExtensionAbilityInfo Property");
496         auto abilityInfo = context->GetAbilityInfo();
497         auto hapModuleInfo = context->GetHapModuleInfo();
498         if (abilityInfo && hapModuleInfo) {
499             extensionId = abilityInfo->bundleName;
500             PRINT_HILOGD("Set ExtensionAbilityInfo Property: extensionId = %{public}s", extensionId.c_str());
501             auto isExist = [&abilityInfo](const AppExecFwk::ExtensionAbilityInfo &info) {
502                 PRINT_HILOGD("%{public}s, %{public}s", info.bundleName.c_str(), info.name.c_str());
503                 return info.bundleName == abilityInfo->bundleName && info.name == abilityInfo->name;
504             };
505             auto infoIter =
506                 std::find_if(hapModuleInfo->extensionInfos.begin(), hapModuleInfo->extensionInfos.end(), isExist);
507             if (infoIter == hapModuleInfo->extensionInfos.end()) {
508                 PRINT_HILOGD("Get target fail.");
509                 return objValue;
510             }
511             napi_set_named_property(engine, object,
512                 "extensionAbilityInfo", CreateJsExtensionAbilityInfoMessage(engine, *infoIter));
513         }
514     }
515 
516     return objValue;
517 }
518 } // namespace AbilityRuntime
519 } // namespace OHOS
520