1 /*
2  * Copyright (c) 2023 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 "timer_database.h"
16 #include "time_hilog.h"
17 #include "time_common.h"
18 
19 namespace OHOS {
20 namespace MiscServices {
21 constexpr const char *CREATE_TIME_TIMER_HOLD_ON_REBOOT = "CREATE TABLE IF NOT EXISTS hold_on_reboot "
22                                                          "(timerId INTEGER PRIMARY KEY, "
23                                                          "type INTEGER, "
24                                                          "flag INTEGER, "
25                                                          "windowLength INTEGER, "
26                                                          "interval INTEGER, "
27                                                          "uid INTEGER, "
28                                                          "bundleName TEXT, "
29                                                          "wantAgent TEXT, "
30                                                          "state INTEGER, "
31                                                          "triggerTime INTEGER, "
32                                                          "pid INTEGER)";
33 
34 constexpr const char *CREATE_TIME_TIMER_DROP_ON_REBOOT = "CREATE TABLE IF NOT EXISTS drop_on_reboot "
35                                                          "(timerId INTEGER PRIMARY KEY, "
36                                                          "type INTEGER, "
37                                                          "flag INTEGER, "
38                                                          "windowLength INTEGER, "
39                                                          "interval INTEGER, "
40                                                          "uid INTEGER, "
41                                                          "bundleName TEXT, "
42                                                          "wantAgent TEXT, "
43                                                          "state INTEGER, "
44                                                          "triggerTime INTEGER, "
45                                                          "pid INTEGER)";
46 
47 constexpr const char *HOLD_ON_REBOOT_ADD_COLUMN = "ALTER TABLE hold_on_reboot ADD COLUMN pid INTEGER";
48 
49 constexpr const char *DROP_ON_REBOOT_ADD_COLUMN = "ALTER TABLE drop_on_reboot ADD COLUMN pid INTEGER";
50 
TimeDatabase()51 TimeDatabase::TimeDatabase()
52 {
53     int errCode = OHOS::NativeRdb::E_OK;
54     OHOS::NativeRdb::RdbStoreConfig config(DB_NAME);
55     config.SetSecurityLevel(NativeRdb::SecurityLevel::S1);
56     config.SetEncryptStatus(false);
57     config.SetReadConSize(1);
58     TimeDBOpenCallback timeDBOpenCallback;
59     store_ = OHOS::NativeRdb::RdbHelper::GetRdbStore(config, DATABASE_OPEN_VERSION_2, timeDBOpenCallback, errCode);
60     TIME_HILOGI(TIME_MODULE_SERVICE, "Gets time database, ret: %{public}d", errCode);
61     if (errCode == OHOS::NativeRdb::E_SQLITE_CORRUPT) {
62         auto ret = OHOS::NativeRdb::RdbHelper::DeleteRdbStore(config);
63         if (ret != OHOS::NativeRdb::E_OK) {
64             TIME_HILOGE(TIME_MODULE_SERVICE, "delete corrupt database failed, ret: %{public}d", ret);
65             return;
66         }
67         store_ = OHOS::NativeRdb::RdbHelper::GetRdbStore(config, DATABASE_OPEN_VERSION_2, timeDBOpenCallback, errCode);
68     }
69 }
70 
GetInstance()71 TimeDatabase &TimeDatabase::GetInstance()
72 {
73     static TimeDatabase timeDatabase;
74     return timeDatabase;
75 }
76 
RecoverDataBase()77 bool TimeDatabase::RecoverDataBase()
78 {
79     OHOS::NativeRdb::RdbStoreConfig config(DB_NAME);
80     config.SetSecurityLevel(NativeRdb::SecurityLevel::S1);
81     config.SetEncryptStatus(false);
82     config.SetReadConSize(1);
83     auto ret = OHOS::NativeRdb::RdbHelper::DeleteRdbStore(config);
84     if (ret != OHOS::NativeRdb::E_OK) {
85         TIME_HILOGE(TIME_MODULE_SERVICE, "delete corrupt database failed, ret: %{public}d", ret);
86         return false;
87     }
88     TimeDBOpenCallback timeDbOpenCallback;
89     int errCode;
90     store_ = OHOS::NativeRdb::RdbHelper::GetRdbStore(config, DATABASE_OPEN_VERSION_2, timeDbOpenCallback, errCode);
91     return true;
92 }
93 
GetInt(std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet,int line)94 int GetInt(std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet, int line)
95 {
96     int value = 0;
97     resultSet->GetInt(line, value);
98     return value;
99 }
100 
GetLong(std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet,int line)101 int64_t GetLong(std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet, int line)
102 {
103     int64_t value = 0;
104     resultSet->GetLong(line, value);
105     return value;
106 }
107 
GetString(std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet,int line)108 std::string GetString(std::shared_ptr<OHOS::NativeRdb::ResultSet> resultSet, int line)
109 {
110     std::string value = "";
111     resultSet->GetString(line, value);
112     return value;
113 }
114 
Insert(const std::string & table,const OHOS::NativeRdb::ValuesBucket & insertValues)115 bool TimeDatabase::Insert(const std::string &table, const OHOS::NativeRdb::ValuesBucket &insertValues)
116 {
117     if (store_ == nullptr) {
118         TIME_HILOGE(TIME_MODULE_SERVICE, "store_ is nullptr");
119         return false;
120     }
121 
122     int64_t outRowId = 0;
123     int ret = store_->Insert(outRowId, table, insertValues);
124     if (ret != OHOS::NativeRdb::E_OK) {
125         TIME_HILOGE(TIME_MODULE_SERVICE, "insert values failed, ret: %{public}d", ret);
126         if (ret != OHOS::NativeRdb::E_SQLITE_CORRUPT) {
127             return false;
128         }
129         if (!RecoverDataBase()) {
130             return false;
131         }
132         ret = store_->Insert(outRowId, table, insertValues);
133         if (ret != OHOS::NativeRdb::E_OK) {
134             TIME_HILOGE(TIME_MODULE_SERVICE, "Insert values after RecoverDataBase failed, ret: %{public}d", ret);
135         }
136     }
137     return true;
138 }
139 
Update(const OHOS::NativeRdb::ValuesBucket values,const OHOS::NativeRdb::AbsRdbPredicates & predicates)140 bool TimeDatabase::Update(
141     const OHOS::NativeRdb::ValuesBucket values, const OHOS::NativeRdb::AbsRdbPredicates &predicates)
142 {
143     if (store_ == nullptr) {
144         TIME_HILOGE(TIME_MODULE_SERVICE, "store_ is nullptr");
145         return false;
146     }
147 
148     int changedRows = 0;
149     int ret = store_->Update(changedRows, values, predicates);
150     if (ret != OHOS::NativeRdb::E_OK) {
151         TIME_HILOGE(TIME_MODULE_SERVICE, "update values failed, ret: %{public}d", ret);
152         if (ret != OHOS::NativeRdb::E_SQLITE_CORRUPT) {
153             return false;
154         }
155         if (!RecoverDataBase()) {
156             return false;
157         }
158         ret = store_->Update(changedRows, values, predicates);
159         if (ret != OHOS::NativeRdb::E_OK) {
160             TIME_HILOGE(TIME_MODULE_SERVICE, "Update values after RecoverDataBase failed, ret: %{public}d", ret);
161         }
162     }
163     return true;
164 }
165 
Query(const OHOS::NativeRdb::AbsRdbPredicates & predicates,const std::vector<std::string> & columns)166 std::shared_ptr<OHOS::NativeRdb::ResultSet> TimeDatabase::Query(
167     const OHOS::NativeRdb::AbsRdbPredicates &predicates, const std::vector<std::string> &columns)
168 {
169     if (store_ == nullptr) {
170         TIME_HILOGE(TIME_MODULE_SERVICE, "store_ is nullptr");
171         return nullptr;
172     }
173     auto result = store_->Query(predicates, columns);
174     int count;
175     if (result->GetRowCount(count) == OHOS::NativeRdb::E_SQLITE_CORRUPT) {
176         RecoverDataBase();
177         return nullptr;
178     }
179     return result;
180 }
181 
Delete(const OHOS::NativeRdb::AbsRdbPredicates & predicates)182 bool TimeDatabase::Delete(const OHOS::NativeRdb::AbsRdbPredicates &predicates)
183 {
184     if (store_ == nullptr) {
185         TIME_HILOGE(TIME_MODULE_SERVICE, "store_ is nullptr");
186         return false;
187     }
188 
189     int deletedRows = 0;
190     int ret = store_->Delete(deletedRows, predicates);
191     if (ret != OHOS::NativeRdb::E_OK) {
192         TIME_HILOGE(TIME_MODULE_SERVICE, "delete values failed, ret: %{public}d", ret);
193         if (ret != OHOS::NativeRdb::E_SQLITE_CORRUPT) {
194             return false;
195         }
196         if (!RecoverDataBase()) {
197             return false;
198         }
199         ret = store_->Delete(deletedRows, predicates);
200         if (ret != OHOS::NativeRdb::E_OK) {
201             TIME_HILOGE(TIME_MODULE_SERVICE, "Delete values after RecoverDataBase failed, ret: %{public}d", ret);
202         }
203     }
204     return true;
205 }
206 
ClearDropOnReboot()207 void TimeDatabase::ClearDropOnReboot()
208 {
209     TIME_HILOGI(TIME_MODULE_SERVICE, "Clears drop_on_reboot table");
210     if (store_ == nullptr) {
211         TIME_HILOGE(TIME_MODULE_SERVICE, "store_ is nullptr");
212         return;
213     }
214     int ret = store_->ExecuteSql("DELETE FROM drop_on_reboot");
215     if (ret != OHOS::NativeRdb::E_OK) {
216         TIME_HILOGE(TIME_MODULE_SERVICE, "Clears drop_on_reboot table failed");
217         if (ret != OHOS::NativeRdb::E_SQLITE_CORRUPT) {
218             return;
219         }
220         if (!RecoverDataBase()) {
221             return;
222         }
223         ret = store_->ExecuteSql("DELETE FROM drop_on_reboot");
224         if (ret != OHOS::NativeRdb::E_OK) {
225             TIME_HILOGE(TIME_MODULE_SERVICE, "Clears after RecoverDataBase failed, ret: %{public}d", ret);
226         }
227     }
228 }
229 
TimeDBCreateTables(OHOS::NativeRdb::RdbStore & store)230 int TimeDBCreateTables(OHOS::NativeRdb::RdbStore &store)
231 {
232     TIME_HILOGI(TIME_MODULE_SERVICE, "Creates hold_on_reboot table");
233     // Creates hold_on_reboot table.
234     int ret = store.ExecuteSql(CREATE_TIME_TIMER_HOLD_ON_REBOOT);
235     if (ret != OHOS::NativeRdb::E_OK) {
236         TIME_HILOGE(TIME_MODULE_SERVICE, "Creates hold_on_reboot table failed, ret: %{public}d", ret);
237         return ret;
238     }
239 
240     TIME_HILOGI(TIME_MODULE_SERVICE, "Creates drop_on_reboot table");
241     // Creates drop_on_reboot table.
242     ret = store.ExecuteSql(CREATE_TIME_TIMER_DROP_ON_REBOOT);
243     if (ret != OHOS::NativeRdb::E_OK) {
244         TIME_HILOGE(TIME_MODULE_SERVICE, "Creates drop_on_reboot table failed, ret: %{public}d", ret);
245         return ret;
246     }
247     return ret;
248 }
249 
OnCreate(OHOS::NativeRdb::RdbStore & store)250 int TimeDBOpenCallback::OnCreate(OHOS::NativeRdb::RdbStore &store)
251 {
252     TIME_HILOGI(TIME_MODULE_SERVICE, "OnCreate");
253     auto initRet = TimeDBCreateTables(store);
254     if (initRet != OHOS::NativeRdb::E_OK) {
255         TIME_HILOGE(TIME_MODULE_SERVICE, "Init database failed: %{public}d", initRet);
256         return initRet;
257     }
258     return OHOS::NativeRdb::E_OK;
259 }
260 
OnOpen(OHOS::NativeRdb::RdbStore & store)261 int TimeDBOpenCallback::OnOpen(OHOS::NativeRdb::RdbStore &store)
262 {
263     return OHOS::NativeRdb::E_OK;
264 }
265 
OnUpgrade(OHOS::NativeRdb::RdbStore & store,int oldVersion,int newVersion)266 int TimeDBOpenCallback::OnUpgrade(OHOS::NativeRdb::RdbStore &store, int oldVersion, int newVersion)
267 {
268     if (oldVersion == DATABASE_OPEN_VERSION && newVersion == DATABASE_OPEN_VERSION_2) {
269         int ret = store.ExecuteSql(HOLD_ON_REBOOT_ADD_COLUMN);
270         if (ret != OHOS::NativeRdb::E_OK) {
271             TIME_HILOGE(TIME_MODULE_SERVICE, "hold_on_reboot add column failed, ret: %{public}d", ret);
272             return ret;
273         }
274         ret = store.ExecuteSql(DROP_ON_REBOOT_ADD_COLUMN);
275         if (ret != OHOS::NativeRdb::E_OK) {
276             TIME_HILOGE(TIME_MODULE_SERVICE, "drop_on_reboot add column failed, ret: %{public}d", ret);
277             return ret;
278         }
279     }
280     return OHOS::NativeRdb::E_OK;
281 }
282 
OnDowngrade(OHOS::NativeRdb::RdbStore & store,int oldVersion,int newVersion)283 int TimeDBOpenCallback::OnDowngrade(OHOS::NativeRdb::RdbStore &store, int oldVersion, int newVersion)
284 {
285     return OHOS::NativeRdb::E_OK;
286 }
287 }
288 }