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 
16 #include "rdb_data_manager.h"
17 
18 #include "app_log_wrapper.h"
19 #include "bundle_util.h"
20 #include "event_report.h"
21 #include "scope_guard.h"
22 
23 namespace OHOS {
24 namespace AppExecFwk {
25 namespace {
26 const std::string BMS_KEY = "KEY";
27 const std::string BMS_VALUE = "VALUE";
28 const int32_t BMS_KEY_INDEX = 0;
29 const int32_t BMS_VALUE_INDEX = 1;
30 const int32_t WRITE_TIMEOUT = 300; // 300s
31 const int32_t CLOSE_TIME = 20; // delay 20s stop rdbStore
32 constexpr const char* BMS_BACK_UP_RDB_NAME = "bms-backup.db";
33 constexpr int32_t OPERATION_TYPE_OF_INSUFFICIENT_DISK = 3;
34 constexpr int32_t RETRY_TIMES = 3;
35 constexpr int32_t RETRY_INTERVAL = 500; // 500ms
36 }
37 
38 std::mutex RdbDataManager::restoreRdbMutex_;
39 
RdbDataManager(const BmsRdbConfig & bmsRdbConfig)40 RdbDataManager::RdbDataManager(const BmsRdbConfig &bmsRdbConfig)
41     : bmsRdbConfig_(bmsRdbConfig)
42 {
43 }
44 
~RdbDataManager()45 RdbDataManager::~RdbDataManager()
46 {
47     rdbStore_ = nullptr;
48 }
49 
ClearCache()50 void RdbDataManager::ClearCache()
51 {
52     NativeRdb::RdbHelper::ClearCache();
53 }
54 
GetRdbStore()55 std::shared_ptr<NativeRdb::RdbStore> RdbDataManager::GetRdbStore()
56 {
57     std::lock_guard<std::mutex> lock(rdbMutex_);
58     if (rdbStore_ != nullptr) {
59         return rdbStore_;
60     }
61     std::lock_guard<std::mutex> restoreLock(restoreRdbMutex_);
62     NativeRdb::RdbStoreConfig rdbStoreConfig(bmsRdbConfig_.dbPath + bmsRdbConfig_.dbName);
63     rdbStoreConfig.SetSecurityLevel(NativeRdb::SecurityLevel::S1);
64     rdbStoreConfig.SetWriteTime(WRITE_TIMEOUT);
65     rdbStoreConfig.SetAllowRebuild(true);
66     if (!isInitial_) {
67         rdbStoreConfig.SetIntegrityCheck(NativeRdb::IntegrityCheck::FULL);
68         isInitial_ = true;
69     }
70     // for check db exist or not
71     bool isNeedRebuildDb = false;
72     std::string rdbFilePath = bmsRdbConfig_.dbPath + std::string("/") + std::string(BMS_BACK_UP_RDB_NAME);
73     if (access(rdbStoreConfig.GetPath().c_str(), F_OK) != 0) {
74         APP_LOGW("bms db :%{public}s is not exist, need to create. errno:%{public}d",
75             rdbStoreConfig.GetPath().c_str(), errno);
76         if (access(rdbFilePath.c_str(), F_OK) == 0) {
77             isNeedRebuildDb = true;
78         }
79     }
80     int32_t errCode = NativeRdb::E_OK;
81     BmsRdbOpenCallback bmsRdbOpenCallback(bmsRdbConfig_);
82     rdbStore_ = NativeRdb::RdbHelper::GetRdbStore(
83         rdbStoreConfig,
84         bmsRdbConfig_.version,
85         bmsRdbOpenCallback,
86         errCode);
87     if (rdbStore_ == nullptr) {
88         APP_LOGE("GetRdbStore failed, errCode:%{public}d", errCode);
89         return nullptr;
90     }
91     CheckSystemSizeAndHisysEvent(bmsRdbConfig_.dbPath, bmsRdbConfig_.dbName);
92     NativeRdb::RebuiltType rebuildType = NativeRdb::RebuiltType::NONE;
93     int32_t rebuildCode = rdbStore_->GetRebuilt(rebuildType);
94     if (rebuildType == NativeRdb::RebuiltType::REBUILT || isNeedRebuildDb) {
95         APP_LOGI("start %{public}s restore ret %{public}d, type:%{public}d", bmsRdbConfig_.dbName.c_str(),
96             rebuildCode, static_cast<int32_t>(rebuildType));
97         int32_t restoreRet = rdbStore_->Restore(rdbFilePath);
98         if (restoreRet != NativeRdb::E_OK) {
99             APP_LOGE("rdb restore failed ret:%{public}d", restoreRet);
100         }
101     }
102 
103     if (rdbStore_ != nullptr) {
104         DelayCloseRdbStore();
105     }
106     return rdbStore_;
107 }
108 
CheckSystemSizeAndHisysEvent(const std::string & path,const std::string & fileName)109 void RdbDataManager::CheckSystemSizeAndHisysEvent(const std::string &path, const std::string &fileName)
110 {
111     bool flag = BundleUtil::CheckSystemSizeAndHisysEvent(path, fileName);
112     if (flag) {
113         APP_LOGW("space not enough %{public}s", fileName.c_str());
114         EventReport::SendDiskSpaceEvent(fileName, 0, OPERATION_TYPE_OF_INSUFFICIENT_DISK);
115     }
116 }
117 
BackupRdb()118 void RdbDataManager::BackupRdb()
119 {
120     APP_LOGI("%{public}s backup start", bmsRdbConfig_.dbName.c_str());
121     auto rdbStore = GetRdbStore();
122     if (rdbStore == nullptr) {
123         APP_LOGE("RdbStore is null");
124         return;
125     }
126     auto ret = rdbStore->Backup(bmsRdbConfig_.dbPath + std::string("/") + std::string(BMS_BACK_UP_RDB_NAME));
127     if (ret != NativeRdb::E_OK) {
128         APP_LOGE("Backup failed, errCode:%{public}d", ret);
129     }
130     APP_LOGI("%{public}s backup end", bmsRdbConfig_.dbName.c_str());
131 }
132 
InsertData(const std::string & key,const std::string & value)133 bool RdbDataManager::InsertData(const std::string &key, const std::string &value)
134 {
135     APP_LOGD("InsertData start");
136     auto rdbStore = GetRdbStore();
137     if (rdbStore == nullptr) {
138         APP_LOGE("RdbStore is null");
139         return false;
140     }
141 
142     int64_t rowId = -1;
143     NativeRdb::ValuesBucket valuesBucket;
144     valuesBucket.PutString(BMS_KEY, key);
145     valuesBucket.PutString(BMS_VALUE, value);
146     auto ret = InsertWithRetry(rdbStore, rowId, valuesBucket);
147     return ret == NativeRdb::E_OK;
148 }
149 
InsertData(const NativeRdb::ValuesBucket & valuesBucket)150 bool RdbDataManager::InsertData(const NativeRdb::ValuesBucket &valuesBucket)
151 {
152     APP_LOGD("InsertData start");
153     auto rdbStore = GetRdbStore();
154     if (rdbStore == nullptr) {
155         APP_LOGE("RdbStore is null");
156         return false;
157     }
158 
159     int64_t rowId = -1;
160     auto ret = InsertWithRetry(rdbStore, rowId, valuesBucket);
161     return ret == NativeRdb::E_OK;
162 }
163 
BatchInsert(int64_t & outInsertNum,const std::vector<NativeRdb::ValuesBucket> & valuesBuckets)164 bool RdbDataManager::BatchInsert(int64_t &outInsertNum, const std::vector<NativeRdb::ValuesBucket> &valuesBuckets)
165 {
166     APP_LOGD("BatchInsert start");
167     auto rdbStore = GetRdbStore();
168     if (rdbStore == nullptr) {
169         APP_LOGE("RdbStore is null");
170         return false;
171     }
172     auto ret = rdbStore->BatchInsert(outInsertNum, bmsRdbConfig_.tableName, valuesBuckets);
173     return ret == NativeRdb::E_OK;
174 }
175 
UpdateData(const std::string & key,const std::string & value)176 bool RdbDataManager::UpdateData(const std::string &key, const std::string &value)
177 {
178     APP_LOGD("UpdateData start");
179     auto rdbStore = GetRdbStore();
180     if (rdbStore == nullptr) {
181         APP_LOGE("RdbStore is null");
182         return false;
183     }
184 
185     int32_t rowId = -1;
186     NativeRdb::AbsRdbPredicates absRdbPredicates(bmsRdbConfig_.tableName);
187     absRdbPredicates.EqualTo(BMS_KEY, key);
188     NativeRdb::ValuesBucket valuesBucket;
189     valuesBucket.PutString(BMS_KEY, key);
190     valuesBucket.PutString(BMS_VALUE, value);
191     auto ret = rdbStore->Update(rowId, valuesBucket, absRdbPredicates);
192     return ret == NativeRdb::E_OK;
193 }
194 
UpdateData(const NativeRdb::ValuesBucket & valuesBucket,const NativeRdb::AbsRdbPredicates & absRdbPredicates)195 bool RdbDataManager::UpdateData(
196     const NativeRdb::ValuesBucket &valuesBucket, const NativeRdb::AbsRdbPredicates &absRdbPredicates)
197 {
198     APP_LOGD("UpdateData start");
199     auto rdbStore = GetRdbStore();
200     if (rdbStore == nullptr) {
201         APP_LOGE("RdbStore is null");
202         return false;
203     }
204     if (absRdbPredicates.GetTableName() != bmsRdbConfig_.tableName) {
205         APP_LOGE("RdbStore table is invalid");
206         return false;
207     }
208     int32_t rowId = -1;
209     auto ret = rdbStore->Update(rowId, valuesBucket, absRdbPredicates);
210     return ret == NativeRdb::E_OK;
211 }
212 
UpdateOrInsertData(const NativeRdb::ValuesBucket & valuesBucket,const NativeRdb::AbsRdbPredicates & absRdbPredicates)213 bool RdbDataManager::UpdateOrInsertData(
214     const NativeRdb::ValuesBucket &valuesBucket, const NativeRdb::AbsRdbPredicates &absRdbPredicates)
215 {
216     APP_LOGD("UpdateOrInsertData start");
217     auto rdbStore = GetRdbStore();
218     if (rdbStore == nullptr) {
219         APP_LOGE("RdbStore is null");
220         return false;
221     }
222     if (absRdbPredicates.GetTableName() != bmsRdbConfig_.tableName) {
223         APP_LOGE("RdbStore table is invalid");
224         return false;
225     }
226     int32_t rowId = -1;
227     auto ret = rdbStore->Update(rowId, valuesBucket, absRdbPredicates);
228     if ((ret == NativeRdb::E_OK) && (rowId == 0)) {
229         APP_LOGI_NOFUNC("data not exist, need insert data");
230         int64_t rowIdInsert = -1;
231         ret = rdbStore->InsertWithConflictResolution(
232             rowIdInsert, bmsRdbConfig_.tableName, valuesBucket, NativeRdb::ConflictResolution::ON_CONFLICT_REPLACE);
233     }
234     return ret == NativeRdb::E_OK;
235 }
236 
DeleteData(const std::string & key)237 bool RdbDataManager::DeleteData(const std::string &key)
238 {
239     APP_LOGD("DeleteData start");
240     auto rdbStore = GetRdbStore();
241     if (rdbStore == nullptr) {
242         APP_LOGE("RdbStore is null");
243         return false;
244     }
245 
246     int32_t rowId = -1;
247     NativeRdb::AbsRdbPredicates absRdbPredicates(bmsRdbConfig_.tableName);
248     absRdbPredicates.EqualTo(BMS_KEY, key);
249     auto ret = rdbStore->Delete(rowId, absRdbPredicates);
250     return ret == NativeRdb::E_OK;
251 }
252 
DeleteData(const NativeRdb::AbsRdbPredicates & absRdbPredicates)253 bool RdbDataManager::DeleteData(const NativeRdb::AbsRdbPredicates &absRdbPredicates)
254 {
255     auto rdbStore = GetRdbStore();
256     if (rdbStore == nullptr) {
257         APP_LOGE("RdbStore is null");
258         return false;
259     }
260     if (absRdbPredicates.GetTableName() != bmsRdbConfig_.tableName) {
261         APP_LOGE("RdbStore table is invalid");
262         return false;
263     }
264     int32_t rowId = -1;
265     auto ret = rdbStore->Delete(rowId, absRdbPredicates);
266     return ret == NativeRdb::E_OK;
267 }
268 
QueryData(const std::string & key,std::string & value)269 bool RdbDataManager::QueryData(const std::string &key, std::string &value)
270 {
271     APP_LOGD("QueryData start");
272     auto rdbStore = GetRdbStore();
273     if (rdbStore == nullptr) {
274         APP_LOGE("RdbStore is null");
275         return false;
276     }
277 
278     NativeRdb::AbsRdbPredicates absRdbPredicates(bmsRdbConfig_.tableName);
279     absRdbPredicates.EqualTo(BMS_KEY, key);
280     auto absSharedResultSet = rdbStore->QueryByStep(absRdbPredicates, std::vector<std::string>());
281     if (absSharedResultSet == nullptr) {
282         APP_LOGE("absSharedResultSet failed");
283         return false;
284     }
285     ScopeGuard stateGuard([&] { absSharedResultSet->Close(); });
286     auto ret = absSharedResultSet->GoToFirstRow();
287     if (ret != NativeRdb::E_OK) {
288         APP_LOGE("GoToFirstRow failed, ret: %{public}d", ret);
289         return false;
290     }
291 
292     ret = absSharedResultSet->GetString(BMS_VALUE_INDEX, value);
293     if (ret != NativeRdb::E_OK) {
294         APP_LOGE("QueryData failed, ret: %{public}d", ret);
295         return false;
296     }
297 
298     return true;
299 }
300 
QueryData(const NativeRdb::AbsRdbPredicates & absRdbPredicates)301 std::shared_ptr<NativeRdb::ResultSet> RdbDataManager::QueryData(
302     const NativeRdb::AbsRdbPredicates &absRdbPredicates)
303 {
304     APP_LOGD("QueryData start");
305     auto rdbStore = GetRdbStore();
306     if (rdbStore == nullptr) {
307         APP_LOGE("RdbStore is null");
308         return nullptr;
309     }
310     if (absRdbPredicates.GetTableName() != bmsRdbConfig_.tableName) {
311         APP_LOGE("RdbStore table is invalid");
312         return nullptr;
313     }
314     auto absSharedResultSet = rdbStore->QueryByStep(absRdbPredicates, std::vector<std::string>());
315     if (absSharedResultSet == nullptr) {
316         APP_LOGE("absSharedResultSet failed");
317         return nullptr;
318     }
319     return absSharedResultSet;
320 }
321 
QueryAllData(std::map<std::string,std::string> & datas)322 bool RdbDataManager::QueryAllData(std::map<std::string, std::string> &datas)
323 {
324     APP_LOGD("QueryAllData start");
325     auto rdbStore = GetRdbStore();
326     if (rdbStore == nullptr) {
327         APP_LOGE("RdbStore is null");
328         return false;
329     }
330 
331     NativeRdb::AbsRdbPredicates absRdbPredicates(bmsRdbConfig_.tableName);
332     auto absSharedResultSet = rdbStore->QueryByStep(absRdbPredicates, std::vector<std::string>());
333     if (absSharedResultSet == nullptr) {
334         APP_LOGE("absSharedResultSet failed");
335         return false;
336     }
337     ScopeGuard stateGuard([&] { absSharedResultSet->Close(); });
338 
339     if (absSharedResultSet->GoToFirstRow() != NativeRdb::E_OK) {
340         APP_LOGE("GoToFirstRow failed");
341         return false;
342     }
343 
344     do {
345         std::string key;
346         if (absSharedResultSet->GetString(BMS_KEY_INDEX, key) != NativeRdb::E_OK) {
347             APP_LOGE("GetString key failed");
348             return false;
349         }
350 
351         std::string value;
352         if (absSharedResultSet->GetString(BMS_VALUE_INDEX, value) != NativeRdb::E_OK) {
353             APP_LOGE("GetString value failed");
354             return false;
355         }
356 
357         datas.emplace(key, value);
358     } while (absSharedResultSet->GoToNextRow() == NativeRdb::E_OK);
359     return !datas.empty();
360 }
361 
CreateTable()362 bool RdbDataManager::CreateTable()
363 {
364     std::string createTableSql;
365     if (bmsRdbConfig_.createTableSql.empty()) {
366         createTableSql = std::string(
367             "CREATE TABLE IF NOT EXISTS "
368             + bmsRdbConfig_.tableName
369             + "(KEY TEXT NOT NULL PRIMARY KEY, VALUE TEXT NOT NULL);");
370     } else {
371         createTableSql = bmsRdbConfig_.createTableSql;
372     }
373     auto rdbStore = GetRdbStore();
374     if (rdbStore == nullptr) {
375         APP_LOGE("RdbStore is null");
376         return false;
377     }
378     int ret = rdbStore->ExecuteSql(createTableSql);
379     if (ret != NativeRdb::E_OK) {
380         APP_LOGE("CreateTable failed, ret: %{public}d", ret);
381         return false;
382     }
383     for (const auto &sql : bmsRdbConfig_.insertColumnSql) {
384         int32_t insertRet = rdbStore->ExecuteSql(sql);
385         if (insertRet != NativeRdb::E_OK) {
386             APP_LOGW_NOFUNC("ExecuteSql insertColumnSql failed ret: %{public}d", insertRet);
387         }
388     }
389     return true;
390 }
391 
DelayCloseRdbStore()392 void RdbDataManager::DelayCloseRdbStore()
393 {
394     APP_LOGD("RdbDataManager DelayCloseRdbStore start");
395     std::weak_ptr<RdbDataManager> weakPtr = shared_from_this();
396     auto task = [weakPtr]() {
397         APP_LOGD("RdbDataManager DelayCloseRdbStore thread begin");
398         std::this_thread::sleep_for(std::chrono::seconds(CLOSE_TIME));
399         auto sharedPtr = weakPtr.lock();
400         if (sharedPtr == nullptr) {
401             return;
402         }
403         std::lock_guard<std::mutex> lock(sharedPtr->rdbMutex_);
404         sharedPtr->rdbStore_ = nullptr;
405         APP_LOGD("RdbDataManager DelayCloseRdbStore thread end");
406     };
407     std::thread closeRdbStoreThread(task);
408     closeRdbStoreThread.detach();
409 }
410 
QueryByStep(const NativeRdb::AbsRdbPredicates & absRdbPredicates)411 std::shared_ptr<NativeRdb::ResultSet> RdbDataManager::QueryByStep(
412     const NativeRdb::AbsRdbPredicates &absRdbPredicates)
413 {
414     APP_LOGD("QueryByStep start");
415     auto rdbStore = GetRdbStore();
416     if (rdbStore == nullptr) {
417         APP_LOGE("RdbStore is null");
418         return nullptr;
419     }
420     if (absRdbPredicates.GetTableName() != bmsRdbConfig_.tableName) {
421         APP_LOGE("RdbStore table is invalid");
422         return nullptr;
423     }
424     auto absSharedResultSet = rdbStore->QueryByStep(absRdbPredicates, std::vector<std::string>());
425     if (absSharedResultSet == nullptr) {
426         APP_LOGE("absSharedResultSet failed");
427         return nullptr;
428     }
429     return absSharedResultSet;
430 }
431 
InsertWithRetry(std::shared_ptr<NativeRdb::RdbStore> rdbStore,int64_t & rowId,const NativeRdb::ValuesBucket & valuesBucket)432 int32_t RdbDataManager::InsertWithRetry(std::shared_ptr<NativeRdb::RdbStore> rdbStore, int64_t &rowId,
433     const NativeRdb::ValuesBucket &valuesBucket)
434 {
435     int32_t retryCnt = 0;
436     int32_t ret = 0;
437     do {
438         ret = rdbStore->InsertWithConflictResolution(rowId, bmsRdbConfig_.tableName,
439             valuesBucket, NativeRdb::ConflictResolution::ON_CONFLICT_REPLACE);
440         if (ret == NativeRdb::E_OK || !IsRetryErrCode(ret)) {
441             break;
442         }
443         if (++retryCnt < RETRY_TIMES) {
444             std::this_thread::sleep_for(std::chrono::milliseconds(RETRY_INTERVAL));
445         }
446         APP_LOGW("rdb insert failed, retry count: %{public}d, ret: %{public}d", retryCnt, ret);
447     } while (retryCnt < RETRY_TIMES);
448     return ret;
449 }
450 
IsRetryErrCode(int32_t errCode)451 bool RdbDataManager::IsRetryErrCode(int32_t errCode)
452 {
453     if (errCode == NativeRdb::E_DATABASE_BUSY ||
454         errCode == NativeRdb::E_SQLITE_BUSY ||
455         errCode == NativeRdb::E_SQLITE_LOCKED ||
456         errCode == NativeRdb::E_SQLITE_NOMEM ||
457         errCode == NativeRdb::E_SQLITE_IOERR) {
458         return true;
459     }
460     return false;
461 }
462 }  // namespace AppExecFwk
463 }  // namespace OHOS
464