1 /*
2  * Copyright (c) 2023 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 "js_task.h"
17 
18 #include <securec.h>
19 #include <sys/stat.h>
20 
21 #include <chrono>
22 #include <cstring>
23 #include <filesystem>
24 #include <mutex>
25 
26 #include "app_state_callback.h"
27 #include "async_call.h"
28 #include "js_initialize.h"
29 #include "legacy/request_manager.h"
30 #include "log.h"
31 #include "napi_base_context.h"
32 #include "napi_utils.h"
33 #include "request_event.h"
34 #include "request_manager.h"
35 #include "storage_acl.h"
36 #include "upload/upload_task_napiV5.h"
37 
38 using namespace OHOS::StorageDaemon;
39 namespace fs = std::filesystem;
40 namespace OHOS::Request {
41 constexpr int64_t MILLISECONDS_IN_ONE_DAY = 24 * 60 * 60 * 1000;
42 std::mutex JsTask::createMutex_;
43 thread_local napi_ref JsTask::createCtor = nullptr;
44 std::mutex JsTask::requestMutex_;
45 thread_local napi_ref JsTask::requestCtor = nullptr;
46 std::mutex JsTask::requestFileMutex_;
47 thread_local napi_ref JsTask::requestFileCtor = nullptr;
48 std::mutex JsTask::getTaskCreateMutex_;
49 thread_local napi_ref JsTask::getTaskCreateCtor = nullptr;
50 std::mutex JsTask::taskMutex_;
51 std::map<std::string, JsTask *> JsTask::taskMap_;
52 bool JsTask::register_ = false;
53 std::mutex JsTask::pathMutex_;
54 std::map<std::string, int32_t> JsTask::pathMap_;
55 std::map<std::string, int32_t> JsTask::fileMap_;
56 std::mutex JsTask::taskContextMutex_;
57 std::map<std::string, std::shared_ptr<JsTask::ContextInfo>> JsTask::taskContextMap_;
58 
59 napi_property_descriptor clzDes[] = {
60     DECLARE_NAPI_FUNCTION(FUNCTION_ON, RequestEvent::On),
61     DECLARE_NAPI_FUNCTION(FUNCTION_OFF, RequestEvent::Off),
62     DECLARE_NAPI_FUNCTION(FUNCTION_START, RequestEvent::Start),
63     DECLARE_NAPI_FUNCTION(FUNCTION_PAUSE, RequestEvent::Pause),
64     DECLARE_NAPI_FUNCTION(FUNCTION_RESUME, RequestEvent::Resume),
65     DECLARE_NAPI_FUNCTION(FUNCTION_STOP, RequestEvent::Stop),
66 };
67 
68 napi_property_descriptor clzDesV9[] = {
69     DECLARE_NAPI_FUNCTION(FUNCTION_ON, RequestEvent::On),
70     DECLARE_NAPI_FUNCTION(FUNCTION_OFF, RequestEvent::Off),
71     DECLARE_NAPI_FUNCTION(FUNCTION_SUSPEND, RequestEvent::Pause),
72     DECLARE_NAPI_FUNCTION(FUNCTION_GET_TASK_INFO, RequestEvent::Query),
73     DECLARE_NAPI_FUNCTION(FUNCTION_GET_TASK_MIME_TYPE, RequestEvent::QueryMimeType),
74     DECLARE_NAPI_FUNCTION(FUNCTION_DELETE, RequestEvent::Remove),
75     DECLARE_NAPI_FUNCTION(FUNCTION_RESTORE, RequestEvent::Resume),
76     DECLARE_NAPI_FUNCTION(FUNCTION_PAUSE, RequestEvent::Pause),
77     DECLARE_NAPI_FUNCTION(FUNCTION_QUERY, RequestEvent::Query),
78     DECLARE_NAPI_FUNCTION(FUNCTION_QUERY_MIME_TYPE, RequestEvent::QueryMimeType),
79     DECLARE_NAPI_FUNCTION(FUNCTION_REMOVE, RequestEvent::Remove),
80     DECLARE_NAPI_FUNCTION(FUNCTION_RESUME, RequestEvent::Resume),
81 };
82 
~JsTask()83 JsTask::~JsTask()
84 {
85     REQUEST_HILOGD("~JsTask()");
86 }
JsUpload(napi_env env,napi_callback_info info)87 napi_value JsTask::JsUpload(napi_env env, napi_callback_info info)
88 {
89     int32_t seq = RequestManager::GetInstance()->GetNextSeq();
90     REQUEST_HILOGI("JsUpload seq %{public}d", seq);
91     std::shared_ptr<Upload::UploadTaskNapiV5> proxy = std::make_shared<Upload::UploadTaskNapiV5>(env);
92     if (proxy->ParseCallback(env, info)) {
93         return proxy->JsUpload(env, info);
94     }
95     proxy->SetEnv(nullptr);
96 
97     return JsMain(env, info, Version::API8, seq);
98 }
99 
JsDownload(napi_env env,napi_callback_info info)100 napi_value JsTask::JsDownload(napi_env env, napi_callback_info info)
101 {
102     int32_t seq = RequestManager::GetInstance()->GetNextSeq();
103     REQUEST_HILOGI("JsDownload seq %{public}d", seq);
104     if (Legacy::RequestManager::IsLegacy(env, info)) {
105         return Legacy::RequestManager::Download(env, info);
106     }
107     return JsMain(env, info, Version::API8, seq);
108 }
109 
JsRequestFile(napi_env env,napi_callback_info info)110 napi_value JsTask::JsRequestFile(napi_env env, napi_callback_info info)
111 {
112     int32_t seq = RequestManager::GetInstance()->GetNextSeq();
113     REQUEST_HILOGI("JsRequestFile seq %{public}d", seq);
114     return JsMain(env, info, Version::API9, seq);
115 }
116 
JsCreate(napi_env env,napi_callback_info info)117 napi_value JsTask::JsCreate(napi_env env, napi_callback_info info)
118 {
119     int32_t seq = RequestManager::GetInstance()->GetNextSeq();
120     REQUEST_HILOGI("create seq %{public}d", seq);
121     return JsMain(env, info, Version::API10, seq);
122 }
123 
JsMain(napi_env env,napi_callback_info info,Version version,int32_t seq)124 napi_value JsTask::JsMain(napi_env env, napi_callback_info info, Version version, int32_t seq)
125 {
126     auto context = std::make_shared<ContextInfo>();
127     context->withErrCode_ = version != Version::API8;
128     context->version_ = version;
129     auto input = [context, seq](size_t argc, napi_value *argv, napi_value self) -> napi_status {
130         if (context->version_ == Version::API10) {
131             napi_create_reference(context->env_, argv[1], 1, &(context->jsConfig));
132         }
133         napi_value ctor = GetCtor(context->env_, context->version_);
134         napi_value jsTask = nullptr;
135         napi_status status = napi_new_instance(context->env_, ctor, argc, argv, &jsTask);
136         if (jsTask == nullptr || status != napi_ok) {
137             REQUEST_HILOGE("End task create in AsyncCall input, seq: %{public}d, failed:%{public}d not "
138                            "napi_ok",
139                 seq, status);
140             return napi_generic_failure;
141         }
142         napi_unwrap(context->env_, jsTask, reinterpret_cast<void **>(&context->task));
143         napi_create_reference(context->env_, jsTask, 1, &(context->taskRef));
144         return napi_ok;
145     };
146     auto exec = [context, seq]() {
147         Config config = context->task->config_;
148         context->innerCode_ = CreateExec(context, seq);
149         if (context->innerCode_ == E_SERVICE_ERROR && config.version == Version::API9
150             && config.action == Action::UPLOAD) {
151             context->withErrCode_ = false;
152         }
153     };
154     auto output = [context, seq](napi_value *result) -> napi_status {
155         if (result == nullptr || context->innerCode_ != E_OK) {
156             REQUEST_HILOGE(
157                 "End task create in AsyncCall output, seq: %{public}d, failed:%{public}d", seq, context->innerCode_);
158             return napi_generic_failure;
159         }
160         napi_status status = napi_get_reference_value(context->env_, context->taskRef, result);
161         context->task->SetTid(context->tid);
162         JsTask::AddTask(context);
163         napi_value config = nullptr;
164         napi_get_reference_value(context->env_, context->jsConfig, &config);
165         JsInitialize::CreatProperties(context->env_, *result, config, context->task);
166         REQUEST_HILOGI("End create seq %{public}d, tid %{public}s", seq, context->tid.c_str());
167         return status;
168     };
169     context->SetInput(input).SetOutput(output).SetExec(exec);
170     AsyncCall asyncCall(env, info, context);
171     asyncCall.SetQosLevel(napi_qos_utility);
172     return asyncCall.Call(context, "create");
173 }
174 
AddTask(std::shared_ptr<ContextInfo> context)175 void JsTask::AddTask(std::shared_ptr<ContextInfo> context)
176 {
177     {
178         std::lock_guard<std::mutex> lockGuard(JsTask::taskMutex_);
179         JsTask::AddTaskMap(context->tid, context->task);
180     }
181     {
182         std::lock_guard<std::mutex> lockGuard(JsTask::taskContextMutex_);
183         JsTask::AddTaskContextMap(context->tid, context);
184     }
185 }
186 
CreateExec(const std::shared_ptr<ContextInfo> & context,int32_t seq)187 int32_t JsTask::CreateExec(const std::shared_ptr<ContextInfo> &context, int32_t seq)
188 {
189     REQUEST_HILOGD("JsTask CreateExec: Action %{public}d, Mode %{public}d, seq: %{public}d",
190         context->task->config_.action, context->task->config_.mode, seq);
191     if (!RequestManager::GetInstance()->LoadRequestServer()) {
192         REQUEST_HILOGE("End create task in JsTask CreateExec, seq: %{public}d, failed: request service "
193                        "not ready",
194             seq);
195         return E_SERVICE_ERROR;
196     }
197     if (context->task->config_.mode == Mode::FOREGROUND) {
198         RegisterForegroundResume();
199     }
200     int32_t ret = RequestManager::GetInstance()->Create(context->task->config_, seq, context->tid);
201     if (ret != E_OK) {
202         REQUEST_HILOGE("End create task in JsTask CreateExec, seq: %{public}d, failed: %{public}d", seq, ret);
203         return ret;
204     }
205     JsTask::AddRemoveListener(context);
206     return ret;
207 }
208 
AddRemoveListener(const std::shared_ptr<ContextInfo> & context)209 void JsTask::AddRemoveListener(const std::shared_ptr<ContextInfo> &context)
210 {
211     std::string tid = context->tid;
212     context->task->listenerMutex_.lock();
213     context->task->notifyDataListenerMap_[SubscribeType::REMOVE] =
214         std::make_shared<JSNotifyDataListener>(context->env_, tid, SubscribeType::REMOVE);
215     context->task->listenerMutex_.unlock();
216     RequestManager::GetInstance()->AddListener(
217         tid, SubscribeType::REMOVE, context->task->notifyDataListenerMap_[SubscribeType::REMOVE]);
218 }
219 
GetCtor(napi_env env,Version version)220 napi_value JsTask::GetCtor(napi_env env, Version version)
221 {
222     switch (version) {
223         case Version::API8:
224             return GetCtorV8(env);
225         case Version::API9:
226             return GetCtorV9(env);
227         case Version::API10:
228             return GetCtorV10(env);
229         default:
230             break;
231     }
232     return nullptr;
233 }
234 
GetCtorV10(napi_env env)235 napi_value JsTask::GetCtorV10(napi_env env)
236 {
237     REQUEST_HILOGD("GetCtorV10 in");
238     std::lock_guard<std::mutex> lock(createMutex_);
239     napi_value cons;
240     if (createCtor != nullptr) {
241         NAPI_CALL(env, napi_get_reference_value(env, createCtor, &cons));
242         return cons;
243     }
244     size_t count = sizeof(clzDes) / sizeof(napi_property_descriptor);
245     return DefineClass(env, clzDes, count, Create, &createCtor);
246 }
247 
GetCtorV9(napi_env env)248 napi_value JsTask::GetCtorV9(napi_env env)
249 {
250     REQUEST_HILOGD("GetCtorV9 in");
251     std::lock_guard<std::mutex> lock(requestFileMutex_);
252     napi_value cons;
253     if (requestFileCtor != nullptr) {
254         NAPI_CALL(env, napi_get_reference_value(env, requestFileCtor, &cons));
255         return cons;
256     }
257     size_t count = sizeof(clzDesV9) / sizeof(napi_property_descriptor);
258     return DefineClass(env, clzDesV9, count, RequestFile, &requestFileCtor);
259 }
260 
GetCtorV8(napi_env env)261 napi_value JsTask::GetCtorV8(napi_env env)
262 {
263     REQUEST_HILOGD("GetCtorV8 in");
264     std::lock_guard<std::mutex> lock(requestMutex_);
265     napi_value cons;
266     if (requestCtor != nullptr) {
267         NAPI_CALL(env, napi_get_reference_value(env, requestCtor, &cons));
268         return cons;
269     }
270     size_t count = sizeof(clzDesV9) / sizeof(napi_property_descriptor);
271     return DefineClass(env, clzDesV9, count, RequestFileV8, &requestCtor);
272 }
273 
DefineClass(napi_env env,const napi_property_descriptor * desc,size_t count,napi_callback cb,napi_ref * ctor)274 napi_value JsTask::DefineClass(
275     napi_env env, const napi_property_descriptor *desc, size_t count, napi_callback cb, napi_ref *ctor)
276 {
277     napi_value cons = nullptr;
278     napi_status status = napi_define_class(env, "Request", NAPI_AUTO_LENGTH, cb, nullptr, count, desc, &cons);
279     if (status != napi_ok) {
280         REQUEST_HILOGE("napi_define_class failed");
281         return nullptr;
282     }
283     status = napi_create_reference(env, cons, 1, ctor);
284     if (status != napi_ok) {
285         REQUEST_HILOGE("napi_create_reference failed");
286         return nullptr;
287     }
288     return cons;
289 }
290 
Create(napi_env env,napi_callback_info info)291 napi_value JsTask::Create(napi_env env, napi_callback_info info)
292 {
293     REQUEST_HILOGD("Create API10");
294     return JsInitialize::Initialize(env, info, Version::API10);
295 }
296 
RequestFile(napi_env env,napi_callback_info info)297 napi_value JsTask::RequestFile(napi_env env, napi_callback_info info)
298 {
299     REQUEST_HILOGD("RequestFile API9");
300     return JsInitialize::Initialize(env, info, Version::API9);
301 }
302 
RequestFileV8(napi_env env,napi_callback_info info)303 napi_value JsTask::RequestFileV8(napi_env env, napi_callback_info info)
304 {
305     REQUEST_HILOGD("Request API8");
306     return JsInitialize::Initialize(env, info, Version::API8);
307 }
308 
GetTaskCtor(napi_env env)309 napi_value JsTask::GetTaskCtor(napi_env env)
310 {
311     REQUEST_HILOGD("GetTaskCtor in");
312     std::lock_guard<std::mutex> lock(getTaskCreateMutex_);
313     napi_value cons;
314     if (getTaskCreateCtor != nullptr) {
315         NAPI_CALL(env, napi_get_reference_value(env, getTaskCreateCtor, &cons));
316         return cons;
317     }
318     size_t count = sizeof(clzDes) / sizeof(napi_property_descriptor);
319     return DefineClass(env, clzDes, count, GetTaskCreate, &getTaskCreateCtor);
320 }
321 
GetTaskCreate(napi_env env,napi_callback_info info)322 napi_value JsTask::GetTaskCreate(napi_env env, napi_callback_info info)
323 {
324     REQUEST_HILOGD("GetTask Create");
325     return JsInitialize::Initialize(env, info, Version::API10, false);
326 }
327 
GetTask(napi_env env,napi_callback_info info)328 napi_value JsTask::GetTask(napi_env env, napi_callback_info info)
329 {
330     int32_t seq = RequestManager::GetInstance()->GetNextSeq();
331     REQUEST_HILOGI("GetTask seq %{public}d", seq);
332     auto context = std::make_shared<ContextInfo>();
333     context->withErrCode_ = true;
334     context->version_ = Version::API10;
335     auto input = [context, seq](size_t argc, napi_value *argv, napi_value self) -> napi_status {
336         ExceptionError err = ParseGetTask(context->env_, argc, argv, context);
337         if (err.code != E_OK) {
338             REQUEST_HILOGE("End get task in AsyncCall input, seq: %{public}d, failed: parse tid or token fail", seq);
339             NapiUtils::ThrowError(context->env_, err.code, err.errInfo, true);
340             return napi_invalid_arg;
341         }
342         napi_create_reference(context->env_, argv[0], 1, &(context->baseContext));
343         return napi_ok;
344     };
345     auto output = [context, seq](napi_value *result) -> napi_status {
346         if (context->innerCode_ != E_OK) {
347             REQUEST_HILOGE(
348                 "End get task in AsyncCall output, seq: %{public}d, failed: %{public}d", seq, context->innerCode_);
349             return napi_generic_failure;
350         }
351         if (!GetTaskOutput(context)) {
352             REQUEST_HILOGE("End get task in AsyncCall output, seq: %{public}d, failed: get task output failed", seq);
353             return napi_generic_failure;
354         }
355         napi_status res = napi_get_reference_value(context->env_, context->taskRef, result);
356         context->task->SetTid(context->tid);
357         napi_value conf = nullptr;
358         napi_get_reference_value(context->env_, context->jsConfig, &conf);
359         JsInitialize::CreatProperties(context->env_, *result, conf, context->task);
360         REQUEST_HILOGI("End GetTask seq %{public}d", seq);
361         return res;
362     };
363     auto exec = [context]() {
364         if (!RequestManager::GetInstance()->LoadRequestServer()) {
365             context->innerCode_ = E_SERVICE_ERROR;
366             return;
367         }
368         GetTaskExecution(context);
369     };
370     context->SetInput(input).SetOutput(output).SetExec(exec);
371     AsyncCall asyncCall(env, info, context);
372     return asyncCall.Call(context, "getTask");
373 }
374 
GetTaskExecution(std::shared_ptr<ContextInfo> context)375 void JsTask::GetTaskExecution(std::shared_ptr<ContextInfo> context)
376 {
377     std::string tid = context->tid;
378     REQUEST_HILOGD("Process get task, tid: %{public}s", context->tid.c_str());
379     if (taskContextMap_.find(tid) != taskContextMap_.end()) {
380         REQUEST_HILOGD("Find in taskContextMap_");
381         if (taskContextMap_[tid]->task->config_.version != Version::API10
382             || taskContextMap_[tid]->task->config_.token != context->token) {
383             context->innerCode_ = E_TASK_NOT_FOUND;
384             return;
385         }
386         context->task = taskContextMap_[tid]->task;
387         context->taskRef = taskContextMap_[tid]->taskRef;
388         context->jsConfig = taskContextMap_[tid]->jsConfig;
389         context->innerCode_ = E_OK;
390         return;
391     } else {
392         Config &config = context->config;
393         context->innerCode_ = RequestManager::GetInstance()->GetTask(tid, context->token, config);
394         if (config.action == Action::DOWNLOAD && config.files.size() != 0) {
395             config.saveas = config.files[0].uri;
396             REQUEST_HILOGD("GetTaskExecution saveas: %{public}s", config.saveas.c_str());
397         }
398     }
399     if (context->config.version != Version::API10) {
400         context->innerCode_ = E_TASK_NOT_FOUND;
401     }
402 }
403 
GetTaskOutput(std::shared_ptr<ContextInfo> context)404 bool JsTask::GetTaskOutput(std::shared_ptr<ContextInfo> context)
405 {
406     std::lock_guard<std::mutex> lockGuard(JsTask::taskMutex_);
407     std::string tid = context->tid;
408 
409     if (taskMap_.find(tid) != taskMap_.end()) {
410         return true;
411     }
412 
413     napi_value config = NapiUtils::Convert2JSValueConfig(context->env_, context->config);
414     napi_create_reference(context->env_, config, 1, &(context->jsConfig));
415     napi_value ctor = GetTaskCtor(context->env_);
416     napi_value jsTask = nullptr;
417     napi_value baseCtx = nullptr;
418     napi_get_reference_value(context->env_, context->baseContext, &baseCtx);
419     napi_value args[2] = { baseCtx, config };
420     napi_status status = napi_new_instance(context->env_, ctor, 2, args, &jsTask);
421     if (jsTask == nullptr || status != napi_ok) {
422         REQUEST_HILOGE("Get task failed, reason: %{public}d", status);
423         return false;
424     }
425     napi_unwrap(context->env_, jsTask, reinterpret_cast<void **>(&context->task));
426     napi_create_reference(context->env_, jsTask, 1, &(context->taskRef));
427     JsTask::AddTaskMap(tid, context->task);
428     {
429         std::lock_guard<std::mutex> lockGuardContext(JsTask::taskContextMutex_);
430         JsTask::AddTaskContextMap(tid, context);
431     }
432     JsTask::AddRemoveListener(context);
433     return true;
434 }
435 
ParseGetTask(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<ContextInfo> context)436 ExceptionError JsTask::ParseGetTask(napi_env env, size_t argc, napi_value *argv, std::shared_ptr<ContextInfo> context)
437 {
438     ExceptionError err = { .code = E_OK };
439     // need at least 2 params.
440     if (argc < 2) {
441         REQUEST_HILOGE("Wrong number of arguments");
442         err.code = E_PARAMETER_CHECK;
443         err.errInfo = "Missing mandatory parameters, need at least two params, context and id";
444         return err;
445     }
446     if (NapiUtils::GetValueType(env, argv[1]) != napi_string) {
447         REQUEST_HILOGE("The parameter: tid is not of string type");
448         err.code = E_PARAMETER_CHECK;
449         err.errInfo = "Incorrect parameter type, tid is not of string type";
450         return err;
451     }
452     std::string tid = NapiUtils::Convert2String(env, argv[1]);
453     if (tid.empty()) {
454         REQUEST_HILOGE("tid is empty");
455         err.code = E_PARAMETER_CHECK;
456         err.errInfo = "Parameter verification failed, tid is empty";
457         return err;
458     }
459     // tid length <= 32
460     if (tid.size() > 32) {
461         REQUEST_HILOGE("tid invalid, %{public}s", tid.c_str());
462         err.code = E_TASK_NOT_FOUND;
463         err.errInfo = "task not found error";
464         return err;
465     }
466     context->tid = tid;
467     // handle 3rd param TOKEN
468     if (argc == 3) {
469         if (NapiUtils::GetValueType(env, argv[2]) != napi_string) { // argv[2] is the 3rd param
470             REQUEST_HILOGE("The parameter: token is not of string type");
471             err.code = E_PARAMETER_CHECK;
472             err.errInfo = "Incorrect parameter type, token is not of string type";
473             return err;
474         }
475         uint32_t bufferLen = TOKEN_MAX_BYTES + 2;
476         std::unique_ptr<char[]> token = std::make_unique<char[]>(bufferLen);
477         size_t len = 0;
478         napi_status status = napi_get_value_string_utf8(env, argv[2], token.get(), bufferLen, &len);
479         if (status != napi_ok) {
480             REQUEST_HILOGE("napi get value string utf8 failed");
481             memset_s(token.get(), bufferLen, 0, bufferLen);
482             err.code = E_PARAMETER_CHECK;
483             err.errInfo = "Parameter verification failed, get parameter token failed";
484             return err;
485         }
486         if (len < TOKEN_MIN_BYTES || len > TOKEN_MAX_BYTES) {
487             memset_s(token.get(), bufferLen, 0, bufferLen);
488             err.code = E_PARAMETER_CHECK;
489             err.errInfo = "Parameter verification failed, the length of token should between 8 and 2048 bytes";
490             return err;
491         }
492         context->token = std::string(token.get(), len);
493         memset_s(token.get(), bufferLen, 0, bufferLen);
494     }
495     return err;
496 }
497 
Remove(napi_env env,napi_callback_info info)498 napi_value JsTask::Remove(napi_env env, napi_callback_info info)
499 {
500     int32_t seq = RequestManager::GetInstance()->GetNextSeq();
501     REQUEST_HILOGI("Begin remove seq %{public}d", seq);
502     struct RemoveContext : public AsyncCall::Context {
503         std::string tid;
504         bool res = false;
505     };
506 
507     auto context = std::make_shared<RemoveContext>();
508     context->withErrCode_ = true;
509     context->version_ = Version::API10;
510     auto input = [context, seq](size_t argc, napi_value *argv, napi_value self) -> napi_status {
511         ExceptionError err = ParseTid(context->env_, argc, argv, context->tid);
512         if (err.code != E_OK) {
513             REQUEST_HILOGE("End task remove in AsyncCall input, seq: %{public}d, failed: tid invalid", seq);
514             NapiUtils::ThrowError(context->env_, err.code, err.errInfo, true);
515             return napi_invalid_arg;
516         }
517         return napi_ok;
518     };
519     auto output = [context, seq](napi_value *result) -> napi_status {
520         if (context->innerCode_ != E_OK) {
521             context->res = false;
522             REQUEST_HILOGE(
523                 "End task remove in AsyncCall output, seq: %{public}d, failed: %{public}d", seq, context->innerCode_);
524             return napi_generic_failure;
525         }
526         REQUEST_HILOGI("End remove seq %{public}d", seq);
527         return NapiUtils::Convert2JSValue(context->env_, context->res, *result);
528     };
529     auto exec = [context]() {
530         context->innerCode_ = RequestManager::GetInstance()->Remove(context->tid, Version::API10);
531     };
532     context->SetInput(std::move(input)).SetOutput(std::move(output)).SetExec(std::move(exec));
533     AsyncCall asyncCall(env, info, context);
534     return asyncCall.Call(context, "remove");
535 }
536 
ParseTid(napi_env env,size_t argc,napi_value * argv,std::string & tid)537 ExceptionError JsTask::ParseTid(napi_env env, size_t argc, napi_value *argv, std::string &tid)
538 {
539     ExceptionError err = { .code = E_OK };
540     if (argc < 1) {
541         REQUEST_HILOGE("Wrong number of arguments");
542         err.code = E_PARAMETER_CHECK;
543         err.errInfo = "Missing mandatory parameters, missing tid";
544         return err;
545     }
546     if (NapiUtils::GetValueType(env, argv[0]) != napi_string) {
547         REQUEST_HILOGE("The first parameter is not of string type");
548         err.code = E_PARAMETER_CHECK;
549         err.errInfo = "Incorrect parameter type, tid is not of string type";
550         return err;
551     }
552     tid = NapiUtils::Convert2String(env, argv[0]);
553     if (tid.empty()) {
554         err.code = E_PARAMETER_CHECK;
555         err.errInfo = "Parameter verification failed, tid is empty";
556         return err;
557     }
558     return err;
559 }
560 
Show(napi_env env,napi_callback_info info)561 napi_value JsTask::Show(napi_env env, napi_callback_info info)
562 {
563     int32_t seq = RequestManager::GetInstance()->GetNextSeq();
564     REQUEST_HILOGI("Begin show seq %{public}d", seq);
565     auto context = std::make_shared<TouchContext>();
566     auto input = [context, seq](size_t argc, napi_value *argv, napi_value self) -> napi_status {
567         ExceptionError err = ParseTid(context->env_, argc, argv, context->tid);
568         if (err.code != E_OK) {
569             REQUEST_HILOGE("End task show in AsyncCall input, seq: %{public}d, failed: tid invalid", seq);
570             NapiUtils::ThrowError(context->env_, err.code, err.errInfo, true);
571             return napi_invalid_arg;
572         }
573         // tid length <= 32
574         if (context->tid.size() > 32) {
575             REQUEST_HILOGE("End task show in AsyncCall input, seq: %{public}d, failed: tid invalid", seq);
576             NapiUtils::ThrowError(context->env_, E_TASK_NOT_FOUND, "task not found error", true);
577             return napi_invalid_arg;
578         }
579         return napi_ok;
580     };
581     return TouchInner(env, info, std::move(input), std::move(context), seq);
582 }
583 
Touch(napi_env env,napi_callback_info info)584 napi_value JsTask::Touch(napi_env env, napi_callback_info info)
585 {
586     int32_t seq = RequestManager::GetInstance()->GetNextSeq();
587     REQUEST_HILOGI("Begin touch seq %{public}d", seq);
588     auto context = std::make_shared<TouchContext>();
589     auto input = [context, seq](size_t argc, napi_value *argv, napi_value self) -> napi_status {
590         ExceptionError err = ParseTouch(context->env_, argc, argv, context);
591         if (err.code != E_OK) {
592             REQUEST_HILOGE("End task touch in AsyncCall input, seq: %{public}d, failed: arg invalid", seq);
593             NapiUtils::ThrowError(context->env_, err.code, err.errInfo, true);
594             return napi_invalid_arg;
595         }
596         return napi_ok;
597     };
598     return TouchInner(env, info, std::move(input), std::move(context), seq);
599 }
600 
TouchInner(napi_env env,napi_callback_info info,AsyncCall::Context::InputAction input,std::shared_ptr<TouchContext> context,int32_t seq)601 napi_value JsTask::TouchInner(napi_env env, napi_callback_info info, AsyncCall::Context::InputAction input,
602     std::shared_ptr<TouchContext> context, int32_t seq)
603 {
604     context->withErrCode_ = true;
605     context->version_ = Version::API10;
606     auto output = [context, seq](napi_value *result) -> napi_status {
607         if (context->innerCode_ != E_OK) {
608             REQUEST_HILOGE(
609                 "End task show in AsyncCall output, seq: %{public}d, failed: %{public}d", seq, context->innerCode_);
610             return napi_generic_failure;
611         }
612         *result = NapiUtils::Convert2JSValue(context->env_, context->taskInfo);
613         REQUEST_HILOGI("End show seq %{public}d", seq);
614         return napi_ok;
615     };
616     auto exec = [context]() {
617         if (!RequestManager::GetInstance()->LoadRequestServer()) {
618             context->innerCode_ = E_SERVICE_ERROR;
619             return;
620         }
621         context->innerCode_ = RequestManager::GetInstance()->Touch(context->tid, context->token, context->taskInfo);
622     };
623     context->SetInput(std::move(input)).SetOutput(std::move(output)).SetExec(std::move(exec));
624     AsyncCall asyncCall(env, info, context);
625     return asyncCall.Call(context, "touch");
626 }
627 
ParseTouch(napi_env env,size_t argc,napi_value * argv,std::shared_ptr<TouchContext> context)628 ExceptionError JsTask::ParseTouch(napi_env env, size_t argc, napi_value *argv, std::shared_ptr<TouchContext> context)
629 {
630     ExceptionError err = { .code = E_OK };
631     // 2 means least param num.
632     if (argc < 2) {
633         REQUEST_HILOGE("Wrong number of arguments");
634         err.code = E_PARAMETER_CHECK;
635         err.errInfo = "Missing mandatory parameters, need at least two params, id and token";
636         return err;
637     }
638     if (NapiUtils::GetValueType(env, argv[0]) != napi_string || NapiUtils::GetValueType(env, argv[1]) != napi_string) {
639         REQUEST_HILOGE("The parameter: tid is not of string type");
640         err.code = E_PARAMETER_CHECK;
641         err.errInfo = "Incorrect parameter type, tid is not of string type";
642         return err;
643     }
644     context->tid = NapiUtils::Convert2String(env, argv[0]);
645     if (context->tid.empty()) {
646         REQUEST_HILOGE("tid is empty");
647         err.code = E_PARAMETER_CHECK;
648         err.errInfo = "Parameter verification failed, tid is empty";
649         return err;
650     }
651     // tid length <= 32
652     if (context->tid.size() > 32) {
653         REQUEST_HILOGE("tid invalid, %{public}s", context->tid.c_str());
654         err.code = E_TASK_NOT_FOUND;
655         err.errInfo = "task not found error";
656         return err;
657     }
658     uint32_t bufferLen = TOKEN_MAX_BYTES + 2;
659     char *token = new char[bufferLen];
660     size_t len = 0;
661     napi_status status = napi_get_value_string_utf8(env, argv[1], token, bufferLen, &len);
662     if (status != napi_ok) {
663         REQUEST_HILOGE("napi get value string utf8 failed");
664         memset_s(token, bufferLen, 0, bufferLen);
665         delete[] token;
666         err.code = E_PARAMETER_CHECK;
667         err.errInfo = "Parameter verification failed, get token failed";
668         return err;
669     }
670     if (len < TOKEN_MIN_BYTES || len > TOKEN_MAX_BYTES) {
671         memset_s(token, bufferLen, 0, bufferLen);
672         delete[] token;
673         err.code = E_PARAMETER_CHECK;
674         err.errInfo = "Parameter verification failed, the length of token should between 8 and 2048 bytes";
675         return err;
676     }
677     context->token = std::string(token, len);
678     memset_s(token, bufferLen, 0, bufferLen);
679     delete[] token;
680     return err;
681 }
682 
ParseSearch(napi_env env,size_t argc,napi_value * argv,Filter & filter)683 ExceptionError JsTask::ParseSearch(napi_env env, size_t argc, napi_value *argv, Filter &filter)
684 {
685     ExceptionError err = { .code = E_OK };
686     using namespace std::chrono;
687     filter.bundle = "*";
688     filter.before = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
689     filter.after = filter.before - MILLISECONDS_IN_ONE_DAY;
690     if (argc < 1) {
691         return err;
692     }
693     napi_valuetype valueType = NapiUtils::GetValueType(env, argv[0]);
694     if (valueType == napi_null || valueType == napi_undefined) {
695         return err;
696     }
697     if (valueType != napi_object) {
698         REQUEST_HILOGE("The parameter: filter is not of object type");
699         err.code = E_PARAMETER_CHECK;
700         err.errInfo = "Incorrect parameter type, filter is not of object type";
701         return err;
702     }
703     filter.bundle = ParseBundle(env, argv[0]);
704     filter.before = ParseBefore(env, argv[0]);
705     filter.after = ParseAfter(env, argv[0], filter.before);
706     if (filter.before < filter.after) {
707         REQUEST_HILOGE("before is small than after");
708         err.code = E_PARAMETER_CHECK;
709         err.errInfo = "Parameter verification failed, filter before is small than after";
710         return err;
711     }
712     filter.state = ParseState(env, argv[0]);
713     filter.action = ParseAction(env, argv[0]);
714     filter.mode = ParseMode(env, argv[0]);
715     return err;
716 }
717 
ParseBundle(napi_env env,napi_value value)718 std::string JsTask::ParseBundle(napi_env env, napi_value value)
719 {
720     if (!NapiUtils::HasNamedProperty(env, value, "bundle")) {
721         return "*";
722     }
723     napi_value value1 = NapiUtils::GetNamedProperty(env, value, "bundle");
724     if (NapiUtils::GetValueType(env, value1) != napi_string) {
725         return "*";
726     }
727     return NapiUtils::Convert2String(env, value1);
728 }
729 
ParseState(napi_env env,napi_value value)730 State JsTask::ParseState(napi_env env, napi_value value)
731 {
732     if (!NapiUtils::HasNamedProperty(env, value, "state")) {
733         return State::ANY;
734     }
735     napi_value value1 = NapiUtils::GetNamedProperty(env, value, "state");
736     if (NapiUtils::GetValueType(env, value1) != napi_number) {
737         return State::ANY;
738     }
739     return static_cast<State>(NapiUtils::Convert2Uint32(env, value1));
740 }
741 
ParseAction(napi_env env,napi_value value)742 Action JsTask::ParseAction(napi_env env, napi_value value)
743 {
744     if (!NapiUtils::HasNamedProperty(env, value, "action")) {
745         return Action::ANY;
746     }
747     napi_value value1 = NapiUtils::GetNamedProperty(env, value, "action");
748     if (NapiUtils::GetValueType(env, value1) != napi_number) {
749         return Action::ANY;
750     }
751     return static_cast<Action>(NapiUtils::Convert2Uint32(env, value1));
752 }
753 
ParseMode(napi_env env,napi_value value)754 Mode JsTask::ParseMode(napi_env env, napi_value value)
755 {
756     if (!NapiUtils::HasNamedProperty(env, value, "mode")) {
757         return Mode::ANY;
758     }
759     napi_value value1 = NapiUtils::GetNamedProperty(env, value, "mode");
760     if (NapiUtils::GetValueType(env, value1) != napi_number) {
761         return Mode::ANY;
762     }
763     return static_cast<Mode>(NapiUtils::Convert2Uint32(env, value1));
764 }
765 
ParseBefore(napi_env env,napi_value value)766 int64_t JsTask::ParseBefore(napi_env env, napi_value value)
767 {
768     using namespace std::chrono;
769     int64_t now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
770     if (!NapiUtils::HasNamedProperty(env, value, "before")) {
771         return now;
772     }
773     napi_value value1 = NapiUtils::GetNamedProperty(env, value, "before");
774     if (NapiUtils::GetValueType(env, value1) != napi_number) {
775         return now;
776     }
777     int64_t ret = 0;
778     NAPI_CALL_BASE(env, napi_get_value_int64(env, value1, &ret), now);
779     return ret;
780 }
781 
ParseAfter(napi_env env,napi_value value,int64_t before)782 int64_t JsTask::ParseAfter(napi_env env, napi_value value, int64_t before)
783 {
784     int64_t defaultValue = before - MILLISECONDS_IN_ONE_DAY;
785     if (!NapiUtils::HasNamedProperty(env, value, "after")) {
786         return defaultValue;
787     }
788     napi_value value1 = NapiUtils::GetNamedProperty(env, value, "after");
789     if (NapiUtils::GetValueType(env, value1) != napi_number) {
790         return defaultValue;
791     }
792     int64_t ret = 0;
793     NAPI_CALL_BASE(env, napi_get_value_int64(env, value1, &ret), defaultValue);
794     return ret;
795 }
796 
Search(napi_env env,napi_callback_info info)797 napi_value JsTask::Search(napi_env env, napi_callback_info info)
798 {
799     int32_t seq = RequestManager::GetInstance()->GetNextSeq();
800     REQUEST_HILOGI("Begin search seq %{public}d", seq);
801     struct SearchContext : public AsyncCall::Context {
802         Filter filter;
803         std::vector<std::string> tids;
804     };
805 
806     auto context = std::make_shared<SearchContext>();
807     context->withErrCode_ = true;
808     context->version_ = Version::API10;
809     auto input = [context, seq](size_t argc, napi_value *argv, napi_value self) -> napi_status {
810         ExceptionError err = ParseSearch(context->env_, argc, argv, context->filter);
811         if (err.code != E_OK) {
812             REQUEST_HILOGE("End task search in AsyncCall input, seq: %{public}d, failed: arg invalid", seq);
813             NapiUtils::ThrowError(context->env_, err.code, err.errInfo, true);
814             return napi_invalid_arg;
815         }
816         return napi_ok;
817     };
818     auto output = [context, seq](napi_value *result) -> napi_status {
819         if (context->innerCode_ != E_OK) {
820             REQUEST_HILOGE(
821                 "End task search in AsyncCall output, seq: %{public}d, failed: %{public}d", seq, context->innerCode_);
822             return napi_generic_failure;
823         }
824         *result = NapiUtils::Convert2JSValue(context->env_, context->tids);
825         REQUEST_HILOGI("End search seq %{public}d", seq);
826         return napi_ok;
827     };
828     auto exec = [context]() {
829         if (!RequestManager::GetInstance()->LoadRequestServer()) {
830             context->innerCode_ = E_SERVICE_ERROR;
831             return;
832         }
833         context->innerCode_ = RequestManager::GetInstance()->Search(context->filter, context->tids);
834     };
835     context->SetInput(std::move(input)).SetOutput(std::move(output)).SetExec(std::move(exec));
836     AsyncCall asyncCall(env, info, context);
837     return asyncCall.Call(context, "search");
838 }
839 
Query(napi_env env,napi_callback_info info)840 napi_value JsTask::Query(napi_env env, napi_callback_info info)
841 {
842     int32_t seq = RequestManager::GetInstance()->GetNextSeq();
843     REQUEST_HILOGI("Begin query seq %{public}d", seq);
844     struct QueryContext : public AsyncCall::Context {
845         std::string tid;
846         TaskInfo taskInfo;
847     };
848 
849     auto context = std::make_shared<QueryContext>();
850     context->withErrCode_ = true;
851     context->version_ = Version::API10;
852     auto input = [context, seq](size_t argc, napi_value *argv, napi_value self) -> napi_status {
853         ExceptionError err = ParseTid(context->env_, argc, argv, context->tid);
854         if (err.code != E_OK) {
855             REQUEST_HILOGE("End task query in AsyncCall input, seq: %{public}d, failed: tid invalid", seq);
856             NapiUtils::ThrowError(context->env_, err.code, err.errInfo, true);
857             return napi_invalid_arg;
858         }
859         return napi_ok;
860     };
861     auto output = [context, seq](napi_value *result) -> napi_status {
862         if (context->innerCode_ != E_OK) {
863             REQUEST_HILOGE(
864                 "End task query in AsyncCall output, seq: %{public}d, failed: %{public}d", seq, context->innerCode_);
865             return napi_generic_failure;
866         }
867         context->taskInfo.withSystem = true;
868         *result = NapiUtils::Convert2JSValue(context->env_, context->taskInfo);
869         REQUEST_HILOGI("End query seq %{public}d", seq);
870         return napi_ok;
871     };
872     auto exec = [context]() {
873         if (!RequestManager::GetInstance()->LoadRequestServer()) {
874             context->innerCode_ = E_SERVICE_ERROR;
875             return;
876         }
877         context->innerCode_ = RequestManager::GetInstance()->Query(context->tid, context->taskInfo);
878     };
879     context->SetInput(std::move(input)).SetOutput(std::move(output)).SetExec(std::move(exec));
880     AsyncCall asyncCall(env, info, context);
881     return asyncCall.Call(context, "query");
882 }
883 
GetTid()884 std::string JsTask::GetTid()
885 {
886     return tid_;
887 }
888 
SetTid(std::string & tid)889 void JsTask::SetTid(std::string &tid)
890 {
891     tid_ = tid;
892 }
893 
AddTaskMap(const std::string & key,JsTask * task)894 void JsTask::AddTaskMap(const std::string &key, JsTask *task)
895 {
896     JsTask::taskMap_[key] = task;
897 
898     if (!JsTask::taskMap_.empty()) {
899         JsTask::SubscribeSA();
900     }
901 }
902 
AddTaskContextMap(const std::string & key,std::shared_ptr<ContextInfo> context)903 void JsTask::AddTaskContextMap(const std::string &key, std::shared_ptr<ContextInfo> context)
904 {
905     JsTask::taskContextMap_[key] = context;
906 }
907 
SubscribeSA()908 void JsTask::SubscribeSA()
909 {
910     REQUEST_HILOGD("SubscribeSA in");
911     if (!RequestManager::GetInstance()->SubscribeSA()) {
912         REQUEST_HILOGE("SubscribeSA Failed");
913     }
914 }
915 
UnsubscribeSA()916 void JsTask::UnsubscribeSA()
917 {
918     REQUEST_HILOGD("UnsubscribeSA in");
919     if (!RequestManager::GetInstance()->UnsubscribeSA()) {
920         REQUEST_HILOGE("UnsubscribeSA Failed");
921     }
922 }
923 
ReloadListener()924 void JsTask::ReloadListener()
925 {
926     REQUEST_HILOGD("ReloadListener in");
927     // collect all tids first to reduce lock holding time
928     std::vector<std::string> tids;
929     {
930         std::lock_guard<std::mutex> lockGuard(JsTask::taskMutex_);
931         for (const auto &it : taskMap_) {
932             tids.push_back(it.first);
933         }
934     }
935     for (const auto &it : tids) {
936         REQUEST_HILOGD("ReloadListener tid: %{public}s", it.c_str());
937         RequestManager::GetInstance()->Subscribe(it);
938     }
939 }
940 
ClearTaskMap(const std::string & key)941 void JsTask::ClearTaskMap(const std::string &key)
942 {
943     std::lock_guard<std::mutex> lockGuard(JsTask::taskMutex_);
944     auto it = taskMap_.find(key);
945     if (it != taskMap_.end()) {
946         taskMap_.erase(it);
947     }
948     if (taskMap_.empty()) {
949         JsTask::UnsubscribeSA();
950     }
951 }
952 
SetDirsPermission(std::vector<std::string> & dirs)953 bool JsTask::SetDirsPermission(std::vector<std::string> &dirs)
954 {
955     if (dirs.empty()) {
956         return true;
957     }
958     std::string newPath = "/data/storage/el2/base/.ohos/.request/.certs";
959     std::vector<std::string> dirElems;
960     JsInitialize::StringSplit(newPath, '/', dirElems);
961     if (!JsInitialize::CreateDirs(dirElems)) {
962         REQUEST_HILOGE("CreateDirs Err: %{public}s", newPath.c_str());
963         return false;
964     }
965 
966     for (const auto &folderPath : dirs) {
967         fs::path folder = folderPath;
968         if (!(fs::exists(folder) && fs::is_directory(folder))) {
969             return false;
970         }
971         for (const auto &entry : fs::directory_iterator(folder)) {
972             fs::path path = entry.path();
973             std::string existfilePath = folder.string() + "/" + path.filename().string();
974             std::string newfilePath = newPath + "/" + path.filename().string();
975             if (!fs::exists(newfilePath)) {
976                 fs::copy(existfilePath, newfilePath);
977             }
978             if (chmod(newfilePath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
979                 REQUEST_HILOGD("File add OTH access Failed.");
980             }
981             REQUEST_HILOGD("current filePath is %{public}s", newfilePath.c_str());
982             if (!JsTask::SetPathPermission(newfilePath)) {
983                 REQUEST_HILOGE("Set path permission fail.");
984                 return false;
985             }
986         }
987     }
988     if (!dirs.empty()) {
989         dirs.clear();
990         dirs.push_back(newPath);
991     }
992     return true;
993 }
994 
SetPathPermission(const std::string & filepath)995 bool JsTask::SetPathPermission(const std::string &filepath)
996 {
997     std::string baseDir;
998     if (!JsInitialize::CheckBelongAppBaseDir(filepath, baseDir)) {
999         return false;
1000     }
1001 
1002     AddPathMap(filepath, baseDir);
1003     {
1004         std::lock_guard<std::mutex> lockGuard(JsTask::pathMutex_);
1005         for (auto it : pathMap_) {
1006             if (it.second <= 0) {
1007                 continue;
1008             }
1009             if (AclSetAccess(it.first, SA_PERMISSION_X) != ACL_SUCC) {
1010                 REQUEST_HILOGE("AclSetAccess Parent Dir Failed: %{public}s", it.first.c_str());
1011             }
1012         }
1013     }
1014 
1015     if (AclSetAccess(filepath, SA_PERMISSION_RWX) != ACL_SUCC) {
1016         REQUEST_HILOGE("AclSetAccess Child Dir Failed: %{public}s", filepath.c_str());
1017         return false;
1018     }
1019     return true;
1020 }
1021 
AddPathMap(const std::string & filepath,const std::string & baseDir)1022 void JsTask::AddPathMap(const std::string &filepath, const std::string &baseDir)
1023 {
1024     {
1025         std::lock_guard<std::mutex> lockGuard(JsTask::pathMutex_);
1026         auto it = fileMap_.find(filepath);
1027         if (it == fileMap_.end()) {
1028             fileMap_[filepath] = 1;
1029         } else {
1030             fileMap_[filepath] += 1;
1031         }
1032     }
1033 
1034     std::string childDir(filepath);
1035     std::string parentDir;
1036     while (childDir.length() > baseDir.length()) {
1037         parentDir = childDir.substr(0, childDir.rfind("/"));
1038         std::lock_guard<std::mutex> lockGuard(JsTask::pathMutex_);
1039         auto it = pathMap_.find(parentDir);
1040         if (it == pathMap_.end()) {
1041             pathMap_[parentDir] = 1;
1042         } else {
1043             pathMap_[parentDir] += 1;
1044         }
1045         childDir = parentDir;
1046     }
1047 }
1048 
ResetDirAccess(const std::string & filepath)1049 void JsTask::ResetDirAccess(const std::string &filepath)
1050 {
1051     int ret = AclSetAccess(filepath, SA_PERMISSION_CLEAN);
1052     if (ret != ACL_SUCC) {
1053         REQUEST_HILOGD("AclSetAccess Reset Dir Failed: %{public}s", filepath.c_str());
1054     }
1055 }
1056 
RemovePathMap(const std::string & filepath)1057 void JsTask::RemovePathMap(const std::string &filepath)
1058 {
1059     std::string baseDir;
1060     if (!JsInitialize::CheckBelongAppBaseDir(filepath, baseDir)) {
1061         return;
1062     }
1063 
1064     {
1065         std::lock_guard<std::mutex> lockGuard(JsTask::pathMutex_);
1066         auto it = fileMap_.find(filepath);
1067         if (it != fileMap_.end()) {
1068             if (fileMap_[filepath] <= 1) {
1069                 fileMap_.erase(filepath);
1070                 if (chmod(filepath.c_str(), S_IRUSR | S_IWUSR | S_IRGRP) != 0) {
1071                     REQUEST_HILOGE("File remove OTH access Failed: %{public}s", filepath.c_str());
1072                 }
1073             } else {
1074                 fileMap_[filepath] -= 1;
1075             }
1076         } else {
1077             return;
1078         }
1079     }
1080 
1081     std::string childDir(filepath);
1082     std::string parentDir;
1083     while (childDir.length() > baseDir.length()) {
1084         parentDir = childDir.substr(0, childDir.rfind("/"));
1085         std::lock_guard<std::mutex> lockGuard(JsTask::pathMutex_);
1086         auto it = pathMap_.find(parentDir);
1087         if (it != pathMap_.end()) {
1088             if (pathMap_[parentDir] <= 1) {
1089                 pathMap_.erase(parentDir);
1090                 ResetDirAccess(parentDir);
1091             } else {
1092                 pathMap_[parentDir] -= 1;
1093             }
1094         }
1095         childDir = parentDir;
1096     }
1097 }
1098 
RemoveDirsPermission(const std::vector<std::string> & dirs)1099 void JsTask::RemoveDirsPermission(const std::vector<std::string> &dirs)
1100 {
1101     for (const auto &folderPath : dirs) {
1102         fs::path folder = folderPath;
1103         for (const auto &entry : fs::directory_iterator(folder)) {
1104             fs::path path = entry.path();
1105             std::string filePath = folder.string() + "/" + path.filename().string();
1106             RemovePathMap(filePath);
1107         }
1108     }
1109 }
1110 
ClearTaskTemp(const std::string & tid,bool isRmFiles,bool isRmAcls,bool isRmCertsAcls)1111 void JsTask::ClearTaskTemp(const std::string &tid, bool isRmFiles, bool isRmAcls, bool isRmCertsAcls)
1112 {
1113     std::lock_guard<std::mutex> lockGuard(JsTask::taskContextMutex_);
1114     auto it = taskContextMap_.find(tid);
1115     if (it == taskContextMap_.end()) {
1116         REQUEST_HILOGD("Clear task tmp files, not in ContextMap");
1117         return;
1118     }
1119     auto context = it->second;
1120 
1121     if (isRmFiles) {
1122         auto bodyFileNames = context->task->config_.bodyFileNames;
1123         for (auto &filePath : bodyFileNames) {
1124             std::error_code err;
1125             if (!std::filesystem::exists(filePath, err)) {
1126                 continue;
1127             }
1128             err.clear();
1129             RemovePathMap(filePath);
1130             NapiUtils::RemoveFile(filePath);
1131         }
1132     }
1133     if (isRmAcls) {
1134         // Reset Acl permission
1135         for (auto &file : context->task->config_.files) {
1136             RemovePathMap(file.uri);
1137         }
1138         context->task->isGetPermission = false;
1139     }
1140     if (isRmCertsAcls) {
1141         RemoveDirsPermission(context->task->config_.certsPath);
1142     }
1143 }
1144 
RemoveTaskContext(const std::string & tid)1145 void JsTask::RemoveTaskContext(const std::string &tid)
1146 {
1147     std::lock_guard<std::mutex> lockGuard(JsTask::taskContextMutex_);
1148     auto it = taskContextMap_.find(tid);
1149     if (it == taskContextMap_.end()) {
1150         REQUEST_HILOGD("Clear task tmp files, not in ContextMap");
1151         return;
1152     }
1153     auto context = it->second;
1154 
1155     auto map = context->task->notifyDataListenerMap_;
1156     for (auto i = map.begin(); i != map.end();i++) {
1157         i->second->DeleteAllListenerRef();
1158     }
1159     map.clear();
1160     taskContextMap_.erase(it);
1161     UnrefTaskContextMap(context);
1162 }
1163 
UnrefTaskContextMap(std::shared_ptr<ContextInfo> context)1164 void JsTask::UnrefTaskContextMap(std::shared_ptr<ContextInfo> context)
1165 {
1166     ContextCallbackData *data = new ContextCallbackData();
1167     if (data == nullptr) {
1168         return;
1169     }
1170     data->context = context;
1171     auto callback = [data]() {
1172         if (data == nullptr) {
1173             // Ensure that the `work` is not nullptr.
1174             return;
1175         }
1176         napi_handle_scope scope = nullptr;
1177         napi_open_handle_scope(data->context->env_, &scope);
1178         if (scope == nullptr) {
1179             delete data;
1180             return;
1181         }
1182         u_int32_t taskRefCount = 0;
1183         napi_reference_unref(data->context->env_, data->context->taskRef, &taskRefCount);
1184         REQUEST_HILOGD("Unref task ref, count is %{public}d", taskRefCount);
1185         if (taskRefCount == 0) {
1186             napi_delete_reference(data->context->env_, data->context->taskRef);
1187         }
1188         if (data->context->version_ == Version::API10) {
1189             u_int32_t configRefCount = 0;
1190             napi_reference_unref(data->context->env_, data->context->jsConfig, &configRefCount);
1191             REQUEST_HILOGI("Unref task config ref, count is %{public}d", configRefCount);
1192             if (configRefCount == 0) {
1193                 napi_delete_reference(data->context->env_, data->context->jsConfig);
1194             }
1195         }
1196         napi_close_handle_scope(data->context->env_, scope);
1197         delete data;
1198         return;
1199     };
1200 
1201     int32_t ret = napi_send_event(data->context->env_, callback, napi_eprio_high);
1202     if (ret != napi_ok) {
1203         REQUEST_HILOGE("napi_send_event failed: %{public}d", ret);
1204         delete data;
1205     }
1206 
1207     return;
1208 }
1209 
Equals(napi_env env,napi_value value,napi_ref copy)1210 bool JsTask::Equals(napi_env env, napi_value value, napi_ref copy)
1211 {
1212     if (copy == nullptr) {
1213         return (value == nullptr);
1214     }
1215 
1216     napi_value copyValue = nullptr;
1217     napi_get_reference_value(env, copy, &copyValue);
1218 
1219     bool isEquals = false;
1220     napi_strict_equals(env, value, copyValue, &isEquals);
1221     return isEquals;
1222 }
1223 
RegisterForegroundResume()1224 void JsTask::RegisterForegroundResume()
1225 {
1226     if (register_) {
1227         return;
1228     }
1229     REQUEST_HILOGI("Process register foreground resume callback");
1230     register_ = true;
1231     auto context = AbilityRuntime::ApplicationContext::GetInstance();
1232     if (context == nullptr) {
1233         REQUEST_HILOGE("End register foreground resume callback, failed: Get ApplicationContext failed");
1234         return;
1235     }
1236     context->RegisterAbilityLifecycleCallback(std::make_shared<AppStateCallback>());
1237     REQUEST_HILOGI("End register foreground resume callback successfully");
1238 }
1239 } // namespace OHOS::Request