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