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 constexpr const char* BMS_KEY = "KEY";
27 constexpr const char* BMS_VALUE = "VALUE";
28 constexpr int8_t BMS_KEY_INDEX = 0;
29 constexpr int8_t BMS_VALUE_INDEX = 1;
30 constexpr int16_t WRITE_TIMEOUT = 300; // 300s
31 constexpr int8_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 }
35 
36 std::mutex RdbDataManager::restoreRdbMutex_;
37 
RdbDataManager(const BmsRdbConfig &bmsRdbConfig)38 RdbDataManager::RdbDataManager(const BmsRdbConfig &bmsRdbConfig)
39     : bmsRdbConfig_(bmsRdbConfig)
40 {
41 }
42 
~RdbDataManager()43 RdbDataManager::~RdbDataManager()
44 {
45     rdbStore_ = nullptr;
46 }
47 
ClearCache()48 void RdbDataManager::ClearCache()
49 {
50     NativeRdb::RdbHelper::ClearCache();
51 }
52 
GetRdbStore()53 std::shared_ptr<NativeRdb::RdbStore> RdbDataManager::GetRdbStore()
54 {
55     std::lock_guard<std::mutex> lock(rdbMutex_);
56     if (rdbStore_ != nullptr) {
57         return rdbStore_;
58     }
59     std::lock_guard<std::mutex> restoreLock(restoreRdbMutex_);
60     NativeRdb::RdbStoreConfig rdbStoreConfig(bmsRdbConfig_.dbPath + bmsRdbConfig_.dbName);
61     rdbStoreConfig.SetSecurityLevel(NativeRdb::SecurityLevel::S1);
62     rdbStoreConfig.SetWriteTime(WRITE_TIMEOUT);
63     rdbStoreConfig.SetAllowRebuild(true);
64     if (!isInitial_) {
65         rdbStoreConfig.SetIntegrityCheck(NativeRdb::IntegrityCheck::FULL);
66         isInitial_ = true;
67     }
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     NativeRdb::RebuiltType rebuildType = NativeRdb::RebuiltType::NONE;
91     int32_t rebuildCode = rdbStore_->GetRebuilt(rebuildType);
92     if (rebuildType == NativeRdb::RebuiltType::REBUILT || isNeedRebuildDb) {
93         APP_LOGI("start %{public}s restore ret %{public}d, type:%{public}d", bmsRdbConfig_.dbName.c_str(),
94             rebuildCode, static_cast<int32_t>(rebuildType));
95         int32_t restoreRet = rdbStore_->Restore(rdbFilePath);
96         if (restoreRet != NativeRdb::E_OK) {
97             APP_LOGE("rdb restore failed ret:%{public}d", restoreRet);
98         }
99     }
100 
101     if (rdbStore_ != nullptr) {
102         DelayCloseRdbStore();
103     }
104     return rdbStore_;
105 }
106 
CheckSystemSizeAndHisysEvent(const std::string &path, const std::string &fileName)107 void RdbDataManager::CheckSystemSizeAndHisysEvent(const std::string &path, const std::string &fileName)
108 {
109     bool flag = BundleUtil::CheckSystemSizeAndHisysEvent(path, fileName);
110     if (flag) {
111         APP_LOGW("space not enough %{public}s", fileName.c_str());
112         EventReport::SendDiskSpaceEvent(fileName, 0, OPERATION_TYPE_OF_INSUFFICIENT_DISK);
113     }
114 }
115 
BackupRdb()116 void RdbDataManager::BackupRdb()
117 {
118     APP_LOGI("%{public}s backup start", bmsRdbConfig_.dbName.c_str());
119     auto rdbStore = GetRdbStore();
120     if (rdbStore == nullptr) {
121         APP_LOGE("RdbStore is null");
122         return;
123     }
124     auto ret = rdbStore->Backup(bmsRdbConfig_.dbPath + std::string("/") + std::string(BMS_BACK_UP_RDB_NAME));
125     if (ret != NativeRdb::E_OK) {
126         APP_LOGE("Backup failed, errCode:%{public}d", ret);
127     }
128     APP_LOGI("%{public}s backup end", bmsRdbConfig_.dbName.c_str());
129 }
130 
InsertData(const std::string &key, const std::string &value)131 bool RdbDataManager::InsertData(const std::string &key, const std::string &value)
132 {
133     APP_LOGD("InsertData start");
134     auto rdbStore = GetRdbStore();
135     if (rdbStore == nullptr) {
136         APP_LOGE("RdbStore is null");
137         return false;
138     }
139 
140     int64_t rowId = -1;
141     NativeRdb::ValuesBucket valuesBucket;
142     valuesBucket.PutString(BMS_KEY, key);
143     valuesBucket.PutString(BMS_VALUE, value);
144     auto ret = rdbStore->InsertWithConflictResolution(
145         rowId, bmsRdbConfig_.tableName, valuesBucket, NativeRdb::ConflictResolution::ON_CONFLICT_REPLACE);
146     return ret == NativeRdb::E_OK;
147 }
148 
InsertData(const NativeRdb::ValuesBucket &valuesBucket)149 bool RdbDataManager::InsertData(const NativeRdb::ValuesBucket &valuesBucket)
150 {
151     APP_LOGD("InsertData start");
152     auto rdbStore = GetRdbStore();
153     if (rdbStore == nullptr) {
154         APP_LOGE("RdbStore is null");
155         return false;
156     }
157 
158     int64_t rowId = -1;
159     auto ret = rdbStore->InsertWithConflictResolution(
160         rowId, bmsRdbConfig_.tableName, valuesBucket, NativeRdb::ConflictResolution::ON_CONFLICT_REPLACE);
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->Query(absRdbPredicates, std::vector<std::string>());
281     if (absSharedResultSet == nullptr) {
282         APP_LOGE("absSharedResultSet failed");
283         return false;
284     }
285     ScopeGuard stateGuard([&] { absSharedResultSet->Close(); });
286     if (!absSharedResultSet->HasBlock()) {
287         APP_LOGE("absSharedResultSet has no block");
288         return false;
289     }
290     auto ret = absSharedResultSet->GoToFirstRow();
291     if (ret != NativeRdb::E_OK) {
292         APP_LOGE("GoToFirstRow failed, ret: %{public}d", ret);
293         return false;
294     }
295 
296     ret = absSharedResultSet->GetString(BMS_VALUE_INDEX, value);
297     if (ret != NativeRdb::E_OK) {
298         APP_LOGE("QueryData failed, ret: %{public}d", ret);
299         return false;
300     }
301 
302     return true;
303 }
304 
QueryData( const NativeRdb::AbsRdbPredicates &absRdbPredicates)305 std::shared_ptr<NativeRdb::AbsSharedResultSet> RdbDataManager::QueryData(
306     const NativeRdb::AbsRdbPredicates &absRdbPredicates)
307 {
308     APP_LOGD("QueryData start");
309     auto rdbStore = GetRdbStore();
310     if (rdbStore == nullptr) {
311         APP_LOGE("RdbStore is null");
312         return nullptr;
313     }
314     if (absRdbPredicates.GetTableName() != bmsRdbConfig_.tableName) {
315         APP_LOGE("RdbStore table is invalid");
316         return nullptr;
317     }
318     auto absSharedResultSet = rdbStore->Query(absRdbPredicates, std::vector<std::string>());
319     if (absSharedResultSet == nullptr || !absSharedResultSet->HasBlock()) {
320         APP_LOGE("absSharedResultSet failed");
321         return nullptr;
322     }
323     return absSharedResultSet;
324 }
325 
QueryAllData(std::map<std::string, std::string> &datas)326 bool RdbDataManager::QueryAllData(std::map<std::string, std::string> &datas)
327 {
328     APP_LOGD("QueryAllData start");
329     auto rdbStore = GetRdbStore();
330     if (rdbStore == nullptr) {
331         APP_LOGE("RdbStore is null");
332         return false;
333     }
334 
335     NativeRdb::AbsRdbPredicates absRdbPredicates(bmsRdbConfig_.tableName);
336     auto absSharedResultSet = rdbStore->Query(absRdbPredicates, std::vector<std::string>());
337     if (absSharedResultSet == nullptr) {
338         APP_LOGE("absSharedResultSet failed");
339         return false;
340     }
341     ScopeGuard stateGuard([&] { absSharedResultSet->Close(); });
342     if (!absSharedResultSet->HasBlock()) {
343         APP_LOGE("absSharedResultSet has no block");
344         return false;
345     }
346 
347     if (absSharedResultSet->GoToFirstRow() != NativeRdb::E_OK) {
348         APP_LOGE("GoToFirstRow failed");
349         return false;
350     }
351 
352     do {
353         std::string key;
354         if (absSharedResultSet->GetString(BMS_KEY_INDEX, key) != NativeRdb::E_OK) {
355             APP_LOGE("GetString key failed");
356             return false;
357         }
358 
359         std::string value;
360         if (absSharedResultSet->GetString(BMS_VALUE_INDEX, value) != NativeRdb::E_OK) {
361             APP_LOGE("GetString value failed");
362             return false;
363         }
364 
365         datas.emplace(key, value);
366     } while (absSharedResultSet->GoToNextRow() == NativeRdb::E_OK);
367     return !datas.empty();
368 }
369 
CreateTable()370 bool RdbDataManager::CreateTable()
371 {
372     std::string createTableSql;
373     if (bmsRdbConfig_.createTableSql.empty()) {
374         createTableSql = std::string(
375             "CREATE TABLE IF NOT EXISTS "
376             + bmsRdbConfig_.tableName
377             + "(KEY TEXT NOT NULL PRIMARY KEY, VALUE TEXT NOT NULL);");
378     } else {
379         createTableSql = bmsRdbConfig_.createTableSql;
380     }
381     auto rdbStore = GetRdbStore();
382     if (rdbStore == nullptr) {
383         APP_LOGE("RdbStore is null");
384         return false;
385     }
386     int ret = rdbStore->ExecuteSql(createTableSql);
387     if (ret != NativeRdb::E_OK) {
388         APP_LOGE("CreateTable failed, ret: %{public}d", ret);
389         return false;
390     }
391     for (const auto &sql : bmsRdbConfig_.insertColumnSql) {
392         int32_t insertRet = rdbStore->ExecuteSql(sql);
393         if (insertRet != NativeRdb::E_OK) {
394             APP_LOGW_NOFUNC("ExecuteSql insertColumnSql failed ret: %{public}d", insertRet);
395         }
396     }
397     return true;
398 }
399 
DelayCloseRdbStore()400 void RdbDataManager::DelayCloseRdbStore()
401 {
402     APP_LOGD("RdbDataManager DelayCloseRdbStore start");
403     std::weak_ptr<RdbDataManager> weakPtr = shared_from_this();
404     auto task = [weakPtr]() {
405         APP_LOGD("RdbDataManager DelayCloseRdbStore thread begin");
406         std::this_thread::sleep_for(std::chrono::seconds(CLOSE_TIME));
407         auto sharedPtr = weakPtr.lock();
408         if (sharedPtr == nullptr) {
409             return;
410         }
411         std::lock_guard<std::mutex> lock(sharedPtr->rdbMutex_);
412         sharedPtr->rdbStore_ = nullptr;
413         APP_LOGD("RdbDataManager DelayCloseRdbStore thread end");
414     };
415     std::thread closeRdbStoreThread(task);
416     closeRdbStoreThread.detach();
417 }
418 
QueryByStep( const NativeRdb::AbsRdbPredicates &absRdbPredicates)419 std::shared_ptr<NativeRdb::ResultSet> RdbDataManager::QueryByStep(
420     const NativeRdb::AbsRdbPredicates &absRdbPredicates)
421 {
422     APP_LOGD("QueryByStep start");
423     auto rdbStore = GetRdbStore();
424     if (rdbStore == nullptr) {
425         APP_LOGE("RdbStore is null");
426         return nullptr;
427     }
428     if (absRdbPredicates.GetTableName() != bmsRdbConfig_.tableName) {
429         APP_LOGE("RdbStore table is invalid");
430         return nullptr;
431     }
432     auto absSharedResultSet = rdbStore->QueryByStep(absRdbPredicates, std::vector<std::string>());
433     if (absSharedResultSet == nullptr) {
434         APP_LOGE("absSharedResultSet failed");
435         return nullptr;
436     }
437     return absSharedResultSet;
438 }
439 }  // namespace AppExecFwk
440 }  // namespace OHOS
441