• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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