• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "cj_request_task.h"
17 #include <cstring>
18 #include <fcntl.h>
19 #include <filesystem>
20 #include <fstream>
21 #include <regex>
22 #include <string>
23 #include <sys/stat.h>
24 #include "application_context.h"
25 #include "cj_app_state_callback.h"
26 #include "cj_initialize.h"
27 #include "cj_lambda.h"
28 #include "cj_request_common.h"
29 #include "cj_request_event.h"
30 #include "cj_response_listener.h"
31 #include "constant.h"
32 #include "js_common.h"
33 #include "log.h"
34 #include "request_manager.h"
35 #include "securec.h"
36 #include "storage_acl.h"
37 
38 namespace OHOS::CJSystemapi::Request {
39 namespace fs = std::filesystem;
40 using OHOS::AbilityRuntime::Context;
41 using OHOS::Request::Action;
42 using OHOS::Request::ExceptionErrorCode;
43 using OHOS::Request::RequestManager;
44 using OHOS::Request::TaskInfo;
45 using OHOS::Request::Version;
46 using OHOS::StorageDaemon::AclSetAccess;
47 
48 std::mutex CJRequestTask::taskMutex_;
49 std::map<std::string, CJRequestTask *> CJRequestTask::taskMap_;
50 
51 std::mutex CJRequestTask::pathMutex_;
52 std::map<std::string, int32_t> CJRequestTask::pathMap_;
53 
54 bool CJRequestTask::register_ = false;
55 
56 static constexpr int ACL_SUCC = 0;
57 static const std::string SA_PERMISSION_RWX = "g:3815:rwx";
58 static const std::string SA_PERMISSION_X = "g:3815:x";
59 static const std::string SA_PERMISSION_CLEAN = "g:3815:---";
60 
CJRequestTask()61 CJRequestTask::CJRequestTask()
62 {
63     config_.version = Version::API10;
64     config_.action = Action::ANY;
65     REQUEST_HILOGD("construct CJRequestTask()");
66 }
67 
~CJRequestTask()68 CJRequestTask::~CJRequestTask()
69 {
70     REQUEST_HILOGD("~CJRequestTask()");
71     RequestManager::GetInstance()->RemoveAllListeners(GetTidStr());
72 }
73 
GetTidStr() const74 std::string CJRequestTask::GetTidStr() const
75 {
76     return tid_;
77 }
78 
SetTid()79 void CJRequestTask::SetTid()
80 {
81     tid_ = taskId_;
82 }
83 
AddTaskMap(const std::string & key,CJRequestTask * task)84 void CJRequestTask::AddTaskMap(const std::string &key, CJRequestTask *task)
85 {
86     std::lock_guard<std::mutex> lockGuard(CJRequestTask::taskMutex_);
87     CJRequestTask::taskMap_[key] = task;
88 }
89 
FindTaskById(std::string & taskId)90 CJRequestTask *CJRequestTask::FindTaskById(std::string &taskId)
91 {
92     CJRequestTask *task = nullptr;
93     {
94         std::lock_guard<std::mutex> lockGuard(CJRequestTask::taskMutex_);
95         auto item = CJRequestTask::taskMap_.find(taskId);
96         if (item == CJRequestTask::taskMap_.end()) {
97             return nullptr;
98         }
99         task = item->second;
100     }
101     return task;
102 }
103 
ClearTaskMap(const std::string & key)104 CJRequestTask *CJRequestTask::ClearTaskMap(const std::string &key)
105 {
106     std::lock_guard<std::mutex> lockGuard(CJRequestTask::taskMutex_);
107     auto it = taskMap_.find(key);
108     if (it == taskMap_.end()) {
109         return nullptr;
110     }
111     taskMap_.erase(it);
112     return it->second;
113 }
114 
SetPathPermission(const std::string & filepath)115 bool CJRequestTask::SetPathPermission(const std::string &filepath)
116 {
117     std::string baseDir;
118     if (!CJInitialize::GetBaseDir(baseDir) || filepath.find(baseDir) == std::string::npos) {
119         REQUEST_HILOGE("File dir not found.");
120         return false;
121     }
122 
123     AddPathMap(filepath, baseDir);
124     {
125         std::lock_guard<std::mutex> lockGuard(pathMutex_);
126         for (auto it : pathMap_) {
127             if (it.second <= 0) {
128                 continue;
129             }
130             if (AclSetAccess(it.first, SA_PERMISSION_X) != ACL_SUCC) {
131                 REQUEST_HILOGE("AclSetAccess Parent Dir Failed.");
132             }
133         }
134     }
135 
136     if (AclSetAccess(filepath, SA_PERMISSION_RWX) != ACL_SUCC) {
137         REQUEST_HILOGE("AclSetAccess Child Dir Failed.");
138         return false;
139     }
140     return true;
141 }
142 
SetDirsPermission(std::vector<std::string> & dirs)143 bool CJRequestTask::SetDirsPermission(std::vector<std::string> &dirs)
144 {
145     if (dirs.empty()) {
146         return true;
147     }
148     std::string newPath = "/data/storage/el2/base/.ohos/.request/.certs";
149     std::vector<std::string> dirElems;
150     CJInitialize::StringSplit(newPath, '/', dirElems);
151     if (!CJInitialize::CreateDirs(dirElems)) {
152         REQUEST_HILOGE("CreateDirs Err: %{public}s", newPath.c_str());
153         return false;
154     }
155 
156     for (const auto &folderPath : dirs) {
157         fs::path folder = folderPath;
158         if (!(fs::exists(folder) && fs::is_directory(folder))) {
159             return false;
160         }
161         for (const auto &entry : fs::directory_iterator(folder)) {
162             fs::path path = entry.path();
163             std::string existfilePath = folder.string() + "/" + path.filename().string();
164             std::string newfilePath = newPath + "/" + path.filename().string();
165             if (!fs::exists(newfilePath)) {
166                 fs::copy(existfilePath, newfilePath);
167             }
168             if (chmod(newfilePath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) != 0) {
169                 REQUEST_HILOGD("File add OTH access Failed.");
170             }
171             REQUEST_HILOGD("current filePath is %{public}s", newfilePath.c_str());
172             if (!CJRequestTask::SetPathPermission(newfilePath)) {
173                 REQUEST_HILOGE("Set path permission fail.");
174                 return false;
175             }
176         }
177     }
178     if (!dirs.empty()) {
179         dirs.clear();
180         dirs.push_back(newPath);
181     }
182 
183     return true;
184 }
185 
AddPathMap(const std::string & filepath,const std::string & baseDir)186 void CJRequestTask::AddPathMap(const std::string &filepath, const std::string &baseDir)
187 {
188     std::string childDir(filepath);
189     std::string parentDir;
190     while (childDir.length() > baseDir.length()) {
191         parentDir = childDir.substr(0, childDir.rfind("/"));
192         std::lock_guard<std::mutex> lockGuard(CJRequestTask::pathMutex_);
193         auto it = pathMap_.find(parentDir);
194         if (it == pathMap_.end()) {
195             pathMap_[parentDir] = 1;
196         } else {
197             pathMap_[parentDir] += 1;
198         }
199         childDir = parentDir;
200     }
201 }
202 
ResetDirAccess(const std::string & filepath)203 void CJRequestTask::ResetDirAccess(const std::string &filepath)
204 {
205     int ret = AclSetAccess(filepath, SA_PERMISSION_CLEAN);
206     if (ret != ACL_SUCC) {
207         REQUEST_HILOGE("AclSetAccess Reset Dir Failed: %{public}s", filepath.c_str());
208     }
209 }
210 
RemovePathMap(const std::string & filepath)211 void CJRequestTask::RemovePathMap(const std::string &filepath)
212 {
213     std::string baseDir;
214     if (!CJInitialize::GetBaseDir(baseDir) || filepath.find(baseDir) == std::string::npos) {
215         REQUEST_HILOGE("File dir not found.");
216         return;
217     }
218 
219     if (chmod(filepath.c_str(), S_IRUSR | S_IWUSR | S_IRGRP) != 0) {
220         REQUEST_HILOGE("File remove WOTH access Failed.");
221     }
222 
223     std::string childDir(filepath);
224     std::string parentDir;
225     while (childDir.length() > baseDir.length()) {
226         parentDir = childDir.substr(0, childDir.rfind("/"));
227         std::lock_guard<std::mutex> lockGuard(CJRequestTask::pathMutex_);
228         auto it = pathMap_.find(parentDir);
229         if (it != pathMap_.end()) {
230             if (pathMap_[parentDir] <= 1) {
231                 pathMap_.erase(parentDir);
232                 ResetDirAccess(parentDir);
233             } else {
234                 pathMap_[parentDir] -= 1;
235             }
236         }
237         childDir = parentDir;
238     }
239 }
240 
RemoveDirsPermission(const std::vector<std::string> & dirs)241 void CJRequestTask::RemoveDirsPermission(const std::vector<std::string> &dirs)
242 {
243     for (const auto &folderPath : dirs) {
244         fs::path folder = folderPath;
245         for (const auto &entry : fs::directory_iterator(folder)) {
246             fs::path path = entry.path();
247             std::string filePath = folder.string() + "/" + path.filename().string();
248             RemovePathMap(filePath);
249         }
250     }
251 }
252 
RegisterForegroundResume()253 void CJRequestTask::RegisterForegroundResume()
254 {
255     if (register_) {
256         return;
257     }
258     register_ = true;
259     auto context = AbilityRuntime::ApplicationContext::GetInstance();
260     if (context == nullptr) {
261         REQUEST_HILOGE("Get ApplicationContext failed");
262         return;
263     }
264     context->RegisterAbilityLifecycleCallback(std::make_shared<CJAppStateCallback>());
265     REQUEST_HILOGD("Register foreground resume callback success");
266 }
267 
Create(Context * context,Config & config)268 ExceptionError CJRequestTask::Create(Context *context, Config &config)
269 {
270     int32_t seq = RequestManager::GetInstance()->GetNextSeq();
271     REQUEST_HILOGI("Begin task create, seq: %{public}d", seq);
272     config_ = config;
273 
274     ExceptionError err;
275     RequestManager::GetInstance()->RestoreListener(CJRequestTask::ReloadListener);
276 
277     if (config.mode == Mode::FOREGROUND) {
278         RegisterForegroundResume();
279     }
280 
281     int32_t ret = RequestManager::GetInstance()->Create(config_, seq, taskId_);
282     if (ret != ExceptionErrorCode::E_OK) {
283         REQUEST_HILOGE("Create task failed, in");
284         err.code = static_cast<ExceptionErrorCode>(ret);
285         return err;
286     }
287 
288     SetTid();
289     listenerMutex_.lock();
290     notifyDataListenerMap_[SubscribeType::REMOVE] =
291         std::make_shared<CJNotifyDataListener>(GetTidStr(), SubscribeType::REMOVE);
292     listenerMutex_.unlock();
293     RequestManager::GetInstance()->AddListener(GetTidStr(), SubscribeType::REMOVE,
294                                                notifyDataListenerMap_[SubscribeType::REMOVE]);
295 
296     AddTaskMap(GetTidStr(), this);
297 
298     return err;
299 }
300 
GetTask(OHOS::AbilityRuntime::Context * context,std::string & taskId,std::string & token,Config & config)301 ExceptionError CJRequestTask::GetTask(OHOS::AbilityRuntime::Context *context, std::string &taskId, std::string &token,
302                                       Config &config)
303 {
304     ExceptionError err;
305     int32_t seq = RequestManager::GetInstance()->GetNextSeq();
306     REQUEST_HILOGI("Begin get task, seq: %{public}d", seq);
307 
308     CJRequestTask *task = CJRequestTask::FindTaskById(taskId);
309     if (task != nullptr) {
310         if (task->config_.token != token) {
311             return ConvertError(ExceptionErrorCode::E_TASK_NOT_FOUND);
312         }
313         config = task->config_;
314         return err;
315     }
316 
317     int32_t result = RequestManager::GetInstance()->GetTask(taskId, token, config);
318     if (result != ExceptionErrorCode::E_OK) {
319         return ConvertError(result);
320     }
321     return err;
322 }
323 
Remove(const std::string & tid)324 ExceptionError CJRequestTask::Remove(const std::string &tid)
325 {
326     int32_t result = RequestManager::GetInstance()->Remove(tid, Version::API10);
327     if (result != ExceptionErrorCode::E_OK) {
328         return ConvertError(result);
329     }
330 
331     return ExceptionError();
332 }
333 
Touch(const std::string & tid,TaskInfo & task,const std::string & token)334 ExceptionError CJRequestTask::Touch(const std::string &tid, TaskInfo &task, const std::string &token)
335 {
336     ExceptionError err;
337     int32_t result = RequestManager::GetInstance()->Touch(tid, token, task);
338     if (result != ExceptionErrorCode::E_OK) {
339         return ConvertError(result);
340     }
341     return err;
342 }
343 
Search(const Filter & filter,std::vector<std::string> & tids)344 ExceptionError CJRequestTask::Search(const Filter &filter, std::vector<std::string> &tids)
345 {
346     ExceptionError err;
347     int32_t result = RequestManager::GetInstance()->Search(filter, tids);
348     if (result != ExceptionErrorCode::E_OK) {
349         return ConvertError(result);
350     }
351 
352     return err;
353 }
354 
ReloadListener()355 void CJRequestTask::ReloadListener()
356 {
357     REQUEST_HILOGD("ReloadListener in");
358     std::lock_guard<std::mutex> lockGuard(CJRequestTask::taskMutex_);
359     RequestManager::GetInstance()->ReopenChannel();
360     for (const auto &it : taskMap_) {
361         RequestManager::GetInstance()->Subscribe(it.first);
362     }
363 }
364 
On(std::string type,std::string & taskId,void * callback)365 ExceptionError CJRequestTask::On(std::string type, std::string &taskId, void *callback)
366 {
367     int32_t seq = RequestManager::GetInstance()->GetNextSeq();
368     REQUEST_HILOGI("Begin task on, seq: %{public}d", seq);
369 
370     ExceptionError err;
371     SubscribeType subscribeType = CJRequestEvent::StringToSubscribeType(type);
372     if (subscribeType == SubscribeType::BUTT) {
373         err.code = ExceptionErrorCode::E_PARAMETER_CHECK;
374         err.errInfo = "First parameter error";
375         return err;
376     }
377 
378     if (subscribeType == SubscribeType::RESPONSE) {
379         listenerMutex_.lock();
380         if (responseListener_ == nullptr) {
381             responseListener_ = std::make_shared<CJResponseListener>(GetTidStr());
382         }
383         listenerMutex_.unlock();
384         responseListener_->AddListener(CJLambda::Create((void (*)(CResponse progress))callback), callback);
385     } else {
386         listenerMutex_.lock();
387         auto listener = notifyDataListenerMap_.find(subscribeType);
388         if (listener == notifyDataListenerMap_.end()) {
389             notifyDataListenerMap_[subscribeType] = std::make_shared<CJNotifyDataListener>(GetTidStr(), subscribeType);
390         }
391         listenerMutex_.unlock();
392         notifyDataListenerMap_[subscribeType]->AddListener(CJLambda::Create((void (*)(CProgress progress))callback),
393                                                            (CFunc)callback);
394     }
395 
396     REQUEST_HILOGI("End task on event %{public}s successfully, seq: %{public}d, tid: %{public}s", type.c_str(), seq,
397                    GetTidStr().c_str());
398 
399     return err;
400 }
401 
Off(std::string event,CFunc callback)402 ExceptionError CJRequestTask::Off(std::string event, CFunc callback)
403 {
404     int32_t seq = RequestManager::GetInstance()->GetNextSeq();
405     REQUEST_HILOGI("Begin task off, seq: %{public}d", seq);
406 
407     ExceptionError err;
408     SubscribeType subscribeType = CJRequestEvent::StringToSubscribeType(event);
409     if (subscribeType == SubscribeType::BUTT) {
410         err.code = ExceptionErrorCode::E_PARAMETER_CHECK;
411         err.errInfo = "First parameter error";
412         return err;
413     }
414 
415     listenerMutex_.lock();
416     if (subscribeType == SubscribeType::RESPONSE) {
417         if (responseListener_ == nullptr) {
418             responseListener_ = std::make_shared<CJResponseListener>(GetTidStr());
419         }
420     } else {
421         auto listener = notifyDataListenerMap_.find(subscribeType);
422         if (listener == notifyDataListenerMap_.end()) {
423             notifyDataListenerMap_[subscribeType] = std::make_shared<CJNotifyDataListener>(GetTidStr(), subscribeType);
424         }
425     }
426     listenerMutex_.unlock();
427     notifyDataListenerMap_[subscribeType]->RemoveListener((CFunc)callback);
428 
429     return err;
430 }
431 
ClearTaskTemp(const std::string & tid,bool isRmFiles,bool isRmAcls,bool isRmCertsAcls)432 void CJRequestTask::ClearTaskTemp(const std::string &tid, bool isRmFiles, bool isRmAcls, bool isRmCertsAcls)
433 {
434     std::lock_guard<std::mutex> lockGuard(CJRequestTask::taskMutex_);
435     auto item = CJRequestTask::taskMap_.find(tid);
436     if (item == CJRequestTask::taskMap_.end()) {
437         REQUEST_HILOGD("Clear task tmp files, not find task");
438         return;
439     }
440     auto task = item->second;
441     if (isRmFiles) {
442         auto bodyFileNames = task->config_.bodyFileNames;
443         for (auto &filePath : bodyFileNames) {
444             RemovePathMap(filePath);
445             RemoveFile(filePath);
446         }
447     }
448     if (isRmAcls) {
449         // Reset Acl permission
450         for (auto &file : task->config_.files) {
451             RemovePathMap(file.uri);
452         }
453     }
454     if (isRmCertsAcls) {
455         RemoveDirsPermission(task->config_.certsPath);
456     }
457 }
458 
459 } // namespace OHOS::CJSystemapi::Request