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 "napi/native_common.h"
17 #include "accesstoken_kit.h"
18
19 #include "print_task.h"
20 #include "napi_print_utils.h"
21 #include "print_callback.h"
22 #include "print_log.h"
23 #include "print_manager_client.h"
24 #include "print_constant.h"
25
26 namespace OHOS::Print {
27
28 using namespace std;
29 using namespace Security::AccessToken;
30
31 const std::string EVENT_BLOCK = "block";
32 const std::string EVENT_SUCCESS = "succeed";
33 const std::string EVENT_FAIL = "fail";
34 const std::string EVENT_CANCEL = "cancel";
35
36 static const std::string SPOOLER_BUNDLE_NAME = "com.ohos.spooler";
37 static const std::string SPOOLER_PREVIEW_ABILITY_NAME = "PrintServiceExtAbility";
38 static const std::string LAUNCH_PARAMETER_JOB_ID = "jobId";
39 static const std::string LAUNCH_PARAMETER_FILE_LIST = "fileList";
40 static const std::string TOKEN_KEY = "ohos.ability.params.token";
41 static const std::string UI_EXTENSION_TYPE_NAME = "ability.want.params.uiExtensionType";
42 static const std::string PRINT_UI_EXTENSION_TYPE = "sysDialog/print";
43 static const std::string CALLER_PKG_NAME = "caller.pkgName";
44 static const std::string ABILITY_PARAMS_STREAM = "ability.params.stream";
45 static const std::string LAUNCH_PARAMETER_FILE_LIST_SIZE = "fileListSize";
46 static const int32_t MAX_FILE_LIST_SIZE = 100;
47
PrintTask(const std::vector<std::string> & innerList,const sptr<IRemoteObject> & innerCallerToken_)48 PrintTask::PrintTask(const std::vector<std::string> &innerList, const sptr<IRemoteObject> &innerCallerToken_)
49 : taskId_("")
50 {
51 if (!innerList.empty()) {
52 if (innerList.begin()->find("fd://") == 0) {
53 PRINT_HILOGD("list type: fdlist");
54 for (auto fdPath : innerList) {
55 pathType_ = FD_PATH;
56 uint32_t fd = PrintUtils::GetIdFromFdPath(fdPath);
57 fdList_.emplace_back(fd);
58 }
59 } else {
60 PRINT_HILOGD("list type: filelist");
61 fileList_.assign(innerList.begin(), innerList.end());
62 pathType_ = FILE_PATH_ABSOLUTED;
63 if (!fileList_.empty() && fileList_.begin()->find("file://") == 0) {
64 pathType_ = FILE_PATH;
65 }
66 }
67 }
68
69 supportEvents_[EVENT_BLOCK] = true;
70 supportEvents_[EVENT_SUCCESS] = true;
71 supportEvents_[EVENT_FAIL] = true;
72 supportEvents_[EVENT_CANCEL] = true;
73 callerToken_ = innerCallerToken_;
74 }
75
PrintTask(const std::string & innerPrintJobName_,const sptr<IPrintCallback> & innerPrintAdapterCallback_,const std::shared_ptr<PrintAttributes> & innerPrintAttributes_,const sptr<IRemoteObject> & innerCallerToken_)76 PrintTask::PrintTask(const std::string &innerPrintJobName_, const sptr<IPrintCallback> &innerPrintAdapterCallback_,
77 const std::shared_ptr<PrintAttributes> &innerPrintAttributes_, const sptr<IRemoteObject> &innerCallerToken_)
78 : taskId_("")
79 {
80 supportEvents_[EVENT_BLOCK] = true;
81 supportEvents_[EVENT_SUCCESS] = true;
82 supportEvents_[EVENT_FAIL] = true;
83 supportEvents_[EVENT_CANCEL] = true;
84 printJobName_ = innerPrintJobName_;
85 printAdapterCallback_ = innerPrintAdapterCallback_;
86 printAttributes_ = innerPrintAttributes_;
87 callerToken_ = innerCallerToken_;
88 }
89
~PrintTask()90 PrintTask::~PrintTask()
91 {
92 supportEvents_.clear();
93 Stop();
94 }
95
Start(napi_env env,napi_callback_info info)96 uint32_t PrintTask::Start(napi_env env, napi_callback_info info)
97 {
98 if (fileList_.empty() && fdList_.empty()) {
99 PRINT_HILOGE("fileList and fdList are both empty");
100 return E_PRINT_INVALID_PARAMETER;
101 }
102 if (pathType_ == FILE_PATH_ABSOLUTED) {
103 for (auto file : fileList_) {
104 int32_t fd = PrintUtils::OpenFile(file);
105 if (fd >= 0) {
106 fdList_.emplace_back(fd);
107 continue;
108 }
109 PRINT_HILOGE("file[%{private}s] is invalid", file.c_str());
110 for (auto fd : fdList_) {
111 close(fd);
112 }
113 fdList_.clear();
114 fileList_.clear();
115 return E_PRINT_INVALID_PARAMETER;
116 }
117 }
118
119 PRINT_HILOGI("call client's StartPrint interface.");
120 std::shared_ptr<AdapterParam> adapterParam = std::make_shared<AdapterParam>();
121 CreateDefaultAdapterParam(adapterParam);
122 std::string jobId = PrintUtils::GetPrintJobId();
123 adapterParam->jobId = jobId;
124 taskId_ = jobId;
125 uint32_t ret = CallSpooler(env, info, adapterParam, false);
126 if (ret != E_PRINT_NONE) {
127 PRINT_HILOGE("CallSpooler failed.");
128 for (auto fd : fdList_) {
129 close(fd);
130 }
131 fdList_.clear();
132 fileList_.clear();
133 return ret;
134 }
135 return PrintManagerClient::GetInstance()->StartPrint(fileList_, fdList_, taskId_);
136 }
137
StartPrintAdapter(napi_env env,napi_callback_info info)138 uint32_t PrintTask::StartPrintAdapter(napi_env env, napi_callback_info info)
139 {
140 if (printAdapterCallback_ != nullptr && printAttributes_ != nullptr) {
141 PRINT_HILOGI("call client's StartPrintAdapter interface.");
142 if (callerToken_ != nullptr) {
143 std::shared_ptr<AdapterParam> adapterParam = std::make_shared<AdapterParam>();
144 if (adapterParam == nullptr) {
145 PRINT_HILOGE("create adapterParam failed.");
146 return E_PRINT_SERVER_FAILURE;
147 }
148 adapterParam->documentName = printJobName_;
149 adapterParam->isCheckFdList = false;
150 adapterParam->printAttributes = *printAttributes_;
151 std::string jobId = PrintUtils::GetPrintJobId();
152 adapterParam->jobId = jobId;
153 taskId_ = jobId;
154 uint32_t ret = CallSpooler(env, info, adapterParam, true);
155 if (ret != E_PRINT_NONE) {
156 PRINT_HILOGE("CallSpooler failed.");
157 }
158 return PrintManagerClient::GetInstance()->Print(
159 printJobName_, printAdapterCallback_, *printAttributes_, taskId_, callerToken_);
160 }
161 }
162 return E_PRINT_INVALID_PARAMETER;
163 }
164
CallSpooler(napi_env env,napi_callback_info info,const std::shared_ptr<AdapterParam> & adapterParam,bool isPrintByAdapter)165 uint32_t PrintTask::CallSpooler(
166 napi_env env, napi_callback_info info, const std::shared_ptr<AdapterParam> &adapterParam, bool isPrintByAdapter)
167 {
168 PRINT_HILOGI("enter CallSpooler.");
169 if (!CheckPermission(PERMISSION_NAME_PRINT)) {
170 PRINT_HILOGE("no permission to access print service, ErrorCode:[%{public}d]", E_PRINT_NO_PERMISSION);
171 return E_PRINT_NO_PERMISSION;
172 }
173 size_t argc = isPrintByAdapter ? NapiPrintUtils::ARGC_FOUR : NapiPrintUtils::ARGC_TWO;
174 size_t contextIndex = isPrintByAdapter ? NapiPrintUtils::INDEX_THREE : NapiPrintUtils::INDEX_ONE;
175 size_t callBackIndex = isPrintByAdapter ? NapiPrintUtils::INDEX_FOUR : NapiPrintUtils::INDEX_TWO;
176 size_t argMaxNum = isPrintByAdapter ? NapiPrintUtils::ARGC_FIVE : NapiPrintUtils::ARGC_THREE;
177 napi_value argv[NapiPrintUtils::ARGC_FOUR] = {0};
178 napi_value thisArg = nullptr;
179 void *data = nullptr;
180 napi_value result = nullptr;
181
182 PRINT_CALL_BASE(env, napi_get_undefined(env, &result), E_PRINT_INVALID_PARAMETER);
183 PRINT_CALL_BASE(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data), E_PRINT_INVALID_PARAMETER);
184 PRINT_HILOGI("CallSpooler params size: %{public}zu", argc);
185 if (argc < argMaxNum - 1) {
186 PRINT_HILOGE("invalid parameters.");
187 return E_PRINT_INVALID_PARAMETER;
188 }
189
190 auto asyncContext = std::make_shared<BaseContext>();
191 asyncContext->env = env;
192 asyncContext->requestType = PrintRequestType::REQUEST_TYPE_START;
193 if (!ParseAbilityContextReq(env, argv[contextIndex], asyncContext->context, asyncContext->uiExtensionContext)) {
194 PRINT_HILOGE("invalid parameters.");
195 return E_PRINT_INVALID_PARAMETER;
196 }
197
198 if (argc == argMaxNum) {
199 napi_valuetype valueType = napi_undefined;
200 PRINT_CALL_BASE(env, napi_typeof(env, argv[callBackIndex], &valueType), napi_undefined);
201 if (valueType == napi_function) {
202 PRINT_CALL_BASE(env, napi_create_reference(env, argv[callBackIndex], 1, &asyncContext->callback),
203 E_PRINT_INVALID_PARAMETER);
204 PRINT_HILOGD("is a callback api");
205 }
206 } else {
207 PRINT_CALL_BASE(env, napi_create_promise(env, &asyncContext->deferred, &result), E_PRINT_INVALID_PARAMETER);
208 PRINT_HILOGD("is a promise api");
209 }
210 uint32_t ret = StartUIExtensionAbility(asyncContext, adapterParam);
211 PRINT_HILOGI("end CallSpooler");
212 return ret;
213 }
214
ParseAbilityContextReq(napi_env env,const napi_value & obj,std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> & abilityContext,std::shared_ptr<OHOS::AbilityRuntime::UIExtensionContext> & uiExtensionContext)215 bool PrintTask::ParseAbilityContextReq(napi_env env, const napi_value &obj,
216 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> &abilityContext,
217 std::shared_ptr<OHOS::AbilityRuntime::UIExtensionContext> &uiExtensionContext)
218 {
219 PRINT_HILOGD("begin ParseAbilityContextReq");
220 bool stageMode = false;
221 napi_status status = OHOS::AbilityRuntime::IsStageContext(env, obj, stageMode);
222 if (status != napi_ok || !stageMode) {
223 PRINT_HILOGE("it is not a stage mode");
224 return false;
225 }
226
227 auto context = OHOS::AbilityRuntime::GetStageModeContext(env, obj);
228 if (context == nullptr) {
229 PRINT_HILOGE("get context failed");
230 return false;
231 }
232
233 abilityContext = OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
234 if (abilityContext == nullptr) {
235 PRINT_HILOGE("get abilityContext failed");
236 uiExtensionContext =
237 OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::UIExtensionContext>(context);
238 if (uiExtensionContext == nullptr) {
239 PRINT_HILOGE("get uiExtensionContext failed");
240 return false;
241 }
242 }
243
244 PRINT_HILOGD("end ParseAbilityContextReq");
245 return true;
246 }
247
StartUIExtensionAbility(std::shared_ptr<BaseContext> asyncContext,const std::shared_ptr<AdapterParam> & adapterParam)248 uint32_t PrintTask::StartUIExtensionAbility(
249 std::shared_ptr<BaseContext> asyncContext, const std::shared_ptr<AdapterParam> &adapterParam)
250 {
251 PRINT_HILOGD("begin StartUIExtensionAbility");
252
253 if (adapterParam == nullptr) {
254 PRINT_HILOGE("adapterParam is nullptr.");
255 return E_PRINT_INVALID_PARAMETER;
256 }
257 if ((adapterParam->isCheckFdList && fileList_.empty() && fdList_.empty())) {
258 PRINT_HILOGE("to be printed filelist and fdlist are empty.");
259 return E_PRINT_INVALID_PARAMETER;
260 }
261 AAFwk::Want want;
262 want.SetElementName(SPOOLER_BUNDLE_NAME, SPOOLER_PREVIEW_ABILITY_NAME);
263 want.SetParam(LAUNCH_PARAMETER_JOB_ID, adapterParam->jobId);
264 if (fileList_.size() <= MAX_FILE_LIST_SIZE) {
265 want.SetParam(LAUNCH_PARAMETER_FILE_LIST, fileList_);
266 } else {
267 PRINT_HILOGW("fileList exceeds the maximum length.");
268 }
269 want.SetParam(LAUNCH_PARAMETER_FILE_LIST_SIZE, static_cast<int>(fileList_.size()));
270 PrintUtils::BuildAdapterParam(adapterParam, want);
271 int32_t callerTokenId = static_cast<int32_t>(IPCSkeleton::GetCallingTokenID());
272 int32_t callerUid = IPCSkeleton::GetCallingUid();
273 int32_t callerPid = IPCSkeleton::GetCallingPid();
274 std::string callerPkg = PrintUtils::GetBundleNameForUid(callerUid);
275 want.SetParam(AAFwk::Want::PARAM_RESV_CALLER_TOKEN, callerTokenId);
276 want.SetParam(AAFwk::Want::PARAM_RESV_CALLER_UID, callerUid);
277 want.SetParam(AAFwk::Want::PARAM_RESV_CALLER_PID, callerPid);
278 want.SetParam(CALLER_PKG_NAME, callerPkg);
279 want.SetParam(UI_EXTENSION_TYPE_NAME, PRINT_UI_EXTENSION_TYPE);
280 want.SetParam(ABILITY_PARAMS_STREAM, fileList_);
281 want.SetFlags(AAFwk::Want::FLAG_AUTH_READ_URI_PERMISSION);
282
283 uint32_t ret = StartUIExtensionAbility(want, asyncContext);
284 if (ret != E_PRINT_NONE) {
285 PRINT_HILOGE("StartUIExtensionAbility fail");
286 }
287 PRINT_HILOGD("end StartUIExtensionAbility");
288 return ret;
289 }
290
StartUIExtensionAbility(OHOS::AAFwk::Want & want,std::shared_ptr<BaseContext> asyncContext)291 uint32_t PrintTask::StartUIExtensionAbility(OHOS::AAFwk::Want &want, std::shared_ptr<BaseContext> asyncContext)
292 {
293 PRINT_HILOGI("begin StartUIExtensionAbility");
294 if (asyncContext == nullptr) {
295 PRINT_HILOGE("asyncContext is nullptr");
296 return E_PRINT_INVALID_PARAMETER;
297 }
298
299 if (asyncContext->context == nullptr && asyncContext->uiExtensionContext == nullptr) {
300 PRINT_HILOGE("asyncContext is nullptr");
301 return E_PRINT_INVALID_PARAMETER;
302 }
303
304 auto uiContent = GetUIContent(asyncContext.get());
305 if (uiContent == nullptr) {
306 PRINT_HILOGE("UIContent is nullptr");
307 return E_PRINT_INVALID_PARAMETER;
308 }
309
310 std::string info = uiContent->GetContentInfo();
311 auto callback = std::make_shared<PrintModalUICallback>(asyncContext);
312 if (callback == nullptr) {
313 PRINT_HILOGE("create callback failed.");
314 return E_PRINT_SERVER_FAILURE;
315 }
316 OHOS::Ace::ModalUIExtensionCallbacks extensionCallbacks = {
317 [callback](int32_t releaseCode) { callback->OnRelease(releaseCode); },
318 [callback](int32_t resultCode, const OHOS::AAFwk::Want& result) {
319 callback->OnResultForModal(resultCode, result);
320 },
321 [callback](const OHOS::AAFwk::WantParams& request) { callback->OnReceive(request); },
322 [callback](int32_t code, const std::string& name, const std::string& message) {
323 callback->OnError(code, name, message);
324 }
325 };
326
327 OHOS::Ace::ModalUIExtensionConfig config;
328 config.isProhibitBack = true;
329 int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallbacks, config);
330 PRINT_HILOGI("StartUIExtensionAbility sessionId %{public}d", sessionId);
331 callback->SetSessionId(sessionId);
332
333 PRINT_HILOGI("end StartUIExtensionAbility");
334 return E_PRINT_NONE;
335 }
336
GetUIContent(const BaseContext * asyncContext)337 OHOS::Ace::UIContent *PrintTask::GetUIContent(const BaseContext *asyncContext)
338 {
339 if (asyncContext == nullptr) {
340 PRINT_HILOGE("asyncContext is nullptr.");
341 return nullptr;
342 }
343 OHOS::Ace::UIContent *uiContent = nullptr;
344 if (asyncContext->context != nullptr) {
345 PRINT_HILOGI("get uiContext by ability context");
346 uiContent = asyncContext->context->GetUIContent();
347 } else if (asyncContext->uiExtensionContext != nullptr) {
348 PRINT_HILOGI("get uiContext by ui extension ability context");
349 uiContent = asyncContext->uiExtensionContext->GetUIContent();
350 } else {
351 PRINT_HILOGE("get uiContext failed.");
352 }
353
354 return uiContent;
355 }
356
CreateDefaultAdapterParam(const std::shared_ptr<AdapterParam> & adapterParam)357 void PrintTask::CreateDefaultAdapterParam(const std::shared_ptr<AdapterParam> &adapterParam)
358 {
359 adapterParam->documentName = "";
360 adapterParam->isCheckFdList = true;
361 }
362
Stop()363 void PrintTask::Stop()
364 {
365 PrintManagerClient::GetInstance()->StopPrint(taskId_);
366 taskId_ = "";
367 }
368
GetId() const369 const std::string &PrintTask::GetId() const
370 {
371 return taskId_;
372 }
373
On(napi_env env,napi_callback_info info)374 napi_value PrintTask::On(napi_env env, napi_callback_info info)
375 {
376 PRINT_HILOGD("Enter ---->");
377 size_t argc = NapiPrintUtils::MAX_ARGC;
378 napi_value argv[NapiPrintUtils::MAX_ARGC] = { nullptr };
379 napi_value thisVal = nullptr;
380 void *data = nullptr;
381 PRINT_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVal, &data));
382 PRINT_ASSERT(env, argc == NapiPrintUtils::ARGC_TWO, "need 2 parameter!");
383
384 napi_valuetype valuetype;
385 PRINT_CALL(env, napi_typeof(env, argv[0], &valuetype));
386 PRINT_ASSERT(env, valuetype == napi_string, "type is not a string");
387 std::string type = NapiPrintUtils::GetStringFromValueUtf8(env, argv[NapiPrintUtils::INDEX_ZERO]);
388 PRINT_HILOGD("type : %{public}s", type.c_str());
389
390 valuetype = napi_undefined;
391 napi_typeof(env, argv[1], &valuetype);
392 PRINT_ASSERT(env, valuetype == napi_function, "callback is not a function");
393
394 PrintTask *task;
395 PRINT_CALL(env, napi_unwrap(env, thisVal, reinterpret_cast<void **>(&task)));
396 if (task == nullptr || !task->IsSupportType(type)) {
397 PRINT_HILOGE("Event On type : %{public}s not support", type.c_str());
398 return nullptr;
399 }
400
401 napi_ref callbackRef = NapiPrintUtils::CreateReference(env, argv[1]);
402 sptr<IPrintCallback> callback = new (std::nothrow) PrintCallback(env, callbackRef);
403 if (callback == nullptr) {
404 PRINT_HILOGE("create print callback object fail");
405 return nullptr;
406 }
407 int32_t ret = PrintManagerClient::GetInstance()->On(task->taskId_, type, callback);
408 if (ret != E_PRINT_NONE) {
409 PRINT_HILOGE("Failed to register event");
410 return nullptr;
411 }
412 return nullptr;
413 }
414
Off(napi_env env,napi_callback_info info)415 napi_value PrintTask::Off(napi_env env, napi_callback_info info)
416 {
417 PRINT_HILOGD("Enter ---->");
418 auto context = std::make_shared<TaskEventContext>();
419 if (context == nullptr) {
420 PRINT_HILOGE("create context failed.");
421 return nullptr;
422 }
423 auto input =
424 [context](
425 napi_env env, size_t argc, napi_value *argv, napi_value self, napi_callback_info info) -> napi_status {
426 PRINT_ASSERT_BASE(env, argc == NapiPrintUtils::ARGC_ONE, "need 1 parameter!", napi_invalid_arg);
427 napi_valuetype valuetype;
428 PRINT_CALL_BASE(env, napi_typeof(env, argv[NapiPrintUtils::INDEX_ZERO], &valuetype), napi_invalid_arg);
429 PRINT_ASSERT_BASE(env, valuetype == napi_string, "type is not a string", napi_string_expected);
430 std::string type = NapiPrintUtils::GetStringFromValueUtf8(env, argv[0]);
431 PrintTask *task;
432 PRINT_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast<void **>(&task)), napi_invalid_arg);
433 if (task == nullptr || !task->IsSupportType(type)) {
434 PRINT_HILOGE("Event On type : %{public}s not support", type.c_str());
435 context->SetErrorIndex(E_PRINT_INVALID_PARAMETER);
436 return napi_invalid_arg;
437 }
438
439 context->type = type;
440 context->taskId = task->taskId_;
441 PRINT_HILOGD("event type : %{public}s", context->type.c_str());
442 return napi_ok;
443 };
444 auto output = [context](napi_env env, napi_value *result) -> napi_status {
445 napi_status status = napi_get_boolean(env, context->result, result);
446 PRINT_HILOGD("context->result = %{public}d", context->result);
447 return status;
448 };
449 auto exec = [context](PrintAsyncCall::Context *ctx) {
450 int32_t ret = PrintManagerClient::GetInstance()->Off(context->taskId, context->type);
451 context->result = ret == E_PRINT_NONE;
452 if (ret != E_PRINT_NONE) {
453 PRINT_HILOGE("Failed to unregistered event");
454 context->SetErrorIndex(ret);
455 }
456 };
457 context->SetAction(std::move(input), std::move(output));
458 PrintAsyncCall asyncCall(env, info, std::dynamic_pointer_cast<PrintAsyncCall::Context>(context));
459 return asyncCall.Call(env, exec);
460 }
461
IsSupportType(const std::string & type) const462 bool PrintTask::IsSupportType(const std::string &type) const
463 {
464 return supportEvents_.find(type) != supportEvents_.end();
465 }
466
CheckPermission(const std::string & name)467 bool PrintTask::CheckPermission(const std::string &name)
468 {
469 AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
470 TypeATokenTypeEnum tokenType = AccessTokenKit::GetTokenTypeFlag(tokenId);
471 if (tokenType == TOKEN_INVALID) {
472 PRINT_HILOGE("invalid token id %{public}d", tokenId);
473 return false;
474 }
475 int result = AccessTokenKit::VerifyAccessToken(tokenId, name);
476 if (result != PERMISSION_GRANTED) {
477 PRINT_HILOGE("Current tokenId permission is %{public}d", result);
478 }
479 return result == PERMISSION_GRANTED;
480 }
481 } // namespace OHOS::Print
482