• 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 #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