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