1 /*
2 * Copyright (c) 2022 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 #include "data_storage_helper.h"
16
17 #include <fcntl.h>
18 #include <fstream>
19 #include <unistd.h>
20 #include <sstream>
21 #include <sys/stat.h>
22 #include <sys/statfs.h>
23
24 #include "common_utils.h"
25 #include "continuous_task_log.h"
26 #include "config_policy_utils.h"
27 #include "directory_ex.h"
28 #include "hisysevent.h"
29 #include <file_ex.h>
30
31 namespace OHOS {
32 namespace BackgroundTaskMgr {
33 namespace {
34 static constexpr char TASK_RECORD_FILE_PATH[] = "/data/service/el1/public/background_task_mgr/running_task";
35 static const std::string RESOURCE_RECORD_FILE_PATH = "/data/service/el1/public/background_task_mgr/resource_record";
36 static const std::string APP_RESOURCE_RECORD = "appResourceRecord";
37 static const std::string PROCESS_RESOURCE_RECORD = "processResourceRecord";
38 const std::string PARAM = "param";
39 const std::string FAST_FROZEN = "fast_frozen";
40 const std::string ENABLE = "enable";
41 const std::string DOZE_TIME = "doze_time";
42 }
43
DataStorageHelper()44 DataStorageHelper::DataStorageHelper() {}
45
~DataStorageHelper()46 DataStorageHelper::~DataStorageHelper() {}
47
RefreshTaskRecord(const std::unordered_map<std::string,std::shared_ptr<ContinuousTaskRecord>> & allRecord)48 ErrCode DataStorageHelper::RefreshTaskRecord(const std::unordered_map<std::string,
49 std::shared_ptr<ContinuousTaskRecord>> &allRecord)
50 {
51 nlohmann::json root;
52 for (const auto &iter : allRecord) {
53 auto record = iter.second;
54 std::string data = record->ParseToJsonStr();
55 nlohmann::json recordJson = nlohmann::json::parse(data, nullptr, false);;
56 if (!recordJson.is_discarded()) {
57 root[iter.first] = recordJson;
58 }
59 }
60 if (access(TASK_RECORD_FILE_PATH, F_OK) == ERR_OK) {
61 BGTASK_LOGD("the file: %{private}s already exists.", TASK_RECORD_FILE_PATH);
62 } else {
63 FILE *file = fopen(TASK_RECORD_FILE_PATH, "w+");
64 if (file == nullptr) {
65 BGTASK_LOGE("Fail to open file: %{private}s, errno: %{public}s", TASK_RECORD_FILE_PATH, strerror(errno));
66 return ERR_BGTASK_CREATE_FILE_ERR;
67 }
68 int closeResult = fclose(file);
69 if (closeResult < 0) {
70 BGTASK_LOGE("Fail to close file: %{private}s, errno: %{public}s", TASK_RECORD_FILE_PATH, strerror(errno));
71 return ERR_BGTASK_CREATE_FILE_ERR;
72 }
73 }
74 return SaveJsonValueToFile(root.dump(CommonUtils::jsonFormat_), TASK_RECORD_FILE_PATH);
75 }
76
RestoreTaskRecord(std::unordered_map<std::string,std::shared_ptr<ContinuousTaskRecord>> & allRecord)77 ErrCode DataStorageHelper::RestoreTaskRecord(std::unordered_map<std::string,
78 std::shared_ptr<ContinuousTaskRecord>> &allRecord)
79 {
80 nlohmann::json root;
81 if (ParseJsonValueFromFile(root, TASK_RECORD_FILE_PATH) != ERR_OK) {
82 return ERR_BGTASK_DATA_STORAGE_ERR;
83 }
84 for (auto iter = root.begin(); iter != root.end(); iter++) {
85 nlohmann::json recordJson = iter.value();
86 std::shared_ptr<ContinuousTaskRecord> record = std::make_shared<ContinuousTaskRecord>();
87 if (record->ParseFromJson(recordJson)) {
88 allRecord.emplace(iter.key(), record);
89 }
90 }
91 return ERR_OK;
92 }
93
RefreshResourceRecord(const ResourceRecordMap & appRecord,const ResourceRecordMap & processRecord)94 ErrCode DataStorageHelper::RefreshResourceRecord(const ResourceRecordMap &appRecord,
95 const ResourceRecordMap &processRecord)
96 {
97 std::string record {""};
98 ConvertMapToString(appRecord, processRecord, record);
99 if (access(RESOURCE_RECORD_FILE_PATH.c_str(), F_OK) == ERR_OK) {
100 BGTASK_LOGD("the file: %{private}s already exists.", RESOURCE_RECORD_FILE_PATH.c_str());
101 } else {
102 FILE *file = fopen(RESOURCE_RECORD_FILE_PATH.c_str(), "w+");
103 if (file == nullptr) {
104 BGTASK_LOGE("Fail to open file: %{private}s, errno: %{public}s",
105 RESOURCE_RECORD_FILE_PATH.c_str(), strerror(errno));
106 return ERR_BGTASK_CREATE_FILE_ERR;
107 }
108 int closeResult = fclose(file);
109 if (closeResult < 0) {
110 BGTASK_LOGE("Fail to close file: %{private}s, errno: %{public}s",
111 RESOURCE_RECORD_FILE_PATH.c_str(), strerror(errno));
112 return ERR_BGTASK_CREATE_FILE_ERR;
113 }
114 }
115 return SaveJsonValueToFile(record, RESOURCE_RECORD_FILE_PATH);
116 }
117
RestoreResourceRecord(ResourceRecordMap & appRecord,ResourceRecordMap & processRecord)118 ErrCode DataStorageHelper::RestoreResourceRecord(ResourceRecordMap &appRecord,
119 ResourceRecordMap &processRecord)
120 {
121 nlohmann::json root;
122 if (ParseJsonValueFromFile(root, RESOURCE_RECORD_FILE_PATH) != ERR_OK) {
123 BGTASK_LOGD("can not read string form file: %{private}s", RESOURCE_RECORD_FILE_PATH.c_str());
124 return ERR_BGTASK_DATA_STORAGE_ERR;
125 }
126 DivideJsonToMap(root, appRecord, processRecord);
127 return ERR_OK;
128 }
129
SaveJsonValueToFile(const std::string & value,const std::string & filePath)130 int32_t DataStorageHelper::SaveJsonValueToFile(const std::string &value, const std::string &filePath)
131 {
132 std::ofstream fout;
133 std::string realPath;
134 if (!ConvertFullPath(filePath, realPath)) {
135 BGTASK_LOGE("SaveJsonValueToFile Get real file path: %{private}s failed", filePath.c_str());
136 return ERR_BGTASK_GET_ACTUAL_FILE_ERR;
137 }
138 fout.open(realPath, std::ios::out);
139 if (!fout.is_open()) {
140 BGTASK_LOGE("Open file: %{private}s failed.", filePath.c_str());
141 return ERR_BGTASK_OPEN_FILE_ERR;
142 }
143 fout << value.c_str() << std::endl;
144 fout.close();
145 if (filePath == TASK_RECORD_FILE_PATH) {
146 ReportUserDataSizeEvent();
147 }
148 return ERR_OK;
149 }
150
ParseFastSuspendDozeTime(const std::string & FilePath,int & time)151 bool DataStorageHelper::ParseFastSuspendDozeTime(const std::string &FilePath, int &time)
152 {
153 nlohmann::json jsonObj;
154 std::string absolutePath = GetConfigFileAbsolutePath(FilePath);
155 if (ParseJsonValueFromFile(jsonObj, absolutePath) != ERR_OK) {
156 return false;
157 }
158 if (jsonObj.is_null() || !jsonObj.is_object() || !CommonUtils::CheckJsonValue(jsonObj, {PARAM})) {
159 BGTASK_LOGW("check jsonObj value failed.");
160 return false;
161 }
162 nlohmann::json param = jsonObj[PARAM];
163 if (param.is_null() || !param.is_object() || !CommonUtils::CheckJsonValue(param, {FAST_FROZEN})) {
164 BGTASK_LOGW("check param value failed.");
165 return false;
166 }
167 nlohmann::json fastFrozen = param[FAST_FROZEN];
168 if (fastFrozen.is_null() || !fastFrozen.is_object() ||
169 !CommonUtils::CheckJsonValue(fastFrozen, {ENABLE, DOZE_TIME})) {
170 BGTASK_LOGW("check fastFrozen value failed.");
171 return false;
172 }
173 if (!fastFrozen[ENABLE].is_boolean() || !fastFrozen.at(ENABLE).get<bool>()) {
174 BGTASK_LOGW("fast suspend switch is Disable");
175 return false;
176 }
177 if (!fastFrozen[DOZE_TIME].is_number_integer()) {
178 BGTASK_LOGW("fast suspend num is invalid");
179 return false;
180 }
181 time = fastFrozen.at(DOZE_TIME).get<int>();
182 return true;
183 }
184
ParseJsonValueFromFile(nlohmann::json & value,const std::string & filePath)185 int32_t DataStorageHelper::ParseJsonValueFromFile(nlohmann::json &value, const std::string &filePath)
186 {
187 std::string realPath;
188 if (!ConvertFullPath(filePath, realPath)) {
189 BGTASK_LOGE("Get real path failed");
190 return ERR_BGTASK_DATA_STORAGE_ERR;
191 }
192 std::string data;
193 LoadStringFromFile(realPath.c_str(), data);
194 value = nlohmann::json::parse(data, nullptr, false);
195 if (value.is_discarded()) {
196 BGTASK_LOGE("failed due to data is discarded");
197 return ERR_BGTASK_DATA_STORAGE_ERR;
198 }
199 return ERR_OK;
200 }
201
GetConfigFileAbsolutePath(const std::string & relativePath)202 std::string DataStorageHelper::GetConfigFileAbsolutePath(const std::string &relativePath)
203 {
204 if (relativePath.empty()) {
205 BGTASK_LOGE("relativePath is empty");
206 return "";
207 }
208 char buf[PATH_MAX];
209 char *tmpPath = GetOneCfgFile(relativePath.c_str(), buf, PATH_MAX);
210 char absolutePath[PATH_MAX] = {0};
211 if (!tmpPath || strlen(tmpPath) > PATH_MAX || !realpath(tmpPath, absolutePath)) {
212 BGTASK_LOGE("get file fail.");
213 return "";
214 }
215 return std::string(absolutePath);
216 }
217
ConvertFullPath(const std::string & partialPath,std::string & fullPath)218 bool DataStorageHelper::ConvertFullPath(const std::string& partialPath, std::string& fullPath)
219 {
220 if (partialPath.empty() || partialPath.length() >= PATH_MAX) {
221 return false;
222 }
223 char tmpPath[PATH_MAX] = {0};
224 if (realpath(partialPath.c_str(), tmpPath) == nullptr) {
225 return false;
226 }
227 fullPath = tmpPath;
228 return true;
229 }
230
ConvertMapToString(const ResourceRecordMap & appRecord,const ResourceRecordMap & processRecord,std::string & recordString)231 void DataStorageHelper::ConvertMapToString(const ResourceRecordMap &appRecord,
232 const ResourceRecordMap &processRecord, std::string &recordString)
233 {
234 nlohmann::json root;
235 nlohmann::json appValue;
236 ConvertMapToJson(appRecord, appValue);
237 root[APP_RESOURCE_RECORD] = appValue;
238 nlohmann::json processValue;
239 ConvertMapToJson(processRecord, processValue);
240 root[PROCESS_RESOURCE_RECORD] = processValue;
241 recordString = root.dump(CommonUtils::jsonFormat_);
242 }
243
ConvertMapToJson(const ResourceRecordMap & appRecord,nlohmann::json & root)244 void DataStorageHelper::ConvertMapToJson(const ResourceRecordMap &appRecord, nlohmann::json &root)
245 {
246 for (const auto &iter : appRecord) {
247 nlohmann::json value;
248 iter.second->ParseToJson(value);
249 root[std::to_string(iter.first)] = value;
250 }
251 }
252
DivideJsonToMap(nlohmann::json & root,ResourceRecordMap & appRecord,ResourceRecordMap & processRecord)253 void DataStorageHelper::DivideJsonToMap(nlohmann::json &root,
254 ResourceRecordMap &appRecord, ResourceRecordMap &processRecord)
255 {
256 if (root.contains(APP_RESOURCE_RECORD) && root.at(APP_RESOURCE_RECORD).is_object()) {
257 nlohmann::json appRecordJson = root.at(APP_RESOURCE_RECORD);
258 ConvertJsonToMap(appRecordJson, appRecord);
259 } else {
260 BGTASK_LOGE("can not read appRecord, json init fail");
261 }
262 if (root.contains(PROCESS_RESOURCE_RECORD) && root.at(PROCESS_RESOURCE_RECORD).is_object()) {
263 nlohmann::json processrecordJson = root.at(PROCESS_RESOURCE_RECORD);
264 ConvertJsonToMap(processrecordJson, processRecord);
265 } else {
266 BGTASK_LOGE("can not read processRecord, json init fail");
267 }
268 }
269
ConvertJsonToMap(const nlohmann::json & value,ResourceRecordMap & recordMap)270 void DataStorageHelper::ConvertJsonToMap(const nlohmann::json &value, ResourceRecordMap &recordMap)
271 {
272 for (auto iter = value.begin(); iter != value.end(); iter++) {
273 std::shared_ptr<ResourceApplicationRecord> recordPtr = std::make_shared<ResourceApplicationRecord>();
274 recordPtr->ParseFromJson(iter.value());
275 recordMap.emplace(static_cast<uint32_t>(std::atoi(iter.key().c_str())), recordPtr);
276 }
277 }
278
GetRemainPartitionSize(const std::string & partitionName)279 uint64_t GetRemainPartitionSize(const std::string& partitionName)
280 {
281 struct statfs stat;
282 if (statfs(partitionName.c_str(), &stat) != 0) {
283 return -1;
284 }
285 uint64_t blockSize = stat.f_bsize;
286 uint64_t freeSize = stat.f_bfree * blockSize;
287 constexpr double units = 1024.0;
288 return freeSize / (units * units);
289 }
290
GetFileOrFolderSize(const std::vector<std::string> & paths)291 std::vector<uint64_t> GetFileOrFolderSize(const std::vector<std::string>& paths)
292 {
293 std::vector<uint64_t> folderSize;
294 for (auto path : paths) {
295 folderSize.emplace_back(OHOS::GetFolderSize(path));
296 }
297 return folderSize;
298 }
299
ReportUserDataSizeEvent()300 void DataStorageHelper::ReportUserDataSizeEvent()
301 {
302 std::vector<std::string> paths = {
303 "/data/service/el1/public/background_task_mgr/"
304 };
305 uint64_t remainPartitionSize = GetRemainPartitionSize("/data");
306 std::vector<uint64_t> folderSize = GetFileOrFolderSize(paths);
307 HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::FILEMANAGEMENT, "USER_DATA_SIZE",
308 HiviewDFX::HiSysEvent::EventType::STATISTIC,
309 "COMPONENT_NAME", "background_task_mgr",
310 "PARTITION_NAME", "/data",
311 "REMAIN_PARTITION_SIZE", remainPartitionSize,
312 "FILE_OR_FOLDER_PATH", paths,
313 "FILE_OR_FOLDER_SIZE", folderSize);
314 }
315 } // namespace BackgroundTaskMgr
316 } // namespace OHOS
317
318