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