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