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