• 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 <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