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 PRINT_HILOGE("workParam is a nullptr");
339 return false;
340 }
341 auto workCb = [](WorkParam *param) {
342 if (param == nullptr) {
343 PRINT_HILOGE("param is a nullptr");
344 return;
345 }
346 napi_handle_scope scope = nullptr;
347 napi_open_handle_scope(param->env, &scope);
348 if (scope == nullptr) {
349 PRINT_HILOGE("scope is a nullptr");
350 return;
351 }
352 napi_value arg[] = { 0 };
353 std::lock_guard<std::mutex> lock(mtx);
354 if (JsPrintExtension::jsExtension_ != nullptr) {
355 JsPrintExtension::jsExtension_->CallObjectMethod(param->funcName.c_str(), arg, NapiPrintUtils::ARGC_ZERO);
356 }
357 napi_close_handle_scope(param->env, scope);
358 };
359 bool ret = JsPrintCallback::Call(env, workParam, workCb);
360 if (!ret) {
361 PRINT_HILOGE("Callback fail, delete param");
362 delete workParam;
363 return false;
364 }
365 return true;
366 }
367
Callback(const std::string funcName,const std::string & printerId)368 bool JsPrintExtension::Callback(const std::string funcName, const std::string &printerId)
369 {
370 PRINT_HILOGD("call %{public}s", funcName.c_str());
371 std::lock_guard<std::mutex> lock(mtx);
372 if (JsPrintExtension::jsExtension_ == nullptr) {
373 return false;
374 }
375 napi_env env = (JsPrintExtension::jsExtension_->jsRuntime_).GetNapiEnv();
376 WorkParam *workParam = new (std::nothrow) WorkParam(env, funcName);
377 if (workParam == nullptr) {
378 PRINT_HILOGE("workParam is a nullptr");
379 return false;
380 }
381 workParam->printerId = printerId;
382
383 auto workCb = [](WorkParam *param) {
384 if (param == nullptr) {
385 PRINT_HILOGE("param is a nullptr");
386 return;
387 }
388 napi_handle_scope scope = nullptr;
389 napi_open_handle_scope(param->env, &scope);
390 if (scope == nullptr) {
391 PRINT_HILOGE("scope is a nullptr");
392 return;
393 }
394 napi_value id = OHOS::AppExecFwk::WrapStringToJS(param->env, param->printerId);
395 napi_value arg[] = { id };
396 std::lock_guard<std::mutex> lock(mtx);
397 if (JsPrintExtension::jsExtension_ != nullptr) {
398 JsPrintExtension::jsExtension_->CallObjectMethod(param->funcName.c_str(), arg, NapiPrintUtils::ARGC_ONE);
399 }
400 napi_close_handle_scope(param->env, scope);
401 };
402
403 bool ret = JsPrintCallback::Call(env, workParam, workCb);
404 if (!ret) {
405 PRINT_HILOGE("Callback fail, delete param");
406 delete workParam;
407 return false;
408 }
409 return true;
410 }
411
Callback(const std::string funcName,const Print::PrintJob & job)412 bool JsPrintExtension::Callback(const std::string funcName, const Print::PrintJob &job)
413 {
414 PRINT_HILOGD("call %{public}s", funcName.c_str());
415 std::lock_guard<std::mutex> lock(mtx);
416 if (JsPrintExtension::jsExtension_ == nullptr) {
417 return false;
418 }
419 napi_env env = (JsPrintExtension::jsExtension_->jsRuntime_).GetNapiEnv();
420 WorkParam *workParam = new (std::nothrow) WorkParam(env, funcName);
421 if (workParam == nullptr) {
422 PRINT_HILOGE("workParam is a nullptr");
423 return false;
424 }
425 workParam->job = job;
426
427 auto workCb = [](WorkParam *param) {
428 if (param == nullptr) {
429 PRINT_HILOGE("param is a nullptr");
430 return;
431 }
432 napi_handle_scope scope = nullptr;
433 napi_open_handle_scope(param->env, &scope);
434 if (scope == nullptr) {
435 PRINT_HILOGE("scope is a nullptr");
436 return;
437 }
438 napi_value jobObject = PrintJobHelper::MakeJsObject(param->env, param->job);
439 napi_value arg[] = { jobObject };
440 std::lock_guard<std::mutex> lock(mtx);
441 if (JsPrintExtension::jsExtension_ != nullptr) {
442 JsPrintExtension::jsExtension_->CallObjectMethod(param->funcName.c_str(), arg, NapiPrintUtils::ARGC_ONE);
443 }
444 napi_close_handle_scope(param->env, scope);
445 };
446
447 bool ret = JsPrintCallback::Call(env, workParam, workCb);
448 if (!ret) {
449 PRINT_HILOGE("Callback fail, delete param");
450 delete workParam;
451 return false;
452 }
453 return true;
454 }
455
RegisterDiscoveryCb()456 void JsPrintExtension::RegisterDiscoveryCb()
457 {
458 PRINT_HILOGD("Register Print Extension Callback");
459 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_START_DISCOVERY,
460 []() -> bool {
461 if (JsPrintExtension::jsExtension_ == nullptr) {
462 return false;
463 }
464 return JsPrintExtension::jsExtension_->Callback("onStartDiscoverPrinter");
465 });
466 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_STOP_DISCOVERY,
467 []() -> bool {
468 if (JsPrintExtension::jsExtension_ == nullptr) {
469 return false;
470 }
471 return JsPrintExtension::jsExtension_->Callback("onStopDiscoverPrinter");
472 });
473 }
474
RegisterConnectionCb()475 void JsPrintExtension::RegisterConnectionCb()
476 {
477 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_CONNECT_PRINTER,
478 [](const std::string &printId) -> bool {
479 if (JsPrintExtension::jsExtension_ == nullptr) {
480 return false;
481 }
482 std::string realPrinterId = PrintUtils::GetLocalId(printId, jsExtension_->extensionId_);
483 return JsPrintExtension::jsExtension_->Callback("onConnectPrinter", realPrinterId);
484 });
485 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_DISCONNECT_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("onDisconnectPrinter", realPrinterId);
492 });
493 }
494
RegisterPrintJobCb()495 void JsPrintExtension::RegisterPrintJobCb()
496 {
497 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_START_PRINT,
498 [](const PrintJob &job) -> bool {
499 if (JsPrintExtension::jsExtension_ == nullptr) {
500 return false;
501 }
502 return JsPrintExtension::jsExtension_->Callback("onStartPrintJob", job);
503 });
504 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_CANCEL_PRINT,
505 [](const PrintJob &job) -> bool {
506 if (JsPrintExtension::jsExtension_ == nullptr) {
507 return false;
508 }
509 return JsPrintExtension::jsExtension_->Callback("onCancelPrintJob", job);
510 });
511 }
512
RegisterPreviewCb()513 void JsPrintExtension::RegisterPreviewCb()
514 {
515 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_REQUEST_PREVIEW,
516 [](const PrintJob &job) -> bool {
517 if (JsPrintExtension::jsExtension_ == nullptr) {
518 return false;
519 }
520 return JsPrintExtension::jsExtension_->Callback("onRequestPreview", job);
521 });
522 }
523
RegisterQueryCapCb()524 void JsPrintExtension::RegisterQueryCapCb()
525 {
526 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_REQUEST_CAP,
527 [](const std::string &printId) -> bool {
528 if (JsPrintExtension::jsExtension_ == nullptr) {
529 return false;
530 }
531 std::string realPrinterId = PrintUtils::GetLocalId(printId, jsExtension_->extensionId_);
532 return JsPrintExtension::jsExtension_->Callback("onRequestPrinterCapability", realPrinterId);
533 });
534 }
535
RegisterExtensionCb()536 void JsPrintExtension::RegisterExtensionCb()
537 {
538 PrintManagerClient::GetInstance()->RegisterExtCallback(extensionId_, PRINT_EXTCB_DESTROY_EXTENSION,
539 []() -> bool {
540 if (JsPrintExtension::jsExtension_ == nullptr) {
541 return false;
542 }
543 JsPrintExtension::jsExtension_->OnStop();
544 return true;
545 });
546 }
547 } // namespace AbilityRuntime
548 } // namespace OHOS
549