1 /*
2 * Copyright (c) 2023-2024 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 "kv_adapter.h"
16
17 #include <cinttypes>
18 #include <mutex>
19
20 #include "datetime_ex.h"
21 #include "string_ex.h"
22
23 #include "distributed_device_profile_errors.h"
24 #include "distributed_device_profile_log.h"
25 #include "distributed_device_profile_constants.h"
26 #include "profile_cache.h"
27 #include "profile_utils.h"
28
29 namespace OHOS {
30 namespace DistributedDeviceProfile {
31 using namespace OHOS::DistributedKv;
32 namespace {
33 constexpr int32_t MAX_INIT_RETRY_TIMES = 30;
34 constexpr int32_t INIT_RETRY_SLEEP_INTERVAL = 200 * 1000; // 500ms
35 const std::string DATABASE_DIR = "/data/service/el1/public/database/distributed_device_profile_service";
36 const std::string TAG = "KVAdapter";
37 constexpr uint32_t MAX_BATCH_SIZE = 128;
38 }
39
KVAdapter(const std::string & appId,const std::string & storeId,const std::shared_ptr<DistributedKv::KvStoreObserver> & dataChangeListener,const std::shared_ptr<DistributedKv::KvStoreSyncCallback> & syncCompletedListener,const std::shared_ptr<DistributedKv::KvStoreDeathRecipient> & deathListener,DistributedKv::DataType dataType)40 KVAdapter::KVAdapter(const std::string &appId, const std::string &storeId,
41 const std::shared_ptr<DistributedKv::KvStoreObserver> &dataChangeListener,
42 const std::shared_ptr<DistributedKv::KvStoreSyncCallback> &syncCompletedListener,
43 const std::shared_ptr<DistributedKv::KvStoreDeathRecipient> &deathListener,
44 DistributedKv::DataType dataType)
45 {
46 this->appId_.appId = appId;
47 this->storeId_.storeId = storeId;
48 this->dataChangeListener_ = dataChangeListener;
49 this->syncCompletedListener_= syncCompletedListener;
50 this->deathRecipient_ = deathListener;
51 this->dataType_ = dataType;
52 HILOGD("KVAdapter Constructor Success, appId: %{public}s, storeId: %{public}s", appId.c_str(), storeId.c_str());
53 }
54
~KVAdapter()55 KVAdapter::~KVAdapter()
56 {
57 HILOGD("KVAdapter Destruction!");
58 }
59
Init()60 int32_t KVAdapter::Init()
61 {
62 HILOGI("Init kvAdapter, storeId: %{public}s", storeId_.storeId.c_str());
63 int32_t tryTimes = MAX_INIT_RETRY_TIMES;
64 int64_t beginTime = GetTickCount();
65 while (tryTimes > 0) {
66 DistributedKv::Status status = GetKvStorePtr(dataType_);
67 if (status == DistributedKv::Status::SUCCESS) {
68 int64_t endTime = GetTickCount();
69 HILOGI("Init KvStorePtr Success, spend %{public}" PRId64 " ms", endTime - beginTime);
70 RegisterSyncCompletedListener();
71 RegisterDataChangeListener();
72 RegisterDeathListener();
73 return DP_SUCCESS;
74 }
75 HILOGI("CheckKvStore, left times: %{public}d, status: %{public}d", tryTimes, status);
76 if (status == DistributedKv::Status::STORE_META_CHANGED) {
77 HILOGW("This db meta changed, remove and rebuild it");
78 DeleteKvStore();
79 }
80 if (status == DistributedKv::Status::SECURITY_LEVEL_ERROR) {
81 DeleteKvStore();
82 }
83 usleep(INIT_RETRY_SLEEP_INTERVAL);
84 tryTimes--;
85 }
86 return DP_KV_DB_INIT_FAIL;
87 }
88
UnInit()89 int32_t KVAdapter::UnInit()
90 {
91 HILOGI("DBAdapter UnInit");
92 UnRegisterSyncCompletedListener();
93 UnRegisterDataChangeListener();
94 UnRegisterDeathListener();
95 DeleteSyncCompletedListener();
96 DeleteDataChangeListener();
97 DeleteDeathListener();
98 DeleteKvStorePtr();
99 return DP_SUCCESS;
100 }
101
Put(const std::string & key,const std::string & value)102 int32_t KVAdapter::Put(const std::string& key, const std::string& value)
103 {
104 if (key.empty() || key.size() > MAX_STRING_LEN || value.empty() || value.size() > MAX_STRING_LEN) {
105 HILOGE("Param is invalid!");
106 return DP_INVALID_PARAMS;
107 }
108 DistributedKv::Status status;
109 {
110 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
111 if (kvStorePtr_ == nullptr) {
112 HILOGE("kvDBPtr is null!");
113 return DP_KV_DB_PTR_NULL;
114 }
115
116 DistributedKv::Key kvKey(key);
117 DistributedKv::Value oldV;
118 if (kvStorePtr_->Get(kvKey, oldV) == DistributedKv::Status::SUCCESS && oldV.ToString() == value) {
119 HILOGD("The key-value pair already exists. key=%{public}s,value=%{public}s",
120 ProfileUtils::GetDbKeyAnonyString(key).c_str(),
121 ProfileUtils::GetAnonyString(value).c_str());
122 return DP_SUCCESS;
123 }
124
125 DistributedKv::Value kvValue(value);
126 status = kvStorePtr_->Put(kvKey, kvValue);
127 }
128 if (status != DistributedKv::Status::SUCCESS) {
129 HILOGE("Put kv to db failed, ret: %{public}d", status);
130 return DP_PUT_KV_DB_FAIL;
131 }
132 return DP_SUCCESS;
133 }
134
PutBatch(const std::map<std::string,std::string> & values)135 int32_t KVAdapter::PutBatch(const std::map<std::string, std::string>& values)
136 {
137 if (values.empty() || values.size() > MAX_PROFILE_SIZE) {
138 HILOGE("Param is invalid!");
139 return DP_INVALID_PARAMS;
140 }
141 DistributedKv::Status status;
142 {
143 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
144 if (kvStorePtr_ == nullptr) {
145 HILOGE("kvDBPtr is null!");
146 return DP_KV_DB_PTR_NULL;
147 }
148 std::vector<DistributedKv::Entry> entries;
149 DistributedKv::Value oldV;
150 DistributedKv::Key kvKey;
151 for (auto item : values) {
152 kvKey = item.first;
153 if (kvStorePtr_->Get(kvKey, oldV) == DistributedKv::Status::SUCCESS && oldV.ToString() == item.second) {
154 HILOGD("The key-value pair already exists. key=%{public}s,value=%{public}s",
155 ProfileUtils::GetDbKeyAnonyString(item.first).c_str(),
156 ProfileUtils::GetAnonyString(item.second).c_str());
157 continue;
158 }
159
160 Entry entry;
161 entry.key = kvKey;
162 entry.value = item.second;
163 entries.emplace_back(entry);
164 }
165 if (entries.empty()) {
166 HILOGD("All key-value pair already exists.");
167 return DP_SUCCESS;
168 }
169 status = kvStorePtr_->PutBatch(entries);
170 }
171 if (status != DistributedKv::Status::SUCCESS) {
172 HILOGE("PutBatch kv to db failed, ret: %{public}d", status);
173 return DP_PUT_KV_DB_FAIL;
174 }
175 return DP_SUCCESS;
176 }
177
Delete(const std::string & key)178 int32_t KVAdapter::Delete(const std::string& key)
179 {
180 DistributedKv::Status status;
181 {
182 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
183 if (kvStorePtr_ == nullptr) {
184 HILOGE("kvDBPtr is null!");
185 return DP_KV_DB_PTR_NULL;
186 }
187 DistributedKv::Key kvKey(key);
188 status = kvStorePtr_->Delete(kvKey);
189 }
190 if (status != DistributedKv::Status::SUCCESS) {
191 HILOGE("Delete kv by key failed!");
192 return DP_DEL_KV_DB_FAIL;
193 }
194 HILOGD("Delete kv by key success!");
195 return DP_SUCCESS;
196 }
197
Get(const std::string & key,std::string & value)198 int32_t KVAdapter::Get(const std::string& key, std::string& value)
199 {
200 HILOGD("key: %{public}s", ProfileUtils::GetDbKeyAnonyString(key).c_str());
201 DistributedKv::Key kvKey(key);
202 DistributedKv::Value kvValue;
203 DistributedKv::Status status;
204 {
205 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
206 if (kvStorePtr_ == nullptr) {
207 HILOGE("kvStoragePtr_ is null");
208 return DP_KV_DB_PTR_NULL;
209 }
210 status = kvStorePtr_->Get(kvKey, kvValue);
211 }
212 if (status != DistributedKv::Status::SUCCESS) {
213 HILOGE("Get data from kv failed, key: %{public}s", ProfileUtils::GetDbKeyAnonyString(key).c_str());
214 return DP_GET_KV_DB_FAIL;
215 }
216 value = kvValue.ToString();
217 return DP_SUCCESS;
218 }
219
GetByPrefix(const std::string & keyPrefix,std::map<std::string,std::string> & values)220 int32_t KVAdapter::GetByPrefix(const std::string& keyPrefix, std::map<std::string, std::string>& values)
221 {
222 HILOGD("key prefix: %{public}s", ProfileUtils::GetDbKeyAnonyString(keyPrefix).c_str());
223 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
224 if (kvStorePtr_ == nullptr) {
225 HILOGE("kvStoragePtr_ is null");
226 return DP_KV_DB_PTR_NULL;
227 }
228 // if prefix is empty, get all entries.
229 DistributedKv::Key allEntryKeyPrefix(keyPrefix);
230 std::vector<DistributedKv::Entry> allEntries;
231 DistributedKv::Status status = kvStorePtr_->GetEntries(allEntryKeyPrefix, allEntries);
232 if (status != DistributedKv::Status::SUCCESS) {
233 HILOGE("Query data by keyPrefix failed, prefix: %{public}s",
234 ProfileUtils::GetDbKeyAnonyString(keyPrefix).c_str());
235 return DP_GET_KV_DB_FAIL;
236 }
237 if (allEntries.size() == 0 || allEntries.size() > MAX_DB_SIZE) {
238 HILOGE("AllEntries size is invalid!size: %{public}zu!", allEntries.size());
239 return DP_INVALID_PARAMS;
240 }
241 for (const auto& item : allEntries) {
242 values[item.key.ToString()] = item.value.ToString();
243 }
244 return DP_SUCCESS;
245 }
246
DeleteByPrefix(const std::string & keyPrefix)247 int32_t KVAdapter::DeleteByPrefix(const std::string& keyPrefix)
248 {
249 HILOGI("delete by key prefix: %{public}s", ProfileUtils::GetDbKeyAnonyString(keyPrefix).c_str());
250 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
251 if (kvStorePtr_ == nullptr) {
252 HILOGE("kvStoragePtr_ is null");
253 return DP_KV_DB_PTR_NULL;
254 }
255 // if prefix is empty, get all entries.
256 DistributedKv::Key allEntryKeyPrefix(keyPrefix);
257 std::vector<DistributedKv::Entry> allEntries;
258 DistributedKv::Status status = kvStorePtr_->GetEntries(allEntryKeyPrefix, allEntries);
259 if (status != DistributedKv::Status::SUCCESS) {
260 return DP_DEL_KV_DB_FAIL;
261 }
262 std::vector<DistributedKv::Key> keys;
263 for (auto item : allEntries) {
264 keys.push_back(item.key);
265 }
266 status = kvStorePtr_->DeleteBatch(keys);
267 if (status != DistributedKv::Status::SUCCESS) {
268 return DP_DEL_KV_DB_FAIL;
269 }
270 return DP_SUCCESS;
271 }
272
GetKvStorePtr(DistributedKv::DataType dataType)273 DistributedKv::Status KVAdapter::GetKvStorePtr(DistributedKv::DataType dataType)
274 {
275 HILOGI("called");
276 DistributedKv::Options options = {
277 .createIfMissing = true,
278 .encrypt = false,
279 .isPublic = true,
280 .securityLevel = DistributedKv::SecurityLevel::S1,
281 .area = 1,
282 .kvStoreType = KvStoreType::SINGLE_VERSION,
283 .baseDir = DATABASE_DIR,
284 .dataType = dataType,
285 .cloudConfig = {
286 .enableCloud = true,
287 .autoSync = true,
288 }
289 };
290 DistributedKv::Status status;
291 {
292 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
293 status = kvDataMgr_.GetSingleKvStore(options, appId_, storeId_, kvStorePtr_);
294 if (status == DistributedKv::Status::SUCCESS && kvStorePtr_ == nullptr) {
295 status = DistributedKv::Status::ERROR;
296 }
297 }
298 return status;
299 }
300
DeleteKvStorePtr()301 int32_t KVAdapter::DeleteKvStorePtr()
302 {
303 HILOGI("Delete KvStore Ptr!");
304 {
305 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
306 kvStorePtr_ = nullptr;
307 }
308 return DP_SUCCESS;
309 }
310
Sync(const std::vector<std::string> & deviceList,SyncMode syncMode)311 int32_t KVAdapter::Sync(const std::vector<std::string>& deviceList, SyncMode syncMode)
312 {
313 HILOGD("Sync!");
314 {
315 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
316 if (kvStorePtr_ == nullptr) {
317 HILOGE("kvStorePtr is nullptr!");
318 return DP_KV_DB_PTR_NULL;
319 }
320 if (deviceList.empty() || deviceList.size() > MAX_DEVICE_SIZE) {
321 HILOGE("deviceList is invalid!");
322 return DP_INVALID_PARAMS;
323 }
324 if (syncMode <= SyncMode::MIN || syncMode >= SyncMode::MAX) {
325 HILOGE("syncMode is invalid!");
326 return DP_INVALID_PARAMS;
327 }
328 DistributedKv::Status status = kvStorePtr_->Sync(deviceList, static_cast<DistributedKv::SyncMode>(syncMode));
329 if (status != DistributedKv::Status::SUCCESS) {
330 HILOGE("Sync fail!");
331 return DP_KV_SYNC_FAIL;
332 }
333 }
334 return DP_SUCCESS;
335 }
336
GetDeviceEntries(const std::string & udid,std::map<std::string,std::string> & values)337 int32_t KVAdapter::GetDeviceEntries(const std::string& udid, std::map<std::string, std::string>& values)
338 {
339 if (udid.empty()) {
340 HILOGE("udid is invalid!");
341 return DP_INVALID_PARAMS;
342 }
343 std::vector<DistributedKv::Entry> entries;
344 {
345 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
346 if (kvStorePtr_ == nullptr) {
347 HILOGE("kvStorePtr is nullptr!");
348 return DP_KV_DB_PTR_NULL;
349 }
350 DistributedKv::Status status = kvStorePtr_->GetDeviceEntries(udid, entries);
351 if (status != DistributedKv::Status::SUCCESS) {
352 HILOGE("GetDeviceEntries fail! udid=%{public}s", ProfileUtils::GetAnonyString(udid).c_str());
353 return DP_GET_KV_DB_FAIL;
354 }
355 }
356 for (const auto& item : entries) {
357 auto key = item.key.ToString();
358 if (key.empty()) {
359 continue;
360 }
361 values[key] = item.value.ToString();
362 }
363 return DP_SUCCESS;
364 }
365
DeleteBatch(const std::vector<std::string> & keys)366 int32_t KVAdapter::DeleteBatch(const std::vector<std::string>& keys)
367 {
368 if (keys.empty() || keys.size() > MAX_PROFILE_SIZE) {
369 HILOGE("keys size(%{public}zu) is invalid!", keys.size());
370 return DP_INVALID_PARAMS;
371 }
372
373 uint32_t keysSize = static_cast<uint32_t>(keys.size());
374 std::vector<std::vector<DistributedKv::Key>> delKeyBatches;
375 for (uint32_t i = 0; i < keysSize; i += MAX_BATCH_SIZE) {
376 uint32_t end = (i + MAX_BATCH_SIZE) > keysSize ? keysSize : (i + MAX_BATCH_SIZE);
377 auto batch = std::vector<std::string>(keys.begin() + i, keys.begin() + end);
378 std::vector<DistributedKv::Key> delKeys;
379 for (auto item : batch) {
380 DistributedKv::Key key(item);
381 delKeys.emplace_back(key);
382 }
383 delKeyBatches.emplace_back(delKeys);
384 }
385
386 {
387 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
388 if (kvStorePtr_ == nullptr) {
389 HILOGE("kvStorePtr is nullptr!");
390 return DP_KV_DB_PTR_NULL;
391 }
392 for (auto delKeys : delKeyBatches) {
393 DistributedKv::Status status = kvStorePtr_->DeleteBatch(delKeys);
394 if (status != DistributedKv::Status::SUCCESS) {
395 HILOGE("DeleteBatch failed!");
396 return DP_DEL_KV_DB_FAIL;
397 }
398 }
399 }
400 return DP_SUCCESS;
401 }
402
RegisterDataChangeListener()403 int32_t KVAdapter::RegisterDataChangeListener()
404 {
405 HILOGI("Register db data change listener");
406 {
407 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
408 if (kvStorePtr_ == nullptr) {
409 HILOGE("kvStoragePtr_ is null");
410 return DP_INVALID_PARAMS;
411 }
412 DistributedKv::Status status =
413 kvStorePtr_->SubscribeKvStore(DistributedKv::SubscribeType::SUBSCRIBE_TYPE_ALL, dataChangeListener_);
414 if (status != DistributedKv::Status::SUCCESS) {
415 HILOGE("Register db data change listener failed, ret: %{public}d", status);
416 return DP_REGISTER_KV_DATA_LISTENER_FAILED;
417 }
418 }
419 return DP_SUCCESS;
420 }
421
UnRegisterDataChangeListener()422 int32_t KVAdapter::UnRegisterDataChangeListener()
423 {
424 HILOGI("UnRegister db data change listener");
425 {
426 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
427 if (kvStorePtr_ == nullptr) {
428 HILOGE("kvStoragePtr_ is null");
429 return DP_KV_DB_PTR_NULL;
430 }
431 DistributedKv::Status status =
432 kvStorePtr_->UnSubscribeKvStore(DistributedKv::SubscribeType::SUBSCRIBE_TYPE_ALL, dataChangeListener_);
433 if (status != DistributedKv::Status::SUCCESS) {
434 HILOGE("UnRegister db data change listener failed, ret: %{public}d", status);
435 return DP_UNREGISTER_KV_DATA_LISTENER_FAILED;
436 }
437 }
438 return DP_SUCCESS;
439 }
440
DeleteDataChangeListener()441 int32_t KVAdapter::DeleteDataChangeListener()
442 {
443 HILOGI("Delete DataChangeListener!");
444 {
445 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
446 dataChangeListener_ = nullptr;
447 }
448 return DP_SUCCESS;
449 }
450
RegisterSyncCompletedListener()451 int32_t KVAdapter::RegisterSyncCompletedListener()
452 {
453 HILOGI("Register syncCompleted listener");
454 {
455 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
456 if (kvStorePtr_ == nullptr) {
457 HILOGE("kvStoragePtr_ is null");
458 return DP_KV_DB_PTR_NULL;
459 }
460 DistributedKv::Status status = kvStorePtr_->RegisterSyncCallback(syncCompletedListener_);
461 if (status != DistributedKv::Status::SUCCESS) {
462 HILOGE("Register syncCompleted listener failed, ret: %{public}d", status);
463 return DP_REGISTER_KV_SYNC_LISTENER_FAILED;
464 }
465 }
466 return DP_SUCCESS;
467 }
468
UnRegisterSyncCompletedListener()469 int32_t KVAdapter::UnRegisterSyncCompletedListener()
470 {
471 HILOGI("UnRegister syncCompleted listener");
472 {
473 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
474 if (kvStorePtr_ == nullptr) {
475 HILOGE("kvStoragePtr_ is null");
476 return DP_KV_DB_PTR_NULL;
477 }
478 DistributedKv::Status status = kvStorePtr_->UnRegisterSyncCallback();
479 if (status != DistributedKv::Status::SUCCESS) {
480 HILOGE("UnRegister db data change listener failed, ret: %{public}d", status);
481 return DP_UNREGISTER_KV_SYNC_LISTENER_FAILED;
482 }
483 }
484 return DP_SUCCESS;
485 }
486
DeleteSyncCompletedListener()487 int32_t KVAdapter::DeleteSyncCompletedListener()
488 {
489 HILOGI("Delete SyncCompletedListener!");
490 {
491 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
492 syncCompletedListener_ = nullptr;
493 }
494 return DP_SUCCESS;
495 }
496
RegisterDeathListener()497 int32_t KVAdapter::RegisterDeathListener()
498 {
499 HILOGI("Register syncCompleted listener");
500 {
501 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
502 kvDataMgr_.RegisterKvStoreServiceDeathRecipient(deathRecipient_);
503 }
504 return DP_SUCCESS;
505 }
506
UnRegisterDeathListener()507 int32_t KVAdapter::UnRegisterDeathListener()
508 {
509 HILOGI("UnRegister death listener");
510 {
511 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
512 kvDataMgr_.UnRegisterKvStoreServiceDeathRecipient(deathRecipient_);
513 }
514 return DP_SUCCESS;
515 }
516
DeleteDeathListener()517 int32_t KVAdapter::DeleteDeathListener()
518 {
519 HILOGI("Delete DeathListener!");
520 {
521 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
522 deathRecipient_ = nullptr;
523 }
524 return DP_SUCCESS;
525 }
526
DeleteKvStore()527 int32_t KVAdapter::DeleteKvStore()
528 {
529 HILOGI("Delete KvStore!");
530 {
531 std::lock_guard<std::mutex> lock(kvAdapterMutex_);
532 kvDataMgr_.CloseKvStore(appId_, storeId_);
533 kvDataMgr_.DeleteKvStore(appId_, storeId_, DATABASE_DIR);
534 }
535 return DP_SUCCESS;
536 }
537 } // namespace DeviceProfile
538 } // namespace OHOS
539