1 /*
2  * Copyright (c) 2021-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 
16 #include "device_profile_storage.h"
17 
18 #include <cinttypes>
19 #include <thread>
20 #include <unistd.h>
21 
22 #include "device_profile_errors.h"
23 #include "device_profile_log.h"
24 #include "device_profile_storage_manager.h"
25 #include "device_profile_utils.h"
26 #include "dp_device_manager.h"
27 #include "service_characteristic_profile.h"
28 #include "trust_group_manager.h"
29 
30 #include "datetime_ex.h"
31 #include "profile_change_handler.h"
32 
33 namespace OHOS {
34 namespace DeviceProfile {
35 using namespace OHOS::DistributedKv;
36 using namespace std::chrono_literals;
37 
38 namespace {
39 const std::string TAG = "DeviceProfileStorage";
40 const std::string PKG_NAME = "ohos.deviceprofile";
41 constexpr int32_t RETRY_TIMES_GET_KVSTORE = 1;
42 }
43 
DeviceProfileStorage(const std::string & appId,const std::string & storeId)44 DeviceProfileStorage::DeviceProfileStorage(const std::string& appId, const std::string& storeId)
45 {
46     appId_.appId = appId,
47     storeId_.storeId = storeId;
48 }
49 
SetOptions(const Options & options)50 void DeviceProfileStorage::SetOptions(const Options& options)
51 {
52     options_ = options;
53 }
54 
RegisterKvStoreInitCallback(const KvStoreInitCallback & callback)55 bool DeviceProfileStorage::RegisterKvStoreInitCallback(const KvStoreInitCallback& callback)
56 {
57     if (kvStoreInitCallback_ != nullptr) {
58         HILOGE("callback is not null");
59         return false;
60     }
61     kvStoreInitCallback_ = callback;
62     return true;
63 }
64 
Init()65 void DeviceProfileStorage::Init()
66 {
67     int64_t begin = GetTickCount();
68     std::unique_lock<std::shared_mutex> writeLock(storageLock_);
69     bool result = TryGetKvStore();
70     writeLock.unlock();
71     int64_t end = GetTickCount();
72     HILOGI("TryGetKvStore %{public}s, spend %{public}" PRId64 " ms",
73         result ? "succeeded" : "failed", end - begin);
74     // must call callback before set init status
75     if (result && kvStoreInitCallback_ != nullptr) {
76         kvStoreInitCallback_();
77     }
78     if (result) {
79         initStatus_ = StorageInitStatus::INIT_SUCCEED;
80     }
81 }
82 
SubscribeKvStore(const std::shared_ptr<KvStoreObserver> & observer)83 int32_t DeviceProfileStorage::SubscribeKvStore(const std::shared_ptr<KvStoreObserver>& observer)
84 {
85     HILOGD("called");
86     if (kvStorePtr_ == nullptr || observer == nullptr) {
87         return ERR_DP_INVALID_PARAMS;
88     }
89     Status status = kvStorePtr_->SubscribeKvStore(SubscribeType::SUBSCRIBE_TYPE_REMOTE, observer);
90     HILOGI("status %{public}d", status);
91     return static_cast<int32_t>(status);
92 }
93 
UnSubscribeKvStore(const std::shared_ptr<KvStoreObserver> & observer)94 int32_t DeviceProfileStorage::UnSubscribeKvStore(const std::shared_ptr<KvStoreObserver>& observer)
95 {
96     HILOGD("called");
97     if (kvStorePtr_ == nullptr || observer == nullptr) {
98         return ERR_DP_INVALID_PARAMS;
99     }
100     Status status = kvStorePtr_->UnSubscribeKvStore(SubscribeType::SUBSCRIBE_TYPE_REMOTE, observer);
101     HILOGI("status %{public}d", status);
102     return static_cast<int32_t>(status);
103 }
104 
RegisterSyncCallback(const std::shared_ptr<KvStoreSyncCallback> & sycnCb)105 int32_t DeviceProfileStorage::RegisterSyncCallback(const std::shared_ptr<KvStoreSyncCallback>& sycnCb)
106 {
107     HILOGD("called");
108     if (kvStorePtr_ == nullptr || sycnCb == nullptr) {
109         return ERR_DP_INVALID_PARAMS;
110     }
111     Status status = kvStorePtr_->RegisterSyncCallback(sycnCb);
112     HILOGI("status %{public}d", status);
113     return static_cast<int32_t>(status);
114 }
115 
UnRegisterSyncCallback()116 int32_t DeviceProfileStorage::UnRegisterSyncCallback()
117 {
118     HILOGD("called");
119     if (kvStorePtr_ == nullptr) {
120         return ERR_DP_INVALID_PARAMS;
121     }
122     Status status = kvStorePtr_->UnRegisterSyncCallback();
123     HILOGI("status %{public}d", status);
124     return static_cast<int32_t>(status);
125 }
126 
GetInitStatus()127 StorageInitStatus DeviceProfileStorage::GetInitStatus()
128 {
129     HILOGI("GetInitStatus %{public}d", static_cast<int32_t>(initStatus_.load()));
130     return initStatus_;
131 }
132 
TryGetKvStore()133 bool DeviceProfileStorage::TryGetKvStore()
134 {
135     int32_t retryTimes = 0;
136     while (retryTimes < RETRY_TIMES_GET_KVSTORE) {
137         if (GetKvStore() == Status::SUCCESS && kvStorePtr_ != nullptr) {
138             return true;
139         }
140         HILOGD("retry get kvstore...");
141         retryTimes++;
142     }
143     if (kvStorePtr_ == nullptr) {
144         initStatus_ = StorageInitStatus::INIT_FAILED;
145         return false;
146     }
147     return true;
148 }
149 
GetKvStore()150 Status DeviceProfileStorage::GetKvStore()
151 {
152     HILOGD("called");
153     Status status = dataManager_.GetSingleKvStore(options_, appId_, storeId_, kvStorePtr_);
154     if (status != Status::SUCCESS) {
155         HILOGI("get failed, error = %{public}d", status);
156     } else {
157         HILOGI("get succeeded");
158     }
159     return status;
160 }
161 
DeleteKvStore()162 void DeviceProfileStorage::DeleteKvStore()
163 {
164     Status status = dataManager_.DeleteKvStore(appId_, storeId_, options_.baseDir);
165     if (status != Status::SUCCESS) {
166         HILOGE("delete failed, error = %{public}d", status);
167     }
168 }
169 
GetDeviceProfile(const std::string & key,std::string & value)170 int32_t DeviceProfileStorage::GetDeviceProfile(const std::string& key, std::string& value)
171 {
172     std::shared_lock<std::shared_mutex> readLock(storageLock_);
173     if (kvStorePtr_ == nullptr) {
174         HILOGE("null kvstore");
175         return ERR_DP_INVALID_PARAMS;
176     }
177 
178     Key k(key);
179     Value v;
180     Status status = kvStorePtr_->Get(k, v);
181     if (status != Status::SUCCESS) {
182         HILOGE("get failed, %{public}d", status);
183         return static_cast<int32_t>(status);
184     }
185     value = v.ToString();
186     HILOGI("get succeeded");
187     return static_cast<int32_t>(status);
188 }
189 
PutDeviceProfile(const std::string & key,const std::string & value)190 int32_t DeviceProfileStorage::PutDeviceProfile(const std::string& key, const std::string& value)
191 {
192     std::unique_lock<std::shared_mutex> writeLock(storageLock_);
193     if (kvStorePtr_ == nullptr) {
194         HILOGE("null kvstore");
195         return ERR_DP_INVALID_PARAMS;
196     }
197 
198     Key kvKey(key);
199     Value oldV;
200     if (kvStorePtr_->Get(kvKey, oldV) == Status::SUCCESS && oldV.ToString() == value) {
201         HILOGD("The key-value pair already exists. key=%{public}s,value=%{public}s",
202             DeviceProfileUtils::AnonymizeDeviceId(key).c_str(), DeviceProfileUtils::AnonymizeDeviceId(value).c_str());
203         return ERR_OK;
204     }
205 
206     Value kvValue(value);
207     Status status  = kvStorePtr_->Put(kvKey, kvValue);
208     if (status != Status::SUCCESS) {
209         HILOGE("put failed, error = %{public}d", status);
210     }
211     return static_cast<int32_t>(status);
212 }
213 
PutDeviceProfileBatch(const std::vector<std::string> & keys,const std::vector<std::string> & values)214 int32_t DeviceProfileStorage::PutDeviceProfileBatch(const std::vector<std::string>& keys,
215     const std::vector<std::string>& values)
216 {
217     std::unique_lock<std::shared_mutex> writeLock(storageLock_);
218     if (kvStorePtr_ == nullptr) {
219         HILOGE("null kvstore");
220         return ERR_DP_INVALID_PARAMS;
221     }
222 
223     const size_t keySize = keys.size();
224     const size_t valSize = values.size();
225     HILOGI("keySize = %{public}zu, valSize = %{public}zu", keySize, valSize);
226     if (keySize != valSize) {
227         HILOGE("diff key-value size");
228         return ERR_DP_INVALID_PARAMS;
229     }
230 
231     std::vector<Entry> entries;
232     Value oldV;
233     Key kvKey;
234     for (uint32_t i = 0; i < keySize; i++) {
235         kvKey = keys[i];
236         if (kvStorePtr_->Get(kvKey, oldV) == Status::SUCCESS && oldV.ToString() == values[i]) {
237             HILOGD("The key-value pair already exists. key=%{public}s,value=%{public}s",
238                 DeviceProfileUtils::AnonymizeDeviceId(keys[i]).c_str(),
239                 DeviceProfileUtils::AnonymizeDeviceId(values[i]).c_str());
240             continue;
241         }
242 
243         Entry entry;
244         entry.key = kvKey;
245         entry.value = values[i];
246         entries.emplace_back(entry);
247     }
248     if (entries.empty()) {
249         HILOGD("All key-value pair already exists.");
250         return ERR_OK;
251     }
252 
253     Status status = kvStorePtr_->PutBatch(entries);
254     if (status != Status::SUCCESS) {
255         HILOGE("put batch failed, error = %{public}d", status);
256     }
257     return static_cast<int32_t>(status);
258 }
259 
DeleteDeviceProfile(const std::string & key)260 int32_t DeviceProfileStorage::DeleteDeviceProfile(const std::string& key)
261 {
262     std::unique_lock<std::shared_mutex> writeLock(storageLock_);
263     if (kvStorePtr_ == nullptr) {
264         return ERR_DP_INVALID_PARAMS;
265     }
266     Key k(key);
267     Status status = kvStorePtr_->Delete(k);
268     if (status != Status::SUCCESS) {
269         HILOGE("delete failed, error = %{public}d", status);
270     }
271     return static_cast<int32_t>(status);
272 }
273 
SyncDeviceProfile(const std::vector<std::string> & deviceIdList,SyncMode syncMode)274 int32_t DeviceProfileStorage::SyncDeviceProfile(const std::vector<std::string>& deviceIdList,
275     SyncMode syncMode)
276 {
277     HILOGI("called");
278     std::vector<std::string> trustDeviceList = CheckTrustDeviceList(deviceIdList);
279     if (trustDeviceList.empty()) {
280         HILOGE("trust device list is empty");
281         return ERR_DP_UNTRUSTED_GROUP;
282     }
283 
284     std::unique_lock<std::shared_mutex> writeLock(storageLock_);
285     if (kvStorePtr_ == nullptr) {
286         return ERR_DP_INVALID_PARAMS;
287     }
288 
289     Status status = kvStorePtr_->Sync(trustDeviceList, static_cast<DistributedKv::SyncMode>(syncMode));
290     if (status != Status::SUCCESS) {
291         HILOGE("sync failed, error = %{public}d", status);
292     }
293     return static_cast<int32_t>(status);
294 }
295 
RemoveDeviceData(const std::string networkId)296 int32_t DeviceProfileStorage::RemoveDeviceData(const std::string networkId)
297 {
298     HILOGI("called");
299 
300     std::unique_lock<std::shared_mutex> writeLock(storageLock_);
301     if (kvStorePtr_ == nullptr) {
302         HILOGE("null kvstore");
303         return ERR_DP_INVALID_PARAMS;
304     }
305 
306     Status status = kvStorePtr_->RemoveDeviceData(networkId);
307     if (status != Status::SUCCESS) {
308         HILOGE("remote device data failed, error = %{public}d", status);
309     }
310     return static_cast<int32_t>(status);
311 }
312 
CheckTrustGroup(const std::vector<std::string> & deviceIdList)313 bool DeviceProfileStorage::CheckTrustGroup(const std::vector<std::string>& deviceIdList)
314 {
315     if (deviceIdList.empty()) {
316         HILOGE("device list is empty");
317         return false;
318     }
319     for (const auto& deviceId : deviceIdList) {
320         std::string udid;
321         if (!DpDeviceManager::GetInstance().TransformDeviceId(deviceId, udid, DeviceIdType::UDID)) {
322             HILOGE("%{public}s transform to udid failed", DeviceProfileUtils::AnonymizeDeviceId(deviceId).c_str());
323             return false;
324         }
325 
326         if (!TrustGroupManager::GetInstance().CheckTrustGroup(udid)) {
327             HILOGE("%{public}s not in trust group", DeviceProfileUtils::AnonymizeDeviceId(deviceId).c_str());
328             return false;
329         }
330     }
331     return true;
332 }
333 
CheckTrustDeviceList(const std::vector<std::string> & deviceIdList)334 std::vector<std::string> DeviceProfileStorage::CheckTrustDeviceList(const std::vector<std::string> &deviceIdList)
335 {
336     std::vector<std::string> trustDevices;
337     if (deviceIdList.empty()) {
338         HILOGE("device list is empty");
339         return trustDevices;
340     }
341     std::vector<std::string> onlineDevices = GetOnlineDevices();
342     for (const auto& deviceId : deviceIdList) {
343         auto iter = find(onlineDevices.begin(), onlineDevices.end(), deviceId);
344         if (iter != onlineDevices.end()) {
345             HILOGI("%{public}s add to trust devices", DeviceProfileUtils::AnonymizeDeviceId(deviceId).c_str());
346             trustDevices.push_back(deviceId);
347         }
348     }
349     return trustDevices;
350 }
351 
GetOnlineDevices()352 std::vector<std::string> DeviceProfileStorage::GetOnlineDevices()
353 {
354     std::vector<std::string> targetDevices;
355     std::vector<DistributedHardware::DmDeviceInfo> allOnlineDeviceInfos;
356     int32_t result =
357         DistributedHardware::DeviceManager::GetInstance().GetTrustedDeviceList(PKG_NAME, "", allOnlineDeviceInfos);
358     if (result != Status::SUCCESS || allOnlineDeviceInfos.empty()) {
359         HILOGE("GetTrustedDeviceList Failed!");
360         return {};
361     }
362     for (const auto& dmDeviceInfo : allOnlineDeviceInfos) {
363         targetDevices.push_back(dmDeviceInfo.networkId);
364     }
365     HILOGI("online device size is %{public}zu", targetDevices.size());
366     return targetDevices;
367 }
368 
GetDeviceProfile(const std::string & udid,const std::string & key,std::string & value)369 int32_t DeviceProfileStorage::GetDeviceProfile(const std::string& udid, const std::string& key, std::string& value)
370 {
371     HILOGI("call");
372     if (udid.empty() || key.empty()) {
373         HILOGE("udid or key invalid");
374         return ERR_DP_INVALID_PARAMS;
375     }
376     Key k(key);
377     Value v;
378     Status status;
379     {
380         std::shared_lock<std::shared_mutex> readLock(storageLock_);
381         if (kvStorePtr_ == nullptr) {
382             HILOGE("null kvstore");
383             return ERR_DP_INVALID_PARAMS;
384         }
385         status = kvStorePtr_->Get(k, v);
386         HILOGI("Get data status: %{public}d", status);
387     }
388     if (status == Status::NOT_FOUND) {
389         std::vector<std::string> device;
390         device.push_back(udid);
391         SyncMode syncMode{ SyncMode::PUSH_PULL };
392         int32_t res = SyncDeviceProfile(device, syncMode);
393         HILOGI("SyncDeviceProfile res: %{public}d!", res);
394         return static_cast<int32_t>(status);
395     }
396     if (status != Status::SUCCESS) {
397         HILOGE("get failed, %{public}d", status);
398         return static_cast<int32_t>(status);
399     }
400     value = v.ToString();
401     HILOGI("get succeeded");
402     return static_cast<int32_t>(status);
403 }
404 } // namespace DeviceProfile
405 } // namespace OHOS
406