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