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 <charconv>
17
18 #include "cjson_helper.h"
19 #include "timer_manager_interface.h"
20
21 namespace OHOS {
22 namespace MiscServices {
23 namespace {
24 constexpr const char* DB_PATH = "/data/service/el1/public/database/time/time.json";
25 constexpr size_t INDEX_TWO = 2;
26 }
27 std::mutex CjsonHelper::mutex_;
28
GetInstance()29 CjsonHelper &CjsonHelper::GetInstance()
30 {
31 static CjsonHelper cjsonHelper;
32 return cjsonHelper;
33 }
34
CjsonHelper()35 CjsonHelper::CjsonHelper()
36 {
37 std::ifstream file(DB_PATH);
38 if (file.is_open()) {
39 file.close();
40 return;
41 }
42
43 std::ofstream newFile(DB_PATH);
44 if (!newFile.is_open()) {
45 TIME_HILOGE(TIME_MODULE_SERVICE, "Create new file fail");
46 return;
47 }
48 cJSON* root = cJSON_CreateObject();
49 cJSON* holdTable = cJSON_CreateArray();
50 cJSON* dropTable = cJSON_CreateArray();
51 cJSON_AddItemToObject(root, HOLD_ON_REBOOT, holdTable);
52 cJSON_AddItemToObject(root, DROP_ON_REBOOT, dropTable);
53 char* jsonString = cJSON_Print(root);
54 if (jsonString != nullptr) {
55 newFile << jsonString;
56 free(jsonString);
57 }
58 cJSON_Delete(root);
59 newFile.close();
60 }
61
LoadAndParseJsonFile(const std::string & tableName,cJSON * & db,cJSON * & table)62 bool CjsonHelper::LoadAndParseJsonFile(const std::string& tableName, cJSON* &db, cJSON* &table)
63 {
64 db = nullptr;
65 table = nullptr;
66 std::ifstream file(DB_PATH);
67 if (!file.good()) {
68 TIME_HILOGE(TIME_MODULE_SERVICE, "open json file fail!");
69 return false;
70 }
71 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
72 db = cJSON_Parse(fileContent.c_str());
73 table = cJSON_GetObjectItem(db, tableName.c_str());
74 if (table == NULL) {
75 TIME_HILOGE(TIME_MODULE_SERVICE, "%{public}s get fail!", tableName.c_str());
76 cJSON_Delete(db);
77 db = nullptr;
78 return false;
79 }
80 return true;
81 }
82
QueryWant(std::string tableName,uint64_t timerId)83 std::string CjsonHelper::QueryWant(std::string tableName, uint64_t timerId)
84 {
85 std::string data = "";
86 cJSON* db = NULL;
87 cJSON* table = QueryTable(tableName, &db);
88 if (table == NULL) {
89 TIME_HILOGE(TIME_MODULE_SERVICE, "QueryTable fail!");
90 cJSON_Delete(db);
91 return data;
92 }
93
94 int size = cJSON_GetArraySize(table);
95 for (int i = 0; i < size; ++i) {
96 cJSON* obj = cJSON_GetArrayItem(table, i);
97
98 auto item = cJSON_GetObjectItem(obj, "timerId");
99 if (!IsString(item)) {
100 continue;
101 }
102 if (item->valuestring == std::to_string(timerId)) {
103 item = cJSON_GetObjectItem(obj, "wantAgent");
104 if (IsString(item)) {
105 data = item->valuestring;
106 }
107 break;
108 }
109 }
110 cJSON_Delete(db);
111 return data;
112 }
113
114 // must cJSON_Delete(db) after use, avoid memory leak.
QueryTable(std::string tableName,cJSON ** db)115 cJSON* CjsonHelper::QueryTable(std::string tableName, cJSON** db)
116 {
117 cJSON* data = NULL;
118 std::lock_guard<std::mutex> lock(mutex_);
119
120 std::ifstream file(DB_PATH);
121 if (!file.good()) {
122 TIME_HILOGE(TIME_MODULE_SERVICE, "open json file fail!");
123 return data;
124 }
125 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
126 *db = cJSON_Parse(fileContent.c_str());
127 cJSON* table = cJSON_GetObjectItem(*db, tableName.c_str());
128 if (table == NULL) {
129 TIME_HILOGE(TIME_MODULE_SERVICE, "%{public}s get fail!", tableName.c_str());
130 return data;
131 }
132
133 data = table;
134 return data;
135 }
136
StrToI64(std::string str,int64_t & value)137 bool CjsonHelper::StrToI64(std::string str, int64_t& value)
138 {
139 auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), value);
140 return ec == std::errc{} && ptr == str.data() + str.size();
141 }
142
Compare(const std::tuple<std::string,std::string,int64_t> & a,const std::tuple<std::string,std::string,int64_t> & b)143 bool Compare(const std::tuple<std::string, std::string, int64_t>& a,
144 const std::tuple<std::string, std::string, int64_t>& b)
145 {
146 return std::get<INDEX_TWO>(a) < std::get<INDEX_TWO>(b);
147 }
148
QueryAutoReboot()149 std::vector<std::tuple<std::string, std::string, int64_t>> CjsonHelper::QueryAutoReboot()
150 {
151 std::vector<std::tuple<std::string, std::string, int64_t>> result;
152 cJSON* db = NULL;
153 cJSON* table = QueryTable(HOLD_ON_REBOOT, &db);
154 if (table == NULL) {
155 TIME_HILOGE(TIME_MODULE_SERVICE, "QueryTable fail!");
156 cJSON_Delete(db);
157 return result;
158 }
159 int size = cJSON_GetArraySize(table);
160 for (int i = 0; i < size; ++i) {
161 cJSON* obj = cJSON_GetArrayItem(table, i);
162
163 auto state = cJSON_GetObjectItem(obj, "state");
164 if (!IsNumber(state)) {
165 continue;
166 }
167 if (state->valueint == 1) {
168 auto item = cJSON_GetObjectItem(obj, "bundleName");
169 if (!IsString(item)) {
170 continue;
171 }
172 std::string bundleName = item->valuestring;
173
174 item = cJSON_GetObjectItem(obj, "name");
175 if (!IsString(item)) {
176 continue;
177 }
178 std::string name = item->valuestring;
179
180 item = cJSON_GetObjectItem(obj, "triggerTime");
181 if (!IsString(item)) {
182 continue;
183 }
184 int64_t triggerTime;
185 if (!StrToI64(item->valuestring, triggerTime)) {
186 continue;
187 }
188 std::tuple<std::string, std::string, int64_t> tuple(bundleName, name, triggerTime);
189 result.push_back(tuple);
190 }
191 }
192 cJSON_Delete(db);
193 std::sort(result.begin(), result.end(), Compare);
194 return result;
195 }
196
Insert(std::string tableName,std::shared_ptr<TimerEntry> timerInfo)197 bool CjsonHelper::Insert(std::string tableName, std::shared_ptr<TimerEntry> timerInfo)
198 {
199 cJSON* newLine = cJSON_CreateObject();
200
201 cJSON_AddStringToObject(newLine, "name", timerInfo->name.c_str());
202 cJSON_AddStringToObject(newLine, "timerId", std::to_string(timerInfo->id).c_str());
203 cJSON_AddNumberToObject(newLine, "type", timerInfo->type);
204 cJSON_AddNumberToObject(newLine, "flag", timerInfo->flag);
205 cJSON_AddNumberToObject(newLine, "windowLength", timerInfo->windowLength);
206 cJSON_AddNumberToObject(newLine, "interval", timerInfo->interval);
207 cJSON_AddNumberToObject(newLine, "uid", timerInfo->uid);
208 cJSON_AddNumberToObject(newLine, "pid", timerInfo->pid);
209 cJSON_AddStringToObject(newLine, "bundleName", timerInfo->bundleName.c_str());
210 cJSON_AddStringToObject(newLine, "wantAgent",
211 OHOS::AbilityRuntime::WantAgent::WantAgentHelper::ToString(timerInfo->wantAgent).c_str());
212 cJSON_AddNumberToObject(newLine, "state", 0);
213 cJSON_AddStringToObject(newLine, "triggerTime", "0");
214
215 std::lock_guard<std::mutex> lock(mutex_);
216 std::ifstream file(DB_PATH);
217 if (!file.good()) {
218 TIME_HILOGE(TIME_MODULE_SERVICE, "open json file fail!");
219 cJSON_Delete(newLine);
220 return false;
221 }
222 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
223 cJSON* db = cJSON_Parse(fileContent.c_str());
224 cJSON* table = cJSON_GetObjectItem(db, tableName.c_str());
225 if (table == NULL) {
226 TIME_HILOGE(TIME_MODULE_SERVICE, "%{public}s get fail!", tableName.c_str());
227 cJSON_Delete(db);
228 cJSON_Delete(newLine);
229 return false;
230 }
231 cJSON_AddItemToArray(table, newLine);
232 SaveJson(db);
233 cJSON_Delete(db);
234 return true;
235 }
236
UpdateTrigger(std::string tableName,int64_t timerId,int64_t triggerTime)237 bool CjsonHelper::UpdateTrigger(std::string tableName, int64_t timerId, int64_t triggerTime)
238 {
239 std::lock_guard<std::mutex> lock(mutex_);
240
241 cJSON* db = nullptr;
242 cJSON* table = nullptr;
243 if (!LoadAndParseJsonFile(tableName, db, table)) {
244 return false;
245 }
246
247 int size = cJSON_GetArraySize(table);
248 for (int i = 0; i < size; ++i) {
249 cJSON* obj = cJSON_GetArrayItem(table, i);
250
251 auto timerIdObj = cJSON_GetObjectItem(obj, "timerId");
252 if (!IsString(timerIdObj)) {
253 continue;
254 }
255 if (timerIdObj->valuestring == std::to_string(timerId)) {
256 cJSON_ReplaceItemInObject(obj, "state", cJSON_CreateNumber(1));
257 cJSON_ReplaceItemInObject(obj, "triggerTime", cJSON_CreateString(std::to_string(triggerTime).c_str()));
258 SaveJson(db);
259 break;
260 }
261 }
262 cJSON_Delete(db);
263 return true;
264 }
265
UpdateTriggerGroup(std::string tableName,std::vector<std::pair<uint64_t,uint64_t>> timerVec)266 bool CjsonHelper::UpdateTriggerGroup(std::string tableName, std::vector<std::pair<uint64_t, uint64_t>> timerVec)
267 {
268 if (timerVec.empty()) {
269 return false;
270 }
271 std::lock_guard<std::mutex> lock(mutex_);
272
273 cJSON* db = nullptr;
274 cJSON* table = nullptr;
275 if (!LoadAndParseJsonFile(tableName, db, table)) {
276 return false;
277 }
278
279 int size = cJSON_GetArraySize(table);
280 for (int i = 0; i < size; ++i) {
281 cJSON* obj = cJSON_GetArrayItem(table, i);
282
283 auto timerIdObj = cJSON_GetObjectItem(obj, "timerId");
284 if (!IsString(timerIdObj)) {
285 continue;
286 }
287 for (auto it = timerVec.begin(); it != timerVec.end(); ++it) {
288 std::string timerId = std::to_string(it->first);
289 if (timerIdObj->valuestring == timerId) {
290 cJSON_ReplaceItemInObject(obj, "state", cJSON_CreateNumber(1));
291 std::string triggerTime = std::to_string(it->second);
292 cJSON_ReplaceItemInObject(obj, "triggerTime", cJSON_CreateString(triggerTime.c_str()));
293 }
294 }
295 }
296 SaveJson(db);
297 cJSON_Delete(db);
298 return true;
299 }
300
UpdateState(std::string tableName,int64_t timerId)301 bool CjsonHelper::UpdateState(std::string tableName, int64_t timerId)
302 {
303 std::lock_guard<std::mutex> lock(mutex_);
304
305 cJSON* db = nullptr;
306 cJSON* table = nullptr;
307 if (!LoadAndParseJsonFile(tableName, db, table)) {
308 return false;
309 }
310
311 int size = cJSON_GetArraySize(table);
312 for (int i = 0; i < size; ++i) {
313 cJSON* obj = cJSON_GetArrayItem(table, i);
314
315 auto timerIdObj = cJSON_GetObjectItem(obj, "timerId");
316 auto stateObj = cJSON_GetObjectItem(obj, "state");
317 if (!IsString(timerIdObj) || !IsNumber(stateObj)) {
318 continue;
319 }
320 if (timerIdObj->valuestring == std::to_string(timerId) && stateObj->valueint == 1) {
321 cJSON_ReplaceItemInObject(obj, "state", cJSON_CreateNumber(0));
322 SaveJson(db);
323 break;
324 }
325 }
326 cJSON_Delete(db);
327 return true;
328 }
329
Delete(std::string tableName,int64_t timerId)330 bool CjsonHelper::Delete(std::string tableName, int64_t timerId)
331 {
332 std::lock_guard<std::mutex> lock(mutex_);
333
334 cJSON* db = nullptr;
335 cJSON* table = nullptr;
336 if (!LoadAndParseJsonFile(tableName, db, table)) {
337 return false;
338 }
339
340 int size = cJSON_GetArraySize(table);
341 for (int i = 0; i < size; ++i) {
342 cJSON* obj = cJSON_GetArrayItem(table, i);
343
344 auto timerIdObj = cJSON_GetObjectItem(obj, "timerId");
345 if (!IsString(timerIdObj)) {
346 continue;
347 }
348 if (timerIdObj->valuestring == std::to_string(timerId)) {
349 cJSON_DeleteItemFromArray(table, i);
350 SaveJson(db);
351 break;
352 }
353 }
354 cJSON_Delete(db);
355 return true;
356 }
357
ClearInvaildDataInHoldOnReboot()358 bool CjsonHelper::ClearInvaildDataInHoldOnReboot()
359 {
360 std::lock_guard<std::mutex> lock(mutex_);
361
362 std::ifstream file(DB_PATH);
363 if (!file.good()) {
364 TIME_HILOGE(TIME_MODULE_SERVICE, "open json file fail!");
365 return false;
366 }
367 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
368 cJSON* db = cJSON_Parse(fileContent.c_str());
369 cJSON* table = cJSON_GetObjectItem(db, HOLD_ON_REBOOT);
370 if (table == NULL) {
371 TIME_HILOGE(TIME_MODULE_SERVICE, "HOLD_ON_REBOOT get fail!");
372 cJSON_Delete(db);
373 return false;
374 }
375
376 int size = cJSON_GetArraySize(table);
377 for (int i = size - 1; i >= 0; --i) {
378 cJSON* obj = cJSON_GetArrayItem(table, i);
379
380 auto stateObj = cJSON_GetObjectItem(obj, "state");
381 auto typeObj = cJSON_GetObjectItem(obj, "type");
382 if (!IsNumber(stateObj) || !IsNumber(typeObj)) {
383 continue;
384 }
385 if (stateObj->valueint == 0
386 || typeObj->valueint == ITimerManager::ELAPSED_REALTIME_WAKEUP
387 || typeObj->valueint == ITimerManager::ELAPSED_REALTIME) {
388 cJSON_DeleteItemFromArray(table, i);
389 }
390 }
391 SaveJson(db);
392 cJSON_Delete(db);
393 return true;
394 }
395
Clear(std::string tableName)396 void CjsonHelper::Clear(std::string tableName)
397 {
398 std::lock_guard<std::mutex> lock(mutex_);
399
400 std::ifstream file(DB_PATH);
401 if (!file.good()) {
402 TIME_HILOGE(TIME_MODULE_SERVICE, "open json file fail!");
403 return;
404 }
405 std::string fileContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
406 cJSON* db = cJSON_Parse(fileContent.c_str());
407 cJSON* table = cJSON_GetObjectItem(db, tableName.c_str());
408 if (table == NULL) {
409 TIME_HILOGE(TIME_MODULE_SERVICE, "%{public}s get json fail!", tableName.c_str());
410 cJSON_Delete(db);
411 return;
412 }
413
414 int size = cJSON_GetArraySize(table);
415 for (int i = size - 1; i >= 0; --i) {
416 cJSON_DeleteItemFromArray(table, i);
417 }
418 SaveJson(db);
419 cJSON_Delete(db);
420 }
421
SaveJson(cJSON * data)422 void CjsonHelper::SaveJson(cJSON* data)
423 {
424 std::ofstream outFile(DB_PATH);
425 char* jsonString = cJSON_Print(data);
426 if (jsonString != nullptr) {
427 outFile << jsonString;
428 free(jsonString);
429 }
430 outFile.close();
431 }
432
IsNumber(cJSON * item)433 bool CjsonHelper::IsNumber(cJSON* item)
434 {
435 return (item != NULL && cJSON_IsNumber(item));
436 }
437
IsString(cJSON * item)438 bool CjsonHelper::IsString(cJSON* item)
439 {
440 return (item != NULL && cJSON_IsString(item));
441 }
442 }
443 }
444