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 <mutex>
17 #include "napi_base_context.h"
18 #include "napi_print_utils.h"
19 #include "print_async_call.h"
20 #include "print_log.h"
21 #include "print_manager_client.h"
22 #include "print_task.h"
23 #include "napi_print_task.h"
24 #include "print_attributes_helper.h"
25 #include "print_callback.h"
26 #include "iprint_callback.h"
27
28 static constexpr const char *FUNCTION_ON = "on";
29 static constexpr const char *FUNCTION_OFF = "off";
30
31 namespace OHOS::Print {
32 __thread napi_ref NapiPrintTask::globalCtor = nullptr;
33
Print(napi_env env,napi_callback_info info)34 napi_value NapiPrintTask::Print(napi_env env, napi_callback_info info)
35 {
36 PRINT_HILOGD("Enter print JsMain.");
37 napi_value argv[NapiPrintUtils::MAX_ARGC] = { nullptr };
38 size_t paramCount = NapiPrintUtils::GetJsVal(env, info, argv, NapiPrintUtils::MAX_ARGC);
39 napi_valuetype type;
40 PRINT_CALL(env, napi_typeof(env, argv[0], &type));
41 if ((paramCount > NapiPrintUtils::ARGC_THREE) && type == napi_string) {
42 return PrintByAdapter(env, info);
43 }
44 return CreatePrintTask(env, info);
45 }
46
CreatePrintTask(napi_env env,napi_callback_info info)47 napi_value NapiPrintTask::CreatePrintTask(napi_env env, napi_callback_info info)
48 {
49 PRINT_HILOGI("CreatePrintTask start ---->");
50 auto context = std::make_shared<PrintTaskContext>();
51 auto input = [context](
52 napi_env env, size_t argc, napi_value *argv, napi_value self, napi_callback_info info) -> napi_status {
53 PRINT_ASSERT_BASE(env, argc == NapiPrintUtils::ARGC_ONE || argc == NapiPrintUtils::ARGC_TWO,
54 "need 1 or 2 parameter!", napi_invalid_arg);
55 napi_status checkStatus = VerifyParameters(env, argc, argv, context);
56 if (argc == NapiPrintUtils::ARGC_TWO && checkStatus != napi_ok) {
57 return checkStatus;
58 }
59
60 napi_value proxy = nullptr;
61 napi_status status = napi_new_instance(env, GetCtor(env), argc, argv, &proxy);
62 if ((proxy == nullptr) || (status != napi_ok)) {
63 PRINT_HILOGE("Failed to create print task");
64 context->SetErrorIndex(E_PRINT_GENERIC_FAILURE);
65 }
66
67 PrintTask *task;
68 PRINT_CALL_BASE(env, napi_unwrap(env, proxy, reinterpret_cast<void **>(&task)), napi_invalid_arg);
69 uint32_t ret = E_PRINT_GENERIC_FAILURE;
70 if (task != nullptr) {
71 ret = task->Start(env, info);
72 }
73 if ((argc == NapiPrintUtils::ARGC_ONE || argc == NapiPrintUtils::ARGC_TWO) && ret != E_PRINT_NONE) {
74 PRINT_HILOGE("Failed to start print task");
75 context->SetErrorIndex(ret);
76 }
77 napi_create_reference(env, proxy, 1, &(context->ref));
78 return napi_ok;
79 };
80 auto output = [context](napi_env env, napi_value *result) -> napi_status {
81 if (context->ref == nullptr) {
82 *result = NapiPrintUtils::GetUndefined(env);
83 return napi_generic_failure;
84 }
85 napi_status status = napi_get_reference_value(env, context->ref, result);
86 napi_delete_reference(env, context->ref);
87 return status;
88 };
89 context->SetAction(std::move(input), std::move(output));
90 PrintAsyncCall asyncCall(env, info, std::dynamic_pointer_cast<PrintAsyncCall::Context>(context));
91 return asyncCall.Call(env);
92 }
93
PrintByAdapter(napi_env env,napi_callback_info info)94 napi_value NapiPrintTask::PrintByAdapter(napi_env env, napi_callback_info info)
95 {
96 PRINT_HILOGI("PrintByAdapter start ---->");
97 auto context = std::make_shared<PrintTaskContext>();
98 auto input =
99 [context](
100 napi_env env, size_t argc, napi_value *argv, napi_value self, napi_callback_info info) -> napi_status {
101 PRINT_ASSERT_BASE(env, argc == NapiPrintUtils::ARGC_FOUR, "need 4 parameter!", napi_invalid_arg);
102 napi_status checkStatus = VerifyParameters(env, argc, argv, context);
103 if (checkStatus != napi_ok) {
104 return checkStatus;
105 }
106
107 napi_value proxy = nullptr;
108 napi_status status = napi_new_instance(env, GetCtor(env), argc, argv, &proxy);
109 if ((proxy == nullptr) || (status != napi_ok)) {
110 PRINT_HILOGE("Failed to create print task");
111 context->SetErrorIndex(E_PRINT_GENERIC_FAILURE);
112 return napi_generic_failure;
113 }
114
115 PrintTask *task;
116 PRINT_CALL_BASE(env, napi_unwrap(env, proxy, reinterpret_cast<void **>(&task)), napi_invalid_arg);
117 uint32_t ret = E_PRINT_GENERIC_FAILURE;
118 if (task != nullptr) {
119 ret = task->StartPrintAdapter(env, info);
120 }
121 if (ret != E_PRINT_NONE) {
122 PRINT_HILOGE("Failed to start print task");
123 context->SetErrorIndex(ret);
124 }
125 napi_create_reference(env, proxy, 1, &(context->ref));
126 return napi_ok;
127 };
128 auto output = [context](napi_env env, napi_value *result) -> napi_status {
129 if (context->ref == nullptr) {
130 *result = NapiPrintUtils::GetUndefined(env);
131 return napi_generic_failure;
132 }
133 napi_status status = napi_get_reference_value(env, context->ref, result);
134 napi_delete_reference(env, context->ref);
135 return status;
136 };
137 context->SetAction(std::move(input), std::move(output));
138 PrintAsyncCall asyncCall(env, info, std::dynamic_pointer_cast<PrintAsyncCall::Context>(context));
139 return asyncCall.Call(env);
140 }
141
ParsePrintAdapterParameter(napi_env env,size_t argc,napi_value * argv,napi_value self)142 napi_value NapiPrintTask::ParsePrintAdapterParameter(napi_env env, size_t argc, napi_value *argv, napi_value self)
143 {
144 if (argc > NapiPrintUtils::ARGC_THREE) {
145 std::string printJobName = NapiPrintUtils::GetStringFromValueUtf8(env, argv[0]);
146
147 std::shared_ptr<PrintAttributes> printAttributes =
148 PrintAttributesHelper::BuildFromJs(env, argv[NapiPrintUtils::ARGC_TWO]);
149 if (printAttributes == nullptr) {
150 PRINT_HILOGE("printAdapter parameter error");
151 return nullptr;
152 }
153
154 napi_ref adapterRef = NapiPrintUtils::CreateReference(env, argv[1]);
155 sptr<IPrintCallback> callback = new (std::nothrow) PrintCallback(env, adapterRef);
156 if (callback == nullptr) {
157 PRINT_HILOGE("callback parameter error");
158 NapiPrintUtils::DeleteReference(env, adapterRef);
159 return nullptr;
160 }
161
162 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext;
163 sptr<IRemoteObject> callerToken = nullptr;
164 if (GetAbilityContext(env, argv[NapiPrintUtils::ARGC_THREE], abilityContext) != nullptr) {
165 if (abilityContext != nullptr) {
166 callerToken = abilityContext->GetToken();
167 }
168 }
169 auto task = new (std::nothrow) PrintTask(printJobName, callback, printAttributes, callerToken);
170
171 if (task == nullptr) {
172 PRINT_HILOGE("print task fail"); // callback结束时自动释放adapterRef
173 return nullptr;
174 }
175 auto finalize = [](napi_env env, void *data, void *hint) {
176 PRINT_HILOGD("destructed print task");
177 PrintTask *task = reinterpret_cast<PrintTask *>(data);
178 delete task;
179 };
180 if (napi_wrap(env, self, task, finalize, nullptr, nullptr) != napi_ok) {
181 finalize(env, task, nullptr); // finalize里释放了tack,然后函数走完后释放callback,callback中自动释放adapterRef
182 return nullptr;
183 }
184 PRINT_HILOGD("Succeed to allocate print task");
185 return self;
186 }
187 return nullptr;
188 }
189
GetAbilityContext(napi_env env,napi_value value,std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> & abilityContext)190 napi_value NapiPrintTask::GetAbilityContext(
191 napi_env env, napi_value value, std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> &abilityContext)
192 {
193 bool stageMode = false;
194 napi_status status = OHOS::AbilityRuntime::IsStageContext(env, value, stageMode);
195 if (status != napi_ok || !stageMode) {
196 PRINT_HILOGE("GetAbilityContext it is not a stage mode");
197 return nullptr;
198 } else {
199 auto context = OHOS::AbilityRuntime::GetStageModeContext(env, value);
200 if (context == nullptr) {
201 PRINT_HILOGE("GetAbilityContext get context failed");
202 return nullptr;
203 }
204 abilityContext = OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
205 if (abilityContext == nullptr) {
206 PRINT_HILOGE("GetAbilityContext get Stage model ability context failed.");
207 }
208 return WrapVoidToJS(env);
209 }
210 }
211
WrapVoidToJS(napi_env env)212 napi_value NapiPrintTask::WrapVoidToJS(napi_env env)
213 {
214 napi_value result = nullptr;
215 NAPI_CALL(env, napi_get_null(env, &result));
216 return result;
217 }
218
GetCtor(napi_env env)219 napi_value NapiPrintTask::GetCtor(napi_env env)
220 {
221 napi_value cons;
222 if (globalCtor != nullptr) {
223 PRINT_CALL(env, napi_get_reference_value(env, globalCtor, &cons));
224 return cons;
225 }
226
227 napi_property_descriptor clzDes[] = {
228 { FUNCTION_ON, 0, PrintTask::On, 0, 0, 0, napi_default, 0 },
229 { FUNCTION_OFF, 0, PrintTask::Off, 0, 0, 0, napi_default, 0 },
230 };
231 PRINT_CALL(env, napi_define_class(env, "NapiPrintTask", NAPI_AUTO_LENGTH, Initialize, nullptr,
232 sizeof(clzDes) / sizeof(napi_property_descriptor), clzDes, &cons));
233 PRINT_CALL(env, napi_create_reference(env, cons, 1, &globalCtor));
234 return cons;
235 }
236
Initialize(napi_env env,napi_callback_info info)237 napi_value NapiPrintTask::Initialize(napi_env env, napi_callback_info info)
238 {
239 PRINT_HILOGD("constructor print task!");
240 napi_value self = nullptr;
241 size_t argc = NapiPrintUtils::MAX_ARGC;
242 napi_value argv[NapiPrintUtils::MAX_ARGC] = { nullptr };
243 PRINT_CALL(env, napi_get_cb_info(env, info, &argc, argv, &self, nullptr));
244
245 if (argc > NapiPrintUtils::ARGC_THREE) {
246 return ParsePrintAdapterParameter(env, argc, argv, self);
247 } else {
248 std::vector<std::string> printfiles;
249 uint32_t arrayReLength = 0;
250 PRINT_CALL(env, napi_get_array_length(env, argv[0], &arrayReLength));
251 for (uint32_t index = 0; index < arrayReLength; index++) {
252 napi_value filesValue;
253 napi_get_element(env, argv[0], index, &filesValue);
254 std::string files = NapiPrintUtils::GetStringFromValueUtf8(env, filesValue);
255 PRINT_HILOGD("file[%{public}d] %{private}s.", index, files.c_str());
256 if (IsValidFile(files)) {
257 printfiles.emplace_back(files);
258 }
259 }
260
261 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext;
262 sptr<IRemoteObject> callerToken;
263 if (argc == NapiPrintUtils::ARGC_TWO && GetAbilityContext(env, argv[1], abilityContext) != nullptr) {
264 if (abilityContext != nullptr) {
265 callerToken = abilityContext->GetToken();
266 }
267 PRINT_HILOGI("get callerToken:%{public}s", callerToken != nullptr ? "success" : "failed");
268 }
269 auto task = new (std::nothrow) PrintTask(printfiles, callerToken);
270 if (task == nullptr) {
271 PRINT_HILOGE("print task fail");
272 return nullptr;
273 }
274 auto finalize = [](napi_env env, void *data, void *hint) {
275 PRINT_HILOGD("destructed print task");
276 PrintTask *task = reinterpret_cast<PrintTask *>(data);
277 delete task;
278 };
279 if (napi_wrap(env, self, task, finalize, nullptr, nullptr) != napi_ok) {
280 finalize(env, task, nullptr);
281 return nullptr;
282 }
283 PRINT_HILOGD("Succeed to allocate print task");
284 return self;
285 }
286 }
287
IsValidFile(const std::string & fileName)288 bool NapiPrintTask::IsValidFile(const std::string &fileName)
289 {
290 if (fileName == "") {
291 PRINT_HILOGE("invalid file name");
292 return false;
293 }
294 auto file = fopen(fileName.c_str(), "rb");
295 if (file != nullptr) {
296 int fcloseResult = fclose(file);
297 if (fcloseResult != 0) {
298 PRINT_HILOGE("Close File Failure.");
299 return false;
300 }
301 return true;
302 }
303 PRINT_HILOGD("fileName: %{public}s", fileName.c_str());
304 if (fileName.find("file://") == 0 || fileName.find("fd://") == 0 || fileName.find("content://") == 0) {
305 return true;
306 }
307 PRINT_HILOGE("invalid file name");
308 return false;
309 }
310
VerifyParameters(napi_env env,size_t argc,napi_value * argv,const std::shared_ptr<PrintTaskContext> context)311 napi_status NapiPrintTask::VerifyParameters(napi_env env, size_t argc, napi_value *argv,
312 const std::shared_ptr<PrintTaskContext> context)
313 {
314 if (argc > NapiPrintUtils::ARGC_THREE) {
315 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext;
316 if (GetAbilityContext(env, argv[NapiPrintUtils::ARGC_THREE], abilityContext) == nullptr) {
317 PRINT_HILOGE("Print adapter Ability Context is null.");
318 context->SetErrorIndex(E_PRINT_INVALID_PARAMETER);
319 }
320 return napi_ok;
321 }
322
323 bool isFileArray = false;
324
325 napi_is_array(env, argv[0], &isFileArray);
326 PRINT_ASSERT_BASE(env, isFileArray == true, "parameter type isn't list", napi_invalid_arg);
327
328 uint32_t len = 0;
329 PRINT_CALL_BASE(env, napi_get_array_length(env, argv[0], &len), napi_invalid_arg);
330
331 if (!isFileArray || len == 0) {
332 context->SetErrorIndex(E_PRINT_INVALID_PARAMETER);
333 return napi_invalid_arg;
334 }
335
336 std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> abilityContext;
337 if (argc == NapiPrintUtils::ARGC_TWO) {
338 if (GetAbilityContext(env, argv[1], abilityContext) == nullptr) {
339 PRINT_HILOGE("Print, Ability Context is null.");
340 }
341 }
342 return napi_ok;
343 }
344 } // namespace OHOS::Print
345