1 /*
2 * Copyright (c) 2025 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 "insight_intent_rdb_data_mgr.h"
16 #include "hilog_tag_wrapper.h"
17 #include "scope_guard.h"
18 #include "utils/hmsf_utils.h"
19
20 namespace OHOS {
21 namespace AbilityRuntime {
22 namespace {
23 const std::string INTENT_KEY = "INTENT_KEY";
24 const std::string INTENT_VALUE = "INTENT_VALUE";
25 const int32_t INTENT_KEY_INDEX = 0;
26 const int32_t INTENT_VALUE_INDEX = 1;
27 constexpr int8_t CLOSE_TIME = 20; // delay 20s stop rdbStore
28 constexpr int32_t RETRY_TIMES = 3;
29 constexpr int32_t RETRY_INTERVAL = 500; // 500ms
30 constexpr int16_t WRITE_TIMEOUT = 300; // 300s
31 } // namespace
32
InsightIntentRdbDataMgr()33 InsightIntentRdbDataMgr::InsightIntentRdbDataMgr()
34 {}
35
~InsightIntentRdbDataMgr()36 InsightIntentRdbDataMgr::~InsightIntentRdbDataMgr()
37 {}
38
GetRdbStore()39 std::shared_ptr<NativeRdb::RdbStore> InsightIntentRdbDataMgr::GetRdbStore()
40 {
41 NativeRdb::RdbStoreConfig rdbStoreConfig(intentRdbConfig_.dbPath + intentRdbConfig_.dbName);
42 rdbStoreConfig.SetSecurityLevel(NativeRdb::SecurityLevel::S1);
43 rdbStoreConfig.SetWriteTime(WRITE_TIMEOUT);
44 rdbStoreConfig.SetAllowRebuild(true);
45 // for check db exist or not
46 bool isNeedRebuildDb = false;
47 std::string rdbFilePath = intentRdbConfig_.dbPath + std::string("/") + std::string(INTENT_BACK_UP_RDB_NAME);
48 if (access(rdbStoreConfig.GetPath().c_str(), F_OK) != 0) {
49 TAG_LOGW(AAFwkTag::INTENT, "intent db :%{public}s is not exist, need to create. errno:%{public}d",
50 rdbStoreConfig.GetPath().c_str(), errno);
51 if (access(rdbFilePath.c_str(), F_OK) == 0) {
52 isNeedRebuildDb = true;
53 }
54 }
55 int32_t errCode = NativeRdb::E_OK;
56 IntentRdbOpenCallback IntentRdbOpenCallback(intentRdbConfig_);
57 rdbStore_ = NativeRdb::RdbHelper::GetRdbStore(
58 rdbStoreConfig,
59 intentRdbConfig_.version,
60 IntentRdbOpenCallback,
61 errCode);
62 if (rdbStore_ == nullptr) {
63 TAG_LOGE(AAFwkTag::INTENT, "GetRdbStore failed, errCode:%{public}d", errCode);
64 return rdbStore_;
65 }
66 NativeRdb::RebuiltType rebuildType = NativeRdb::RebuiltType::NONE;
67 int32_t rebuildCode = rdbStore_->GetRebuilt(rebuildType);
68 if (errCode == NativeRdb::E_SQLITE_CORRUPT || rebuildType == NativeRdb::RebuiltType::REBUILT || isNeedRebuildDb) {
69 TAG_LOGI(AAFwkTag::INTENT, "start %{public}s restore ret %{public}d, type:%{public}d",
70 intentRdbConfig_.dbName.c_str(), rebuildCode, static_cast<int32_t>(rebuildType));
71 int32_t restoreRet = rdbStore_->Restore(rdbFilePath);
72 if (restoreRet != NativeRdb::E_OK) {
73 TAG_LOGE(AAFwkTag::INTENT, "rdb restore failed ret:%{public}d", restoreRet);
74 }
75 }
76
77 if (rdbStore_ != nullptr) {
78 DelayCloseRdbStore();
79 }
80 return rdbStore_;
81 }
82
IsIntentRdbLoaded()83 bool InsightIntentRdbDataMgr::IsIntentRdbLoaded()
84 {
85 auto rdbStore = GetRdbStore();
86 if (rdbStore == nullptr) {
87 TAG_LOGE(AAFwkTag::INTENT, "RdbStore is null");
88 return false;
89 }
90 std::string createTableSql = "CREATE TABLE IF NOT EXISTS " + intentRdbConfig_.tableName
91 + " (INTENT_KEY TEXT NOT NULL PRIMARY KEY, INTENT_VALUE TEXT NOT NULL);";
92 int32_t ret = NativeRdb::E_OK;
93 ret = rdbStore->ExecuteSql(createTableSql);
94 if (ret != NativeRdb::E_OK) {
95 TAG_LOGE(AAFwkTag::INTENT, "Create rdb table failed, ret:%{public}d", ret);
96 return false;
97 }
98 HmfsUtils::AddDeleteDfx(intentRdbConfig_.dbPath);
99 return true;
100 }
101
DelayCloseRdbStore()102 void InsightIntentRdbDataMgr::DelayCloseRdbStore()
103 {
104 std::weak_ptr<InsightIntentRdbDataMgr> weakPtr = shared_from_this();
105 auto task = [weakPtr]() {
106 std::this_thread::sleep_for(std::chrono::seconds(CLOSE_TIME));
107 auto sharedPtr = weakPtr.lock();
108 if (sharedPtr == nullptr) {
109 return;
110 }
111 std::lock_guard<std::mutex> lock(sharedPtr->rdbStoreMutex_);
112 sharedPtr->rdbStore_ = nullptr;
113 };
114 std::thread closeRdbStoreThread(task);
115 closeRdbStoreThread.detach();
116 }
117
InsertData(const std::string & key,const std::string & value)118 bool InsightIntentRdbDataMgr::InsertData(const std::string &key, const std::string &value)
119 {
120 std::lock_guard<std::mutex> lock(rdbStoreMutex_);
121 TAG_LOGD(AAFwkTag::INTENT, "InsertData start");
122 if (!IsIntentRdbLoaded()) {
123 TAG_LOGE(AAFwkTag::INTENT, "null IntentRdbStore");
124 return false;
125 }
126
127 int64_t rowId = -1;
128 NativeRdb::ValuesBucket valuesBucket;
129 valuesBucket.PutString(INTENT_KEY, key);
130 valuesBucket.PutString(INTENT_VALUE, value);
131 auto ret = InsertWithRetry(rdbStore_, rowId, valuesBucket);
132 if (ret != NativeRdb::E_OK) {
133 TAG_LOGE(AAFwkTag::INTENT, "Insert data error ret:%{public}d", ret);
134 return false;
135 }
136 BackupRdb();
137 return true;
138 }
139
UpdateData(const std::string & key,const std::string & value)140 bool InsightIntentRdbDataMgr::UpdateData(const std::string &key, const std::string &value)
141 {
142 TAG_LOGD(AAFwkTag::INTENT, "UpdateData start");
143 std::lock_guard<std::mutex> lock(rdbStoreMutex_);
144 if (!IsIntentRdbLoaded()) {
145 TAG_LOGE(AAFwkTag::INTENT, "null IntentRdbStore");
146 return false;
147 }
148
149 int32_t rowId = -1;
150 NativeRdb::AbsRdbPredicates absRdbPredicates(intentRdbConfig_.tableName);
151 absRdbPredicates.EqualTo(INTENT_KEY, key);
152 NativeRdb::ValuesBucket valuesBucket;
153 valuesBucket.PutString(INTENT_KEY, key);
154 valuesBucket.PutString(INTENT_VALUE, value);
155 auto ret = rdbStore_->Update(rowId, valuesBucket, absRdbPredicates);
156 if (ret == NativeRdb::E_SQLITE_CORRUPT) {
157 std::string rdbFilePath = intentRdbConfig_.dbPath + std::string("/") + std::string(INTENT_BACK_UP_RDB_NAME);
158 int32_t restoreRet = rdbStore_->Restore(rdbFilePath);
159 if (restoreRet != NativeRdb::E_OK) {
160 TAG_LOGE(AAFwkTag::INTENT, "rdb restore failed ret:%{public}d", restoreRet);
161 return false;
162 }
163 ret = rdbStore_->Update(rowId, valuesBucket, absRdbPredicates);
164 }
165 if (ret != NativeRdb::E_OK) {
166 TAG_LOGE(AAFwkTag::INTENT, "Update data error ret:%{public}d", ret);
167 return false;
168 }
169 BackupRdb();
170 return true;
171 }
172
DeleteDataBeginWithKey(const std::string & key)173 bool InsightIntentRdbDataMgr::DeleteDataBeginWithKey(const std::string &key)
174 {
175 TAG_LOGD(AAFwkTag::INTENT, "DeleteDataBeginWithKey start");
176 std::lock_guard<std::mutex> lock(rdbStoreMutex_);
177 if (!IsIntentRdbLoaded()) {
178 TAG_LOGE(AAFwkTag::INTENT, "null IntentRdbStore");
179 return false;
180 }
181
182 int32_t rowId = -1;
183 NativeRdb::AbsRdbPredicates absRdbPredicates(intentRdbConfig_.tableName);
184 absRdbPredicates.BeginsWith(INTENT_KEY, key);
185 auto ret = rdbStore_->Delete(rowId, absRdbPredicates);
186 if (ret == NativeRdb::E_SQLITE_CORRUPT) {
187 std::string rdbFilePath = intentRdbConfig_.dbPath + std::string("/") + std::string(INTENT_BACK_UP_RDB_NAME);
188 int32_t restoreRet = rdbStore_->Restore(rdbFilePath);
189 if (restoreRet != NativeRdb::E_OK) {
190 TAG_LOGE(AAFwkTag::INTENT, "rdb restore failed ret:%{public}d", restoreRet);
191 return false;
192 }
193 ret = rdbStore_->Delete(rowId, absRdbPredicates);
194 }
195 if (ret != NativeRdb::E_OK) {
196 TAG_LOGE(AAFwkTag::INTENT, "Delete data error ret:%{public}d", ret);
197 return false;
198 }
199 BackupRdb();
200 return true;
201 }
202
DeleteData(const std::string & key)203 bool InsightIntentRdbDataMgr::DeleteData(const std::string &key)
204 {
205 TAG_LOGD(AAFwkTag::INTENT, "DeleteData start");
206 std::lock_guard<std::mutex> lock(rdbStoreMutex_);
207 if (!IsIntentRdbLoaded()) {
208 TAG_LOGE(AAFwkTag::INTENT, "null IntentRdbStore");
209 return false;
210 }
211
212 int32_t rowId = -1;
213 NativeRdb::AbsRdbPredicates absRdbPredicates(intentRdbConfig_.tableName);
214 absRdbPredicates.EqualTo(INTENT_KEY, key);
215 auto ret = rdbStore_->Delete(rowId, absRdbPredicates);
216 if (ret == NativeRdb::E_SQLITE_CORRUPT) {
217 std::string rdbFilePath = intentRdbConfig_.dbPath + std::string("/") + std::string(INTENT_BACK_UP_RDB_NAME);
218 int32_t restoreRet = rdbStore_->Restore(rdbFilePath);
219 if (restoreRet != NativeRdb::E_OK) {
220 TAG_LOGE(AAFwkTag::INTENT, "rdb restore failed ret:%{public}d", restoreRet);
221 return false;
222 }
223 ret = rdbStore_->Delete(rowId, absRdbPredicates);
224 }
225 if (ret != NativeRdb::E_OK) {
226 TAG_LOGE(AAFwkTag::INTENT, "Delete data error ret:%{public}d", ret);
227 return false;
228 }
229 BackupRdb();
230 return true;
231 }
232
QueryData(const std::string & key,std::string & value)233 bool InsightIntentRdbDataMgr::QueryData(const std::string &key, std::string &value)
234 {
235 TAG_LOGD(AAFwkTag::INTENT, "QueryData start");
236 std::lock_guard<std::mutex> lock(rdbStoreMutex_);
237 if (!IsIntentRdbLoaded()) {
238 TAG_LOGE(AAFwkTag::INTENT, "null IntentRdbStore");
239 return false;
240 }
241
242 NativeRdb::AbsRdbPredicates absRdbPredicates(intentRdbConfig_.tableName);
243 absRdbPredicates.EqualTo(INTENT_KEY, key);
244 auto absSharedResultSet = rdbStore_->QueryByStep(absRdbPredicates, std::vector<std::string>());
245 if (absSharedResultSet == nullptr) {
246 TAG_LOGE(AAFwkTag::INTENT, "absSharedResultSet failed");
247 return false;
248 }
249 ScopeGuard stateGuard([&] { absSharedResultSet->Close(); });
250 auto ret = absSharedResultSet->GoToFirstRow();
251 if (ret != NativeRdb::E_OK) {
252 TAG_LOGE(AAFwkTag::INTENT, "GoToFirstRow failed, ret: %{public}d", ret);
253 return false;
254 }
255
256 ret = absSharedResultSet->GetString(INTENT_VALUE_INDEX, value);
257 if (ret != NativeRdb::E_OK) {
258 TAG_LOGE(AAFwkTag::INTENT, "QueryData failed, ret: %{public}d", ret);
259 return false;
260 }
261
262 return true;
263 }
264
QueryDataBeginWithKey(const std::string & key,std::unordered_map<std::string,std::string> & datas)265 bool InsightIntentRdbDataMgr::QueryDataBeginWithKey(const std::string &key,
266 std::unordered_map<std::string, std::string> &datas)
267 {
268 TAG_LOGD(AAFwkTag::INTENT, "QueryDataBeginWithKey start");
269 std::lock_guard<std::mutex> lock(rdbStoreMutex_);
270 if (!IsIntentRdbLoaded()) {
271 TAG_LOGE(AAFwkTag::INTENT, "null IntentRdbStore");
272 return false;
273 }
274
275 NativeRdb::AbsRdbPredicates absRdbPredicates(intentRdbConfig_.tableName);
276 absRdbPredicates.BeginsWith(INTENT_KEY, key);
277 auto absSharedResultSet = rdbStore_->QueryByStep(absRdbPredicates, std::vector<std::string>());
278 if (absSharedResultSet == nullptr) {
279 TAG_LOGE(AAFwkTag::INTENT, "absSharedResultSet failed");
280 return false;
281 }
282 ScopeGuard stateGuard([&] { absSharedResultSet->Close(); });
283
284 if (absSharedResultSet->GoToFirstRow() == NativeRdb::E_OK) {
285 do {
286 std::string key;
287 if (absSharedResultSet->GetString(INTENT_KEY_INDEX, key) != NativeRdb::E_OK) {
288 TAG_LOGE(AAFwkTag::INTENT, "GetString key failed");
289 return false;
290 }
291
292 std::string value;
293 if (absSharedResultSet->GetString(INTENT_VALUE_INDEX, value) != NativeRdb::E_OK) {
294 TAG_LOGE(AAFwkTag::INTENT, "GetString value failed");
295 return false;
296 }
297
298 datas.emplace(key, value);
299 } while (absSharedResultSet->GoToNextRow() == NativeRdb::E_OK);
300 }
301 return true;
302 }
303
QueryAllData(std::unordered_map<std::string,std::string> & datas)304 bool InsightIntentRdbDataMgr::QueryAllData(std::unordered_map<std::string, std::string> &datas)
305 {
306 TAG_LOGD(AAFwkTag::INTENT, "QueryAllData start");
307 std::lock_guard<std::mutex> lock(rdbStoreMutex_);
308 if (!IsIntentRdbLoaded()) {
309 TAG_LOGE(AAFwkTag::INTENT, "null IntentRdbStore");
310 return false;
311 }
312
313 NativeRdb::AbsRdbPredicates absRdbPredicates(intentRdbConfig_.tableName);
314 auto absSharedResultSet = rdbStore_->QueryByStep(absRdbPredicates, std::vector<std::string>());
315 if (absSharedResultSet == nullptr) {
316 TAG_LOGE(AAFwkTag::INTENT, "absSharedResultSet failed");
317 return false;
318 }
319 ScopeGuard stateGuard([&] { absSharedResultSet->Close(); });
320
321 if (absSharedResultSet->GoToFirstRow() == NativeRdb::E_OK) {
322 do {
323 std::string key;
324 if (absSharedResultSet->GetString(INTENT_KEY_INDEX, key) != NativeRdb::E_OK) {
325 TAG_LOGE(AAFwkTag::INTENT, "GetString key failed");
326 return false;
327 }
328
329 std::string value;
330 if (absSharedResultSet->GetString(INTENT_VALUE_INDEX, value) != NativeRdb::E_OK) {
331 TAG_LOGE(AAFwkTag::INTENT, "GetString value failed");
332 return false;
333 }
334
335 datas.emplace(key, value);
336 } while (absSharedResultSet->GoToNextRow() == NativeRdb::E_OK);
337 }
338 return true;
339 }
340
BackupRdb()341 void InsightIntentRdbDataMgr::BackupRdb()
342 {
343 TAG_LOGI(AAFwkTag::INTENT, "%{public}s backup start", intentRdbConfig_.dbName.c_str());
344 if (!IsIntentRdbLoaded()) {
345 TAG_LOGE(AAFwkTag::INTENT, "null IntentRdbStore");
346 return;
347 }
348
349 auto ret = rdbStore_->Backup(intentRdbConfig_.dbPath + std::string("/") + std::string(INTENT_BACK_UP_RDB_NAME));
350 if (ret != NativeRdb::E_OK) {
351 TAG_LOGE(AAFwkTag::INTENT, "Backup failed, errCode:%{public}d", ret);
352 }
353 }
354
InsertWithRetry(std::shared_ptr<NativeRdb::RdbStore> rdbStore,int64_t & rowId,const NativeRdb::ValuesBucket & valuesBucket)355 int32_t InsightIntentRdbDataMgr::InsertWithRetry(std::shared_ptr<NativeRdb::RdbStore> rdbStore, int64_t &rowId,
356 const NativeRdb::ValuesBucket &valuesBucket)
357 {
358 int32_t retryCnt = 0;
359 int32_t ret = 0;
360 do {
361 ret = rdbStore->InsertWithConflictResolution(rowId, intentRdbConfig_.tableName,
362 valuesBucket, NativeRdb::ConflictResolution::ON_CONFLICT_REPLACE);
363 if (ret == NativeRdb::E_SQLITE_CORRUPT) {
364 std::string rdbFilePath = intentRdbConfig_.dbPath + std::string("/") + std::string(INTENT_BACK_UP_RDB_NAME);
365 int32_t restoreRet = rdbStore_->Restore(rdbFilePath);
366 if (restoreRet != NativeRdb::E_OK) {
367 TAG_LOGE(AAFwkTag::INTENT, "rdb restore failed ret:%{public}d", restoreRet);
368 break;
369 }
370 ret = rdbStore->InsertWithConflictResolution(rowId, intentRdbConfig_.tableName,
371 valuesBucket, NativeRdb::ConflictResolution::ON_CONFLICT_REPLACE);
372 }
373 if (ret == NativeRdb::E_OK || !IsRetryErrCode(ret)) {
374 break;
375 }
376 if (++retryCnt < RETRY_TIMES) {
377 std::this_thread::sleep_for(std::chrono::milliseconds(RETRY_INTERVAL));
378 }
379 TAG_LOGW(AAFwkTag::INTENT, "rdb insert failed, retry count: %{public}d, ret: %{public}d", retryCnt, ret);
380 } while (retryCnt < RETRY_TIMES);
381 return ret;
382 }
383
IsRetryErrCode(int32_t errCode)384 bool InsightIntentRdbDataMgr::IsRetryErrCode(int32_t errCode)
385 {
386 if (errCode == NativeRdb::E_DATABASE_BUSY ||
387 errCode == NativeRdb::E_SQLITE_BUSY ||
388 errCode == NativeRdb::E_SQLITE_LOCKED ||
389 errCode == NativeRdb::E_SQLITE_NOMEM ||
390 errCode == NativeRdb::E_SQLITE_IOERR) {
391 return true;
392 }
393 return false;
394 }
395
IntentRdbOpenCallback(const IntentRdbConfig & intentRdbConfig)396 IntentRdbOpenCallback::IntentRdbOpenCallback(const IntentRdbConfig &intentRdbConfig)\
397 : intentRdbConfig_(intentRdbConfig) {}
398
OnCreate(NativeRdb::RdbStore & rdbStore)399 int32_t IntentRdbOpenCallback::OnCreate(NativeRdb::RdbStore &rdbStore)
400 {
401 TAG_LOGD(AAFwkTag::INTENT, "OnCreate");
402 return NativeRdb::E_OK;
403 }
404
OnUpgrade(NativeRdb::RdbStore & rdbStore,int currentVersion,int targetVersion)405 int32_t IntentRdbOpenCallback::OnUpgrade(
406 NativeRdb::RdbStore &rdbStore, int currentVersion, int targetVersion)
407 {
408 TAG_LOGD(AAFwkTag::INTENT, "OnUpgrade currentVersion: %{public}d, targetVersion: %{public}d",
409 currentVersion, targetVersion);
410 return NativeRdb::E_OK;
411 }
412
OnDowngrade(NativeRdb::RdbStore & rdbStore,int currentVersion,int targetVersion)413 int32_t IntentRdbOpenCallback::OnDowngrade(
414 NativeRdb::RdbStore &rdbStore, int currentVersion, int targetVersion)
415 {
416 TAG_LOGD(AAFwkTag::INTENT, "OnDowngrade currentVersion: %{public}d, targetVersion: %{public}d",
417 currentVersion, targetVersion);
418 return NativeRdb::E_OK;
419 }
420
OnOpen(NativeRdb::RdbStore & rdbStore)421 int32_t IntentRdbOpenCallback::OnOpen(NativeRdb::RdbStore &rdbStore)
422 {
423 TAG_LOGD(AAFwkTag::INTENT, "OnOpen");
424 return NativeRdb::E_OK;
425 }
426
onCorruption(std::string databaseFile)427 int32_t IntentRdbOpenCallback::onCorruption(std::string databaseFile)
428 {
429 TAG_LOGD(AAFwkTag::INTENT, "onCorruption");
430 return NativeRdb::E_OK;
431 }
432 } // namespace AbilityRuntime
433 } // namespace OHOS