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