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.begin()->find("fd://") == 0) {
50 PRINT_HILOGD("list type: fdlist");
51 for (auto fdPath : innerList) {
52 pathType_ = FD_PATH;
53 uint32_t fd = PrintUtils::GetIdFromFdPath(fdPath);
54 fdList_.emplace_back(fd);
55 }
56 } else {
57 PRINT_HILOGD("list type: filelist");
58 fileList_.assign(innerList.begin(), innerList.end());
59 pathType_ = FILE_PATH_ABSOLUTED;
60 if (fileList_.size() > 0) {
61 if (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 return E_PRINT_INVALID_PARAMETER;
106 }
107 fdList_.emplace_back(fd);
108 }
109 }
110
111 PRINT_HILOGI("call client's StartPrint interface.");
112 std::shared_ptr<AdapterParam> adapterParam = std::make_shared<AdapterParam>();
113 CreateDefaultAdapterParam(adapterParam);
114 std::string jobId = PrintUtils::GetPrintJobId();
115 adapterParam->jobId = jobId;
116 taskId_ = jobId;
117 uint32_t ret = CallSpooler(env, info, adapterParam, false);
118 if (ret != E_PRINT_NONE) {
119 PRINT_HILOGE("CallSpooler failed.");
120 return ret;
121 }
122 return PrintManagerClient::GetInstance()->StartPrint(fileList_, fdList_, taskId_);
123 }
124
StartPrintAdapter(napi_env env,napi_callback_info info)125 uint32_t PrintTask::StartPrintAdapter(napi_env env, napi_callback_info info)
126 {
127 if (printAdapterCallback_ != nullptr && printAttributes_ != nullptr) {
128 PRINT_HILOGI("call client's StartPrintAdapter interface.");
129 if (callerToken_ != nullptr) {
130 std::shared_ptr<AdapterParam> adapterParam = std::make_shared<AdapterParam>();
131 if (adapterParam == nullptr) {
132 PRINT_HILOGE("create adapterParam failed.");
133 return E_PRINT_SERVER_FAILURE;
134 }
135 adapterParam->documentName = printJobName_;
136 adapterParam->isCheckFdList = false;
137 adapterParam->printAttributes = *printAttributes_;
138 std::string jobId = PrintUtils::GetPrintJobId();
139 adapterParam->jobId = jobId;
140 taskId_ = jobId;
141 uint32_t ret = CallSpooler(env, info, adapterParam, true);
142 if (ret != E_PRINT_NONE) {
143 PRINT_HILOGE("CallSpooler failed.");
144 }
145 return PrintManagerClient::GetInstance()->Print(
146 printJobName_, printAdapterCallback_, *printAttributes_, taskId_, callerToken_);
147 }
148 }
149 return E_PRINT_INVALID_PARAMETER;
150 }
151
CallSpooler(napi_env env,napi_callback_info info,const std::shared_ptr<AdapterParam> & adapterParam,bool isPrintByAdapter)152 uint32_t PrintTask::CallSpooler(
153 napi_env env, napi_callback_info info, const std::shared_ptr<AdapterParam> &adapterParam, bool isPrintByAdapter)
154 {
155 PRINT_HILOGI("enter CallSpooler.");
156 if (!CheckPermission(PERMISSION_NAME_PRINT)) {
157 PRINT_HILOGE("no permission to access print service, ErrorCode:[%{public}d]", E_PRINT_NO_PERMISSION);
158 return E_PRINT_NO_PERMISSION;
159 }
160 size_t argc = isPrintByAdapter ? NapiPrintUtils::ARGC_FOUR : NapiPrintUtils::ARGC_TWO;
161 size_t contextIndex = isPrintByAdapter ? NapiPrintUtils::INDEX_THREE : NapiPrintUtils::INDEX_ONE;
162 size_t callBackIndex = isPrintByAdapter ? NapiPrintUtils::INDEX_FOUR : NapiPrintUtils::INDEX_TWO;
163 size_t argMaxNum = isPrintByAdapter ? NapiPrintUtils::ARGC_FIVE : NapiPrintUtils::ARGC_THREE;
164 napi_value argv[NapiPrintUtils::ARGC_FOUR] = {0};
165 napi_value thisArg = nullptr;
166 void *data = nullptr;
167 napi_value result = nullptr;
168
169 PRINT_CALL_BASE(env, napi_get_undefined(env, &result), E_PRINT_INVALID_PARAMETER);
170 PRINT_CALL_BASE(env, napi_get_cb_info(env, info, &argc, argv, &thisArg, &data), E_PRINT_INVALID_PARAMETER);
171 PRINT_HILOGI("CallSpooler params size: %{public}zu", argc);
172 if (argc < argMaxNum - 1) {
173 PRINT_HILOGE("invalid parameters.");
174 return E_PRINT_INVALID_PARAMETER;
175 }
176
177 auto asyncContext = std::make_shared<BaseContext>();
178 if (asyncContext == nullptr) {
179 PRINT_HILOGE("create asyncContext failed.");
180 return E_PRINT_SERVER_FAILURE;
181 }
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 uint32_t ret = StartUIExtensionAbility(asyncContext, adapterParam);
202 PRINT_HILOGI("end CallSpooler");
203 return ret;
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 uint32_t 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 E_PRINT_INVALID_PARAMETER;
247 }
248 if ((adapterParam->isCheckFdList && fileList_.empty() && fdList_.empty())) {
249 PRINT_HILOGE("to be printed filelist and fdlist are empty.");
250 return E_PRINT_INVALID_PARAMETER;
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 uint32_t ret = StartUIExtensionAbility(want, asyncContext);
270 if (ret != E_PRINT_NONE) {
271 PRINT_HILOGE("StartUIExtensionAbility fail");
272 }
273 PRINT_HILOGD("end StartUIExtensionAbility");
274 return ret;
275 }
276
StartUIExtensionAbility(OHOS::AAFwk::Want & want,std::shared_ptr<BaseContext> asyncContext)277 uint32_t PrintTask::StartUIExtensionAbility(OHOS::AAFwk::Want &want, std::shared_ptr<BaseContext> asyncContext)
278 {
279 PRINT_HILOGI("begin StartUIExtensionAbility");
280 if (asyncContext == nullptr) {
281 PRINT_HILOGE("asyncContext is nullptr");
282 return E_PRINT_INVALID_PARAMETER;
283 }
284
285 if (asyncContext->context == nullptr && asyncContext->uiExtensionContext == nullptr) {
286 PRINT_HILOGE("asyncContext is nullptr");
287 return E_PRINT_INVALID_PARAMETER;
288 }
289
290 auto uiContent = GetUIContent(asyncContext.get());
291 if (uiContent == nullptr) {
292 PRINT_HILOGE("UIContent is nullptr");
293 return E_PRINT_INVALID_PARAMETER;
294 }
295
296 std::string info = uiContent->GetContentInfo();
297 auto callback = std::make_shared<PrintModalUICallback>(asyncContext);
298 if (callback == nullptr) {
299 PRINT_HILOGE("create callback failed.");
300 return E_PRINT_SERVER_FAILURE;
301 }
302 OHOS::Ace::ModalUIExtensionCallbacks extensionCallbacks = {
303 [callback](int32_t releaseCode) { callback->OnRelease(releaseCode); },
304 [callback](int32_t resultCode, const OHOS::AAFwk::Want& result) {
305 callback->OnResultForModal(resultCode, result);
306 },
307 [callback](const OHOS::AAFwk::WantParams& request) { callback->OnReceive(request); },
308 [callback](int32_t code, const std::string& name, const std::string& message) {
309 callback->OnError(code, name, message);
310 }
311 };
312
313 OHOS::Ace::ModalUIExtensionConfig config;
314 config.isProhibitBack = true;
315 int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallbacks, config);
316 PRINT_HILOGI("StartUIExtensionAbility sessionId %{public}d", sessionId);
317 callback->SetSessionId(sessionId);
318
319 PRINT_HILOGI("end StartUIExtensionAbility");
320 return E_PRINT_NONE;
321 }
322
GetUIContent(const BaseContext * asyncContext)323 OHOS::Ace::UIContent *PrintTask::GetUIContent(const BaseContext *asyncContext)
324 {
325 if (asyncContext == nullptr) {
326 PRINT_HILOGE("asyncContext is nullptr.");
327 return nullptr;
328 }
329 OHOS::Ace::UIContent *uiContent = nullptr;
330 if (asyncContext->context != nullptr) {
331 PRINT_HILOGI("get uiContext by ability context");
332 uiContent = asyncContext->context->GetUIContent();
333 } else if (asyncContext->uiExtensionContext != nullptr) {
334 PRINT_HILOGI("get uiContext by ui extension ability context");
335 uiContent = asyncContext->uiExtensionContext->GetUIContent();
336 } else {
337 PRINT_HILOGE("get uiContext failed.");
338 }
339
340 return uiContent;
341 }
342
CreateDefaultAdapterParam(const std::shared_ptr<AdapterParam> & adapterParam)343 void PrintTask::CreateDefaultAdapterParam(const std::shared_ptr<AdapterParam> &adapterParam)
344 {
345 adapterParam->documentName = "";
346 adapterParam->isCheckFdList = true;
347 }
348
Stop()349 void PrintTask::Stop()
350 {
351 PrintManagerClient::GetInstance()->StopPrint(taskId_);
352 taskId_ = "";
353 }
354
GetId() const355 const std::string &PrintTask::GetId() const
356 {
357 return taskId_;
358 }
359
On(napi_env env,napi_callback_info info)360 napi_value PrintTask::On(napi_env env, napi_callback_info info)
361 {
362 PRINT_HILOGD("Enter ---->");
363 size_t argc = NapiPrintUtils::MAX_ARGC;
364 napi_value argv[NapiPrintUtils::MAX_ARGC] = { nullptr };
365 napi_value thisVal = nullptr;
366 void *data = nullptr;
367 PRINT_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVal, &data));
368 PRINT_ASSERT(env, argc == NapiPrintUtils::ARGC_TWO, "need 2 parameter!");
369
370 napi_valuetype valuetype;
371 PRINT_CALL(env, napi_typeof(env, argv[0], &valuetype));
372 PRINT_ASSERT(env, valuetype == napi_string, "type is not a string");
373 std::string type = NapiPrintUtils::GetStringFromValueUtf8(env, argv[NapiPrintUtils::INDEX_ZERO]);
374 PRINT_HILOGD("type : %{public}s", type.c_str());
375
376 valuetype = napi_undefined;
377 napi_typeof(env, argv[1], &valuetype);
378 PRINT_ASSERT(env, valuetype == napi_function, "callback is not a function");
379
380 PrintTask *task;
381 PRINT_CALL(env, napi_unwrap(env, thisVal, reinterpret_cast<void **>(&task)));
382 if (task == nullptr || !task->IsSupportType(type)) {
383 PRINT_HILOGE("Event On type : %{public}s not support", type.c_str());
384 return nullptr;
385 }
386
387 napi_ref callbackRef = NapiPrintUtils::CreateReference(env, argv[1]);
388 sptr<IPrintCallback> callback = new (std::nothrow) PrintCallback(env, callbackRef);
389 if (callback == nullptr) {
390 PRINT_HILOGE("create print callback object fail");
391 return nullptr;
392 }
393 int32_t ret = PrintManagerClient::GetInstance()->On(task->taskId_, type, callback);
394 if (ret != E_PRINT_NONE) {
395 PRINT_HILOGE("Failed to register event");
396 return nullptr;
397 }
398 return nullptr;
399 }
400
Off(napi_env env,napi_callback_info info)401 napi_value PrintTask::Off(napi_env env, napi_callback_info info)
402 {
403 PRINT_HILOGD("Enter ---->");
404 auto context = std::make_shared<TaskEventContext>();
405 if (context == nullptr) {
406 PRINT_HILOGE("create context failed.");
407 return nullptr;
408 }
409 auto input =
410 [context](
411 napi_env env, size_t argc, napi_value *argv, napi_value self, napi_callback_info info) -> napi_status {
412 PRINT_ASSERT_BASE(env, argc == NapiPrintUtils::ARGC_ONE, "need 1 parameter!", napi_invalid_arg);
413 napi_valuetype valuetype;
414 PRINT_CALL_BASE(env, napi_typeof(env, argv[NapiPrintUtils::INDEX_ZERO], &valuetype), napi_invalid_arg);
415 PRINT_ASSERT_BASE(env, valuetype == napi_string, "type is not a string", napi_string_expected);
416 std::string type = NapiPrintUtils::GetStringFromValueUtf8(env, argv[0]);
417 PrintTask *task;
418 PRINT_CALL_BASE(env, napi_unwrap(env, self, reinterpret_cast<void **>(&task)), napi_invalid_arg);
419 if (task == nullptr || !task->IsSupportType(type)) {
420 PRINT_HILOGE("Event On type : %{public}s not support", type.c_str());
421 context->SetErrorIndex(E_PRINT_INVALID_PARAMETER);
422 return napi_invalid_arg;
423 }
424
425 context->type = type;
426 context->taskId = task->taskId_;
427 PRINT_HILOGD("event type : %{public}s", context->type.c_str());
428 return napi_ok;
429 };
430 auto output = [context](napi_env env, napi_value *result) -> napi_status {
431 napi_status status = napi_get_boolean(env, context->result, result);
432 PRINT_HILOGD("context->result = %{public}d", context->result);
433 return status;
434 };
435 auto exec = [context](PrintAsyncCall::Context *ctx) {
436 int32_t ret = PrintManagerClient::GetInstance()->Off(context->taskId, context->type);
437 context->result = ret == E_PRINT_NONE;
438 if (ret != E_PRINT_NONE) {
439 PRINT_HILOGE("Failed to unregistered event");
440 context->SetErrorIndex(ret);
441 }
442 };
443 context->SetAction(std::move(input), std::move(output));
444 PrintAsyncCall asyncCall(env, info, std::dynamic_pointer_cast<PrintAsyncCall::Context>(context));
445 return asyncCall.Call(env, exec);
446 }
447
IsSupportType(const std::string & type) const448 bool PrintTask::IsSupportType(const std::string &type) const
449 {
450 return supportEvents_.find(type) != supportEvents_.end();
451 }
452
CheckPermission(const std::string & name)453 bool PrintTask::CheckPermission(const std::string &name)
454 {
455 AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
456 TypeATokenTypeEnum tokenType = AccessTokenKit::GetTokenTypeFlag(tokenId);
457 if (tokenType == TOKEN_INVALID) {
458 PRINT_HILOGE("invalid token id %{public}d", tokenId);
459 return false;
460 }
461 int result = AccessTokenKit::VerifyAccessToken(tokenId, name);
462 if (result != PERMISSION_GRANTED) {
463 PRINT_HILOGE("Current tokenId permission is %{public}d", result);
464 }
465 return result == PERMISSION_GRANTED;
466 }
467 } // namespace OHOS::Print
468