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