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