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.h"
17
18 #include "ability_info.h"
19 #include "iprint_extension_callback.h"
20 #include "js_print_callback.h"
21 #include "js_print_extension_context.h"
22 #include "js_runtime.h"
23 #include "js_runtime_utils.h"
24 #include "napi/native_api.h"
25 #include "napi/native_node_api.h"
26 #include "napi_common_util.h"
27 #include "napi_common_want.h"
28 #include "napi_print_utils.h"
29 #include "napi_remote_object.h"
30 #include "print_log.h"
31 #include "print_manager_client.h"
32 #include "printer_capability.h"
33 #include "print_job_helper.h"
34 #include "print_utils.h"
35
36 namespace OHOS {
37 namespace AbilityRuntime {
38 JsPrintExtension *JsPrintExtension::jsExtension_ = nullptr;
39 std::mutex JsPrintExtension::mtx;
40 using namespace OHOS::AppExecFwk;
41 using namespace OHOS::Print;
42
Create(const std::unique_ptr<Runtime> & runtime)43 JsPrintExtension *JsPrintExtension::Create(const std::unique_ptr<Runtime> &runtime)
44 {
45 PRINT_HILOGD("jws JsPrintExtension begin Create");
46 jsExtension_ = new JsPrintExtension(static_cast<JsRuntime &>(*runtime));
47 return jsExtension_;
48 }
49
JsPrintExtension(JsRuntime & jsRuntime)50 JsPrintExtension::JsPrintExtension(JsRuntime &jsRuntime) : jsRuntime_(jsRuntime),
51 extensionId_("") {}
~JsPrintExtension()52 JsPrintExtension::~JsPrintExtension()
53 {
54 std::lock_guard<std::mutex> lock(mtx);
55 if (jsExtension_ != nullptr) {
56 jsExtension_ = nullptr;
57 }
58 if (jsObj_) {
59 jsRuntime_.FreeNativeReference(std::move(jsObj_));
60 }
61 PRINT_HILOGI("JsPrintExtension destroyed");
62 }
63
64
Init(const std::shared_ptr<AbilityLocalRecord> & record,const std::shared_ptr<OHOSApplication> & application,std::shared_ptr<AbilityHandler> & handler,const sptr<IRemoteObject> & token)65 void JsPrintExtension::Init(const std::shared_ptr<AbilityLocalRecord> &record,
66 const std::shared_ptr<OHOSApplication> &application, std::shared_ptr<AbilityHandler> &handler,
67 const sptr<IRemoteObject> &token)
68 {
69 PRINT_HILOGD("jws JsPrintExtension begin Init");
70 PrintExtension::Init(record, application, handler, token);
71
72 if (!InitExtensionObj(jsRuntime_)) {
73 PRINT_HILOGE("Failed to init extension object");
74 return;
75 }
76
77 napi_value obj = jsObj_->GetNapiValue();
78 if (obj == nullptr) {
79 PRINT_HILOGE("Failed to get JsPrintExtension object");
80 return;
81 }
82
83 if (!InitContextObj(jsRuntime_, obj, extensionId_)) {
84 PRINT_HILOGE("Failed to init extension context object");
85 return;
86 }
87 PRINT_HILOGD("JsPrintExtension::Init end.");
88 }
89
InitExtensionObj(JsRuntime & jsRuntime)90 bool JsPrintExtension::InitExtensionObj(JsRuntime &jsRuntime)
91 {
92 std::string srcPath = "";
93 GetSrcPath(srcPath);
94 if (srcPath.empty()) {
95 PRINT_HILOGE("Failed to get srcPath");
96 return false;
97 }
98
99 std::string moduleName(abilityInfo_->moduleName);
100 moduleName.append("::").append(abilityInfo_->name);
101 PRINT_HILOGD("Init module:%{public}s,srcPath:%{public}s.", moduleName.c_str(), srcPath.c_str());
102 HandleScope handleScope(jsRuntime_);
103
104 jsObj_ = jsRuntime.LoadModule(moduleName, srcPath, abilityInfo_->hapPath,
105 abilityInfo_->compileMode == CompileMode::ES_MODULE);
106 if (jsObj_ == nullptr) {
107 PRINT_HILOGE("Failed to get jsObj_");
108 return false;
109 }
110 return true;
111 }
112
InitContextObj(JsRuntime & jsRuntime,napi_value & extObj,std::string & extensionId)113 bool JsPrintExtension::InitContextObj(JsRuntime &jsRuntime, napi_value &extObj, std::string &extensionId)
114 {
115 auto context = GetContext();
116 if (context == nullptr) {
117 PRINT_HILOGE("Failed to get context");
118 return false;
119 }
120 PRINT_HILOGD("CreateJsPrintExtensionContext.");
121 napi_env engine = jsRuntime.GetNapiEnv();
122 napi_value contextObj = CreateJsPrintExtensionContext(engine, context, extensionId);
123 auto shellContextRef = jsRuntime.LoadSystemModule("PrintExtensionContext", &contextObj, NapiPrintUtils::ARGC_ONE);
124 if (shellContextRef == nullptr) {
125 PRINT_HILOGE("Failed to load print extension context ref");
126 return false;
127 }
128 contextObj = shellContextRef->GetNapiValue();
129 if (contextObj == nullptr) {
130 PRINT_HILOGE("Failed to get Print extension native object");
131 return false;
132 }
133 PRINT_HILOGD("JsPrintExtension::Init Bind.");
134 context->Bind(jsRuntime, shellContextRef.release());
135 PRINT_HILOGD("JsPrintExtension::napi_set_named_property.");
136 napi_set_named_property(engine, extObj, "context", contextObj);
137
138 napi_wrap(engine, contextObj, new std::weak_ptr<AbilityRuntime::Context>(context),
139 [](napi_env, void *data, void *) {
140 PRINT_HILOGD("Finalizer for weak_ptr Print extension context is called");
141 delete static_cast<std::weak_ptr<AbilityRuntime::Context> *>(data);
142 },
143 nullptr, nullptr);
144 return true;
145 }
146
OnStart(const AAFwk::Want & want)147 void JsPrintExtension::OnStart(const AAFwk::Want &want)
148 {
149 Extension::OnStart(want);
150 PRINT_HILOGD("jws JsPrintExtension OnStart begin..");
151 HandleScope handleScope(jsRuntime_);
152 napi_env nativeEngine = jsRuntime_.GetNapiEnv();
153 napi_value nativeWant = OHOS::AppExecFwk::WrapWant(nativeEngine, want);
154 napi_value argv[] = { nativeWant };
155 CallObjectMethod("onCreate", argv, NapiPrintUtils::ARGC_ONE);
156 RegisterCb();
157 PrintManagerClient::GetInstance()->LoadExtSuccess(extensionId_);
158 PRINT_HILOGD("%{public}s end.", __func__);
159 }
160
RegisterCb()161 void JsPrintExtension::RegisterCb()
162 {
163 RegisterDiscoveryCb();
164 RegisterConnectionCb();
165 RegisterPrintJobCb();
166 RegisterPreviewCb();
167 RegisterQueryCapCb();
168 RegisterExtensionCb();
169 }
170
OnStop()171 void JsPrintExtension::OnStop()
172 {
173 PrintExtension::OnStop();
174 PRINT_HILOGD("jws JsPrintExtension OnStop begin.");
175 auto context = GetContext();
176 if (context == nullptr) {
177 PRINT_HILOGE("Failed to get context");
178 return;
179 }
180 bool ret = ConnectionManager::GetInstance().DisconnectCaller(context->GetToken());
181 if (ret) {
182 PRINT_HILOGD("The Print extension connection is not disconnected.");
183 }
184 PRINT_HILOGD("%{public}s end.", __func__);
185 }
186
OnConnect(const AAFwk::Want & want)187 sptr<IRemoteObject> JsPrintExtension::OnConnect(const AAFwk::Want &want)
188 {
189 PRINT_HILOGD("jws JsPrintExtension OnConnect begin.");
190 Extension::OnConnect(want);
191 PRINT_HILOGD("%{public}s begin.", __func__);
192 HandleScope handleScope(jsRuntime_);
193 napi_env nativeEngine = jsRuntime_.GetNapiEnv();
194 napi_value nativeWant = OHOS::AppExecFwk::WrapWant(nativeEngine, want);
195 napi_value argv[] = { nativeWant };
196 if (!jsObj_) {
197 PRINT_HILOGW("Not found PrintExtension.js");
198 return nullptr;
199 }
200
201 napi_value obj = jsObj_->GetNapiValue();
202 if (obj == nullptr) {
203 PRINT_HILOGE("Failed to get PrintExtension object");
204 return nullptr;
205 }
206
207 napi_value method = nullptr;
208 napi_get_named_property(nativeEngine, obj, "onConnect", &method);
209 if (method == nullptr) {
210 PRINT_HILOGE("Failed to get onConnect from PrintExtension object");
211 return nullptr;
212 }
213 PRINT_HILOGD("JsPrintExtension::napi_call_function onConnect, success");
214 napi_value remoteNative = nullptr;
215 napi_call_function(nativeEngine, obj, method, NapiPrintUtils::ARGC_ONE, argv, &remoteNative);
216 if (remoteNative == nullptr) {
217 PRINT_HILOGE("remoteNative nullptr.");
218 }
219 auto remoteObj = NAPI_ohos_rpc_getNativeRemoteObject(nativeEngine, remoteNative);
220 if (remoteObj == nullptr) {
221 PRINT_HILOGE("remoteObj nullptr.");
222 }
223 return remoteObj;
224 }
225
OnDisconnect(const AAFwk::Want & want)226 void JsPrintExtension::OnDisconnect(const AAFwk::Want &want)
227 {
228 PRINT_HILOGD("jws JsPrintExtension OnDisconnect begin.");
229 Extension::OnDisconnect(want);
230 PRINT_HILOGD("%{public}s begin.", __func__);
231 HandleScope handleScope(jsRuntime_);
232 napi_env nativeEngine = jsRuntime_.GetNapiEnv();
233 napi_value nativeWant = OHOS::AppExecFwk::WrapWant(nativeEngine, want);
234 napi_value argv[] = { nativeWant };
235 if (!jsObj_) {
236 PRINT_HILOGW("Not found PrintExtension.js");
237 return;
238 }
239
240 napi_value obj = jsObj_->GetNapiValue();
241 if (obj == nullptr) {
242 PRINT_HILOGE("Failed to get PrintExtension object");
243 return;
244 }
245
246 napi_value method = nullptr;
247 napi_get_named_property(nativeEngine, obj, "onDisconnect", &method);
248 if (method == nullptr) {
249 PRINT_HILOGE("Failed to get onDisconnect from PrintExtension object");
250 return;
251 }
252 napi_value callResult = nullptr;
253 napi_call_function(nativeEngine, obj, method, NapiPrintUtils::ARGC_ONE, argv, &callResult);
254 PRINT_HILOGD("%{public}s end.", __func__);
255 }
256
OnCommand(const AAFwk::Want & want,bool restart,int startId)257 void JsPrintExtension::OnCommand(const AAFwk::Want &want, bool restart, int startId)
258 {
259 PRINT_HILOGD("jws JsPrintExtension OnCommand begin.");
260 Extension::OnCommand(want, restart, startId);
261 PRINT_HILOGD("begin restart=%{public}s,startId=%{public}d.", restart ? "true" : "false", startId);
262 if (startId <= 1) {
263 PRINT_HILOGD("%{public}s ignore.", __func__);
264 return;
265 }
266 HandleScope handleScope(jsRuntime_);
267 napi_env nativeEngine = jsRuntime_.GetNapiEnv();
268 napi_value nativeWant = OHOS::AppExecFwk::WrapWant(nativeEngine, want);
269 napi_value argv[] = { nativeWant };
270 CallObjectMethod("onCreate", argv, NapiPrintUtils::ARGC_ONE);
271 RegisterCb();
272 PrintManagerClient::GetInstance()->LoadExtSuccess(extensionId_);
273 PRINT_HILOGD("%{public}s end.", __func__);
274 }
275
CallObjectMethod(const char * name,napi_value const * argv,size_t argc)276 napi_value JsPrintExtension::CallObjectMethod(const char *name, napi_value const *argv, size_t argc)
277 {
278 PRINT_HILOGD("jws JsPrintExtension::CallObjectMethod(%{public}s), begin", name);
279
280 if (!jsObj_) {
281 PRINT_HILOGW("Not found PrintExtension.js");
282 return nullptr;
283 }
284
285 HandleScope handleScope(jsRuntime_);
286 napi_env nativeEngine = jsRuntime_.GetNapiEnv();
287
288 napi_value obj = jsObj_->GetNapiValue();
289 if (obj == nullptr) {
290 PRINT_HILOGE("Failed to get PrintExtension object");
291 return nullptr;
292 }
293
294 napi_value method = nullptr;
295 napi_get_named_property(nativeEngine, obj, name, &method);
296 if (method == nullptr) {
297 PRINT_HILOGE("Failed to get '%{public}s' from PrintExtension object", name);
298 return nullptr;
299 }
300 PRINT_HILOGD("JsPrintExtension::napi_call_function(%{public}s), success", name);
301 napi_value callResult = nullptr;
302 napi_call_function(nativeEngine, obj, method, argc, argv, &callResult);
303 return callResult;
304 }
305
GetSrcPath(std::string & srcPath)306 void JsPrintExtension::GetSrcPath(std::string &srcPath)
307 {
308 PRINT_HILOGD("jws JsPrintExtension GetSrcPath begin.");
309 if (!Extension::abilityInfo_->isModuleJson) {
310 /* temporary compatibility api8 + config.json */
311 srcPath.append(Extension::abilityInfo_->package);
312 srcPath.append("/assets/js/");
313 if (!Extension::abilityInfo_->srcPath.empty()) {
314 srcPath.append(Extension::abilityInfo_->srcPath);
315 }
316 srcPath.append("/").append(Extension::abilityInfo_->name).append(".abc");
317 return;
318 }
319
320 if (!Extension::abilityInfo_->srcEntrance.empty()) {
321 srcPath.append(Extension::abilityInfo_->moduleName + "/");
322 srcPath.append(Extension::abilityInfo_->srcEntrance);
323 srcPath.erase(srcPath.rfind('.'));
324 srcPath.append(".abc");
325 }
326 }
327
Callback(std::string funcName)328 bool JsPrintExtension::Callback(std::string funcName)
329 {
330 PRINT_HILOGD("call %{public}s", funcName.c_str());
331 std::lock_guard<std::mutex> lock(mtx);
332 if (JsPrintExtension::jsExtension_ == nullptr) {
333 return false;
334 }
335 napi_env env = (JsPrintExtension::jsExtension_->jsRuntime_).GetNapiEnv();
336 WorkParam *workParam = new (std::nothrow) WorkParam(env, funcName);
337 if (workParam == nullptr) {
338 return false;
339 }
340 uv_after_work_cb afterCallback = [](uv_work_t *work, int32_t status) {
341 WorkParam *param = reinterpret_cast<WorkParam *>(work->data);
342 if (param == nullptr) {
343 delete work;
344 return;
345 }
346 napi_handle_scope scope = nullptr;
347 napi_open_handle_scope(param->env, &scope);
348 if (scope == nullptr) {
349 delete param;
350 delete work;
351 return;
352 }
353 napi_value arg[] = { 0 };
354 std::lock_guard<std::mutex> lock(mtx);
355 if (JsPrintExtension::jsExtension_ != nullptr) {
356 JsPrintExtension::jsExtension_->CallObjectMethod(param->funcName.c_str(), arg, NapiPrintUtils::ARGC_ZERO);
357 }
358 napi_close_handle_scope(param->env, scope);
359 delete param;
360 delete work;
361 };
362 bool ret = JsPrintCallback::Call(env, workParam, afterCallback);
363 if (!ret) {
364 delete workParam;
365 workParam = nullptr;
366 PRINT_HILOGE("Callback fail, delete param");
367 return false;
368 }
369 return true;
370 }
371
Callback(const std::string funcName,const std::string & printerId)372 bool JsPrintExtension::Callback(const std::string funcName, const std::string &printerId)
373 {
374 PRINT_HILOGD("call %{public}s", funcName.c_str());
375 std::lock_guard<std::mutex> lock(mtx);
376 if (JsPrintExtension::jsExtension_ == nullptr) {
377 return false;
378 }
379 napi_env env = (JsPrintExtension::jsExtension_->jsRuntime_).GetNapiEnv();
380 WorkParam *workParam = new (std::nothrow) WorkParam(env, funcName);
381 if (workParam == nullptr) {
382 return false;
383 }
384 workParam->printerId = printerId;
385 uv_after_work_cb afterCallback = [](uv_work_t *work, int32_t status) {
386 WorkParam *param = reinterpret_cast<WorkParam *>(work->data);
387 if (param == nullptr) {
388 delete work;
389 return;
390 }
391 napi_handle_scope scope = nullptr;
392 napi_open_handle_scope(param->env, &scope);
393 if (scope == nullptr) {
394 delete param;
395 delete work;
396 return;
397 }
398 napi_value id = OHOS::AppExecFwk::WrapStringToJS(param->env, param->printerId);
399 napi_value arg[] = { id };
400 std::lock_guard<std::mutex> lock(mtx);
401 if (JsPrintExtension::jsExtension_ != nullptr) {
402 JsPrintExtension::jsExtension_->CallObjectMethod(param->funcName.c_str(), arg, NapiPrintUtils::ARGC_ONE);
403 }
404 napi_close_handle_scope(param->env, scope);
405 delete param;
406 delete work;
407 };
408 bool ret = JsPrintCallback::Call(env, workParam, afterCallback);
409 if (!ret) {
410 delete workParam;
411 workParam = nullptr;
412 PRINT_HILOGE("Callback fail, delete param");
413 return false;
414 }
415 return true;
416 }
417
Callback(const std::string funcName,const Print::PrintJob & job)418 bool JsPrintExtension::Callback(const std::string funcName, const Print::PrintJob &job)
419 {
420 PRINT_HILOGD("call %{public}s", funcName.c_str());
421 std::lock_guard<std::mutex> lock(mtx);
422 if (JsPrintExtension::jsExtension_ == nullptr) {
423 return false;
424 }
425 napi_env env = (JsPrintExtension::jsExtension_->jsRuntime_).GetNapiEnv();
426 WorkParam *workParam = new (std::nothrow) WorkParam(env, funcName);
427 if (workParam == nullptr) {
428 return false;
429 }
430 workParam->job = job;
431 uv_after_work_cb afterCallback = [](uv_work_t *work, int32_t status) {
432 WorkParam *param = reinterpret_cast<WorkParam *>(work->data);
433 if (param == nullptr) {
434 delete work;
435 return;
436 }
437 napi_handle_scope scope = nullptr;
438 napi_open_handle_scope(param->env, &scope);
439 if (scope == nullptr) {
440 delete param;
441 delete work;
442 return;
443 }
444 napi_value jobObject = PrintJobHelper::MakeJsObject(param->env, param->job);
445 napi_value arg[] = { jobObject };
446 std::lock_guard<std::mutex> lock(mtx);
447 if (JsPrintExtension::jsExtension_ != nullptr) {
448 JsPrintExtension::jsExtension_->CallObjectMethod(param->funcName.c_str(), arg, NapiPrintUtils::ARGC_ONE);
449 }
450 napi_close_handle_scope(param->env, scope);
451 delete param;
452 delete work;
453 };
454 bool ret = JsPrintCallback::Call(env, workParam, afterCallback);
455 if (!ret) {
456 delete workParam;
457 workParam = nullptr;
458 PRINT_HILOGE("Callback fail, delete param");
459 return false;
460 }
461 return true;
462 }
463
RegisterDiscoveryCb()464 void JsPrintExtension::RegisterDiscoveryCb()
465 {
466 PRINT_HILOGD("Register Print Extension Callback");
467 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_START_DISCOVERY,
468 []() -> bool {
469 if (JsPrintExtension::jsExtension_ == nullptr) {
470 return false;
471 }
472 return JsPrintExtension::jsExtension_->Callback("onStartDiscoverPrinter");
473 });
474 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_STOP_DISCOVERY,
475 []() -> bool {
476 if (JsPrintExtension::jsExtension_ == nullptr) {
477 return false;
478 }
479 return JsPrintExtension::jsExtension_->Callback("onStopDiscoverPrinter");
480 });
481 }
482
RegisterConnectionCb()483 void JsPrintExtension::RegisterConnectionCb()
484 {
485 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_CONNECT_PRINTER,
486 [](const std::string &printId) -> bool {
487 if (JsPrintExtension::jsExtension_ == nullptr) {
488 return false;
489 }
490 std::string realPrinterId = PrintUtils::GetLocalId(printId, jsExtension_->extensionId_);
491 return JsPrintExtension::jsExtension_->Callback("onConnectPrinter", realPrinterId);
492 });
493 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_DISCONNECT_PRINTER,
494 [](const std::string &printId) -> bool {
495 if (JsPrintExtension::jsExtension_ == nullptr) {
496 return false;
497 }
498 std::string realPrinterId = PrintUtils::GetLocalId(printId, jsExtension_->extensionId_);
499 return JsPrintExtension::jsExtension_->Callback("onDisconnectPrinter", realPrinterId);
500 });
501 }
502
RegisterPrintJobCb()503 void JsPrintExtension::RegisterPrintJobCb()
504 {
505 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_START_PRINT,
506 [](const PrintJob &job) -> bool {
507 if (JsPrintExtension::jsExtension_ == nullptr) {
508 return false;
509 }
510 return JsPrintExtension::jsExtension_->Callback("onStartPrintJob", job);
511 });
512 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_CANCEL_PRINT,
513 [](const PrintJob &job) -> bool {
514 if (JsPrintExtension::jsExtension_ == nullptr) {
515 return false;
516 }
517 return JsPrintExtension::jsExtension_->Callback("onCancelPrintJob", job);
518 });
519 }
520
RegisterPreviewCb()521 void JsPrintExtension::RegisterPreviewCb()
522 {
523 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_REQUEST_PREVIEW,
524 [](const PrintJob &job) -> bool {
525 if (JsPrintExtension::jsExtension_ == nullptr) {
526 return false;
527 }
528 return JsPrintExtension::jsExtension_->Callback("onRequestPreview", job);
529 });
530 }
531
RegisterQueryCapCb()532 void JsPrintExtension::RegisterQueryCapCb()
533 {
534 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_REQUEST_CAP,
535 [](const std::string &printId) -> bool {
536 if (JsPrintExtension::jsExtension_ == nullptr) {
537 return false;
538 }
539 std::string realPrinterId = PrintUtils::GetLocalId(printId, jsExtension_->extensionId_);
540 return JsPrintExtension::jsExtension_->Callback("onRequestPrinterCapability", realPrinterId);
541 });
542 }
543
RegisterExtensionCb()544 void JsPrintExtension::RegisterExtensionCb()
545 {
546 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_DESTROY_EXTENSION,
547 []() -> bool {
548 if (JsPrintExtension::jsExtension_ == nullptr) {
549 return false;
550 }
551 JsPrintExtension::jsExtension_->OnStop();
552 return true;
553 });
554 }
555 } // namespace AbilityRuntime
556 } // namespace OHOS
557