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