1 /*
2 * Copyright (c) 2021 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_manager.h"
17
18 #include <chrono>
19 #include <thread>
20
21 #include "device_manager.h"
22 #include "device_profile_errors.h"
23 #include "device_profile_log.h"
24 #include "device_profile_utils.h"
25 #include "sync_coordinator.h"
26
27 #include "ipc_object_proxy.h"
28 #include "ipc_skeleton.h"
29 #include "iservice_registry.h"
30 #include "subscribe_info.h"
31 #include "subscribe_manager.h"
32 #include "system_ability_definition.h"
33
34 namespace OHOS {
35 namespace DeviceProfile {
36 using namespace std::chrono_literals;
37 using namespace OHOS::DistributedKv;
38
39 namespace {
40 const std::string TAG = "DeviceProfileStorageManager";
41
42 const std::string SERVICE_TYPE = "type";
43 const std::string SERVICES = "services";
44 constexpr int32_t RETRY_TIMES_WAIT_KV_DATA = 30;
45 constexpr int32_t INTREVAL_POST_ONLINE_SYNC_MS = 50;
46 constexpr int32_t RETRY_TIMES_POST_ONLINE_SYNC = 15;
47 }
48
49 IMPLEMENT_SINGLE_INSTANCE(DeviceProfileStorageManager);
50
Init()51 bool DeviceProfileStorageManager::Init()
52 {
53 if (!inited_) {
54 if (!SyncCoordinator::GetInstance().Init()) {
55 HILOGE("SyncCoordinator init failed");
56 return false;
57 }
58 DeviceManager::GetInstance().GetLocalDeviceUdid(localUdid_);
59 if (localUdid_.empty()) {
60 HILOGE("get local udid failed");
61 return false;
62 }
63 onlineSyncTbl_ = std::make_shared<OnlineSyncTable>();
64 if (onlineSyncTbl_ == nullptr) {
65 return false;
66 }
67
68 kvStoreDeathRecipient_ = sptr<IRemoteObject::DeathRecipient>(new KvStoreDeathRecipient());
69 auto runner = AppExecFwk::EventRunner::Create("dpstorage");
70 storageHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
71 if (storageHandler_ == nullptr) {
72 return false;
73 }
74 inited_ = true;
75 }
76
77 auto waitTask = [this]() {
78 if (!WaitKvDataService()) {
79 std::lock_guard<std::mutex> autoLock(serviceLock_);
80 profileItems_.clear();
81 kvDataServiceFailed_ = true;
82 return;
83 }
84 auto callback = std::bind(&DeviceProfileStorageManager::OnKvStoreInitDone, this);
85 onlineSyncTbl_->RegisterKvStoreInitCallback(callback);
86 onlineSyncTbl_->Init();
87 };
88 if (!storageHandler_->PostTask(waitTask)) {
89 HILOGE("post task failed");
90 return false;
91 }
92 HILOGI("init succeeded");
93 return true;
94 }
95
WaitKvDataService()96 bool DeviceProfileStorageManager::WaitKvDataService()
97 {
98 auto samgrProxy = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
99 if (samgrProxy == nullptr) {
100 HILOGE("get samgrProxy failed");
101 return false;
102 }
103 int32_t retryTimes = RETRY_TIMES_WAIT_KV_DATA;
104 do {
105 auto kvDataSvr = samgrProxy->CheckSystemAbility(DISTRIBUTED_KV_DATA_SERVICE_ABILITY_ID);
106 if (kvDataSvr != nullptr) {
107 IPCObjectProxy* proxy = reinterpret_cast<IPCObjectProxy*>(kvDataSvr.GetRefPtr());
108 if (proxy != nullptr && !proxy->IsObjectDead()) {
109 HILOGI("get service succeed");
110 proxy->AddDeathRecipient(kvStoreDeathRecipient_);
111 return true;
112 }
113 }
114 HILOGD("waiting for service...");
115 std::this_thread::sleep_for(1s);
116 if (--retryTimes <= 0) {
117 HILOGE("waiting service timeout(30)s");
118 return false;
119 }
120 } while (true);
121 return false;
122 }
123
GenerateKey(const std::string & udid,const std::string & key,KeyType keyType)124 std::string DeviceProfileStorageManager::GenerateKey(const std::string& udid,
125 const std::string& key, KeyType keyType)
126 {
127 std::string tmp;
128 tmp.append(udid).append("/").append(std::to_string(keyType)).append("/").append(key);
129 return tmp;
130 }
131
PutDeviceProfile(const ServiceCharacteristicProfile & profile)132 int32_t DeviceProfileStorageManager::PutDeviceProfile(const ServiceCharacteristicProfile& profile)
133 {
134 if (kvDataServiceFailed_ || onlineSyncTbl_->GetInitStatus() == StorageInitStatus::INIT_FAILED) {
135 HILOGE("kvstore init failed");
136 return ERR_DP_INIT_DB_FAILED;
137 }
138
139 std::vector<std::string> keys;
140 std::vector<std::string> values;
141 std::string serviceId = profile.GetServiceId();
142 keys.emplace_back(GenerateKey(localUdid_, serviceId, KeyType::SERVICE));
143 values.emplace_back(profile.GetCharacteristicProfileJson());
144 std::unique_lock<std::mutex> autoLock(serviceLock_);
145 if (servicesJson_[serviceId] == nullptr) {
146 nlohmann::json j;
147 j[SERVICE_TYPE] = profile.GetServiceType();
148 servicesJson_[serviceId] = j;
149 keys.emplace_back(GenerateKey(localUdid_, SERVICES, KeyType::SERVICE_LIST));
150 values.emplace_back(servicesJson_.dump());
151 }
152
153 int32_t errCode = ERR_OK;
154 if (onlineSyncTbl_->GetInitStatus() == StorageInitStatus::INIT_SUCCEED) {
155 autoLock.unlock();
156 if (keys.size() > 1) {
157 errCode = onlineSyncTbl_->PutDeviceProfileBatch(keys, values);
158 } else {
159 errCode = onlineSyncTbl_->PutDeviceProfile(keys[0], values[0]);
160 }
161 } else {
162 for (size_t i = 0; i < keys.size(); i++) {
163 profileItems_[keys[i]] = values[i];
164 }
165 }
166 return errCode;
167 }
168
GetDeviceProfile(const std::string & udid,const std::string & serviceId,ServiceCharacteristicProfile & profile)169 int32_t DeviceProfileStorageManager::GetDeviceProfile(const std::string& udid,
170 const std::string& serviceId, ServiceCharacteristicProfile& profile)
171 {
172 if (onlineSyncTbl_->GetInitStatus() == StorageInitStatus::INIT_FAILED) {
173 HILOGE("kvstore init failed");
174 return ERR_DP_INIT_DB_FAILED;
175 }
176
177 std::string key;
178 std::string value;
179 int32_t result = ERR_OK;
180 if (udid.empty()) {
181 key = GenerateKey(localUdid_, serviceId, KeyType::SERVICE);
182 SetServiceType(udid, serviceId, profile);
183 } else {
184 std::string queryUdid;
185 if (!DeviceManager::GetInstance().TransformDeviceId(udid, queryUdid,
186 DeviceIdType::UDID)) {
187 HILOGE("transform to networkid failed");
188 return ERR_DP_INVALID_PARAMS;
189 }
190 key = GenerateKey(queryUdid, serviceId, KeyType::SERVICE);
191 SetServiceType(queryUdid, serviceId, profile);
192 }
193 std::unique_lock<std::mutex> autoLock(serviceLock_);
194 auto itItem = profileItems_.find(key);
195 if (itItem != profileItems_.end()) {
196 value = profileItems_[key];
197 } else {
198 autoLock.unlock();
199 result = onlineSyncTbl_->GetDeviceProfile(key, value);
200 }
201 profile.SetServiceId(serviceId);
202 profile.SetCharacteristicProfileJson(value);
203 return result;
204 }
205
SetServiceType(const std::string & udid,const std::string & serviceId,ServiceCharacteristicProfile & profile)206 void DeviceProfileStorageManager::SetServiceType(const std::string& udid,
207 const std::string& serviceId, ServiceCharacteristicProfile& profile)
208 {
209 std::unique_lock<std::mutex> autoLock(serviceLock_);
210 if (udid.empty()) {
211 auto jsonData = servicesJson_[serviceId];
212 if (jsonData != nullptr) {
213 profile.SetServiceType(jsonData[SERVICE_TYPE]);
214 }
215 return;
216 }
217
218 std::string value;
219 std::string key = GenerateKey(udid, SERVICES, KeyType::SERVICE_LIST);
220 int32_t result = onlineSyncTbl_->GetDeviceProfile(key, value);
221 if (result != ERR_OK) {
222 HILOGE("get service type failed");
223 return;
224 }
225 auto jsonData = nlohmann::json::parse(value, nullptr, false);
226 if (jsonData.is_discarded()) {
227 HILOGE("parse error");
228 return;
229 }
230 auto typeData = jsonData[serviceId];
231 if (typeData != nullptr && typeData[SERVICE_TYPE] != nullptr) {
232 profile.SetServiceType(typeData[SERVICE_TYPE]);
233 }
234 }
235
DeleteDeviceProfile(const std::string & serviceId)236 int32_t DeviceProfileStorageManager::DeleteDeviceProfile(const std::string& serviceId)
237 {
238 if (onlineSyncTbl_->GetInitStatus() == StorageInitStatus::INIT_FAILED) {
239 HILOGE("kvstore init failed");
240 return ERR_DP_INIT_DB_FAILED;
241 }
242
243 std::unique_lock<std::mutex> autoLock(serviceLock_);
244 if (servicesJson_[serviceId] == nullptr) {
245 HILOGW("can't find service %{public}s", serviceId.c_str());
246 return ERR_DP_INVALID_PARAMS;
247 }
248 nlohmann::json original = servicesJson_[serviceId];
249 servicesJson_.erase(serviceId);
250 std::string servicesKey = GenerateKey(localUdid_, SERVICES, KeyType::SERVICE_LIST);
251 std::string servicesValue = servicesJson_.dump();
252 int32_t errCode = ERR_OK;
253 std::string serviceKey = GenerateKey(localUdid_, serviceId, KeyType::SERVICE);
254 if (onlineSyncTbl_->GetInitStatus() == StorageInitStatus::INIT_SUCCEED) {
255 errCode = onlineSyncTbl_->DeleteDeviceProfile(serviceKey);
256 if (errCode != ERR_OK) {
257 servicesJson_[serviceId] = std::move(original);
258 return errCode;
259 }
260 errCode = onlineSyncTbl_->PutDeviceProfile(servicesKey, servicesValue);
261 if (errCode != ERR_OK) {
262 HILOGW("update services failed, errorCode = %{public}d", errCode);
263 }
264 } else {
265 profileItems_.erase(serviceKey);
266 profileItems_[servicesKey] = std::move(servicesValue);
267 }
268 return errCode;
269 }
270
SyncDeviceProfile(const SyncOptions & syncOptions,const sptr<IRemoteObject> & profileEventNotifier)271 int32_t DeviceProfileStorageManager::SyncDeviceProfile(const SyncOptions& syncOptions,
272 const sptr<IRemoteObject>& profileEventNotifier)
273 {
274 if (onlineSyncTbl_->GetInitStatus() == StorageInitStatus::INIT_FAILED) {
275 HILOGE("kvstore init failed");
276 return ERR_DP_INIT_DB_FAILED;
277 }
278
279 if (!CheckSyncOption(syncOptions)) {
280 HILOGW("device list has offline device");
281 return ERR_DP_INVALID_PARAMS;
282 }
283
284 int32_t result = NotifySyncStart(profileEventNotifier);
285 if (result != ERR_OK) {
286 return result;
287 }
288
289 auto syncTask = [syncOptions, this]() {
290 HILOGI("start sync");
291 auto devicesList = syncOptions.GetDeviceList();
292 if (devicesList.empty()) {
293 DeviceManager::GetInstance().GetDeviceIdList(devicesList);
294 }
295 SyncCoordinator::GetInstance().SetSyncTrigger(false);
296 std::vector<std::string> devicesVector(std::vector<std::string> { devicesList.begin(), devicesList.end() });
297 int32_t result = onlineSyncTbl_->SyncDeviceProfile(devicesVector, syncOptions.GetSyncMode());
298 if (result != ERR_OK) {
299 HILOGE("sync failed result : %{public}d", result);
300 NotifySyncCompleted();
301 return;
302 }
303 };
304 if (!SyncCoordinator::GetInstance().DispatchSyncTask(syncTask)) {
305 HILOGE("post sync task failed");
306 NotifySyncCompleted();
307 return ERR_DP_POST_TASK_FAILED;
308 }
309 return ERR_OK;
310 }
311
NotifySyncStart(const sptr<IRemoteObject> & profileEventNotifier)312 int32_t DeviceProfileStorageManager::NotifySyncStart(const sptr<IRemoteObject>& profileEventNotifier)
313 {
314 if (!SyncCoordinator::GetInstance().AcquireSync()) {
315 HILOGW("sync busy");
316 return ERR_DP_DEVICE_SYNC_BUSY;
317 }
318
319 {
320 std::lock_guard<std::mutex> autoLock(profileSyncLock_);
321 syncEventNotifier_ = profileEventNotifier;
322 }
323
324 SubscribeInfo subscribeInfo;
325 subscribeInfo.profileEvent = ProfileEvent::EVENT_SYNC_COMPLETED;
326 std::list<SubscribeInfo> subscribeInfos;
327 subscribeInfos.emplace_back(subscribeInfo);
328 std::list<ProfileEvent> failedEvents;
329 if (SubscribeManager::GetInstance().SubscribeProfileEvents(
330 subscribeInfos, profileEventNotifier, failedEvents) != ERR_OK) {
331 HILOGE("subscribe sync event failed");
332 SyncCoordinator::GetInstance().ReleaseSync();
333 std::lock_guard<std::mutex> autoLock(profileSyncLock_);
334 syncEventNotifier_ = nullptr;
335 return ERR_DP_SUBSCRIBE_FAILED;
336 }
337 return ERR_OK;
338 }
339
NotifySyncCompleted()340 void DeviceProfileStorageManager::NotifySyncCompleted()
341 {
342 HILOGI("called");
343 SyncCoordinator::GetInstance().ReleaseSync();
344 std::lock_guard<std::mutex> autoLock(profileSyncLock_);
345 std::list<ProfileEvent> profileEvents;
346 profileEvents.emplace_back(ProfileEvent::EVENT_SYNC_COMPLETED);
347 std::list<ProfileEvent> failedEvents;
348 int32_t ret = SubscribeManager::GetInstance().UnsubscribeProfileEvents(
349 profileEvents, syncEventNotifier_, failedEvents);
350 if (ret != ERR_OK) {
351 HILOGW("unsubscribe sync event failed");
352 }
353 syncEventNotifier_ = nullptr;
354 }
355
NotifySubscriberDied(const sptr<IRemoteObject> & profileEventNotifier)356 void DeviceProfileStorageManager::NotifySubscriberDied(const sptr<IRemoteObject>& profileEventNotifier)
357 {
358 HILOGI("called");
359 std::lock_guard<std::mutex> autoLock(profileSyncLock_);
360 if (profileEventNotifier != syncEventNotifier_) {
361 return;
362 }
363
364 SyncCoordinator::GetInstance().ReleaseSync();
365 syncEventNotifier_ = nullptr;
366 }
367
CheckSyncOption(const SyncOptions & syncOptions)368 bool DeviceProfileStorageManager::CheckSyncOption(const SyncOptions& syncOptions)
369 {
370 std::list<std::shared_ptr<DeviceInfo>> onlineDevices;
371 DeviceManager::GetInstance().GetDeviceList(onlineDevices);
372 std::list<std::string> onlineDeviceIds;
373 for (const auto& onlineDevice : onlineDevices) {
374 onlineDeviceIds.emplace_back(onlineDevice->GetDeviceId());
375 }
376
377 // check whether deviceId is online
378 auto syncDeviceIds = syncOptions.GetDeviceList();
379 for (const auto& syncDeviceId : syncDeviceIds) {
380 auto iter = find(onlineDeviceIds.begin(), onlineDeviceIds.end(), syncDeviceId);
381 if (iter == onlineDeviceIds.end()) {
382 HILOGE("deviceId: %{public}s is not online", DeviceProfileUtils::AnonymizeDeviceId(syncDeviceId).c_str());
383 return false;
384 }
385 }
386 return true;
387 }
388
RestoreServiceItemLocked(const std::string & value)389 void DeviceProfileStorageManager::RestoreServiceItemLocked(const std::string& value)
390 {
391 auto restoreItems = nlohmann::json::parse(value, nullptr, false);
392 if (restoreItems.is_discarded()) {
393 HILOGE("parse error");
394 return;
395 }
396 for (const auto& [key, value] : servicesJson_.items()) {
397 restoreItems[key] = value;
398 }
399 servicesJson_ = std::move(restoreItems);
400 }
401
FlushProfileItems()402 void DeviceProfileStorageManager::FlushProfileItems()
403 {
404 std::string services;
405 std::string servicesKey = GenerateKey(localUdid_, SERVICES, KeyType::SERVICE_LIST);
406 int32_t errCode = onlineSyncTbl_->GetDeviceProfile(servicesKey, services);
407 std::unique_lock<std::mutex> autoLock(serviceLock_);
408 if (errCode == ERR_OK) {
409 RestoreServiceItemLocked(services);
410 }
411
412 std::vector<std::string> keys;
413 std::vector<std::string> values;
414 size_t itemSize = profileItems_.size();
415 HILOGI("profile item size = %{public}zu", itemSize);
416 if (itemSize == 0) {
417 return;
418 }
419 keys.reserve(itemSize);
420 values.reserve(itemSize);
421 // update service list to avoid overwriting the value in db storage
422 profileItems_[servicesKey] = servicesJson_.dump();
423 for (const auto& [key, value] : profileItems_) {
424 keys.emplace_back(key);
425 values.emplace_back(value);
426 HILOGD("key = %{public}s, value = %{public}s", key.c_str(), value.c_str());
427 }
428 profileItems_.clear();
429 autoLock.unlock();
430
431 errCode = onlineSyncTbl_->PutDeviceProfileBatch(keys, values);
432 if (errCode != ERR_OK) {
433 HILOGE("put failed, errCode = %{public}d", errCode);
434 }
435 }
436
RegisterCallbacks()437 void DeviceProfileStorageManager::RegisterCallbacks()
438 {
439 HILOGI("called");
440 int32_t errCode = ERR_OK;
441 if (kvStoreObserver_ != nullptr) {
442 errCode = onlineSyncTbl_->SubscribeKvStore(kvStoreObserver_);
443 HILOGI("SubscribeKvStore errCode = %{public}d", errCode);
444 }
445 if (kvStoreSyncCallback_ != nullptr) {
446 errCode = onlineSyncTbl_->RegisterSyncCallback(kvStoreSyncCallback_);
447 HILOGI("RegisterSyncCallback errCode = %{public}d", errCode);
448 }
449 }
450
OnKvStoreInitDone()451 void DeviceProfileStorageManager::OnKvStoreInitDone()
452 {
453 RegisterCallbacks();
454 FlushProfileItems();
455 }
456
SubscribeKvStore(const std::shared_ptr<KvStoreObserver> & observer)457 int32_t DeviceProfileStorageManager::SubscribeKvStore(const std::shared_ptr<KvStoreObserver>& observer)
458 {
459 std::lock_guard<std::mutex> autoLock(callbackLock_);
460 kvStoreObserver_ = observer;
461 if (onlineSyncTbl_->GetInitStatus() == StorageInitStatus::INIT_SUCCEED) {
462 return onlineSyncTbl_->SubscribeKvStore(observer);
463 }
464 return ERR_OK;
465 }
466
UnSubscribeKvStore(const std::shared_ptr<KvStoreObserver> & observer)467 int32_t DeviceProfileStorageManager::UnSubscribeKvStore(const std::shared_ptr<KvStoreObserver>& observer)
468 {
469 std::lock_guard<std::mutex> autoLock(callbackLock_);
470 kvStoreObserver_ = nullptr;
471 return onlineSyncTbl_->UnSubscribeKvStore(observer);
472 }
473
RegisterSyncCallback(const std::shared_ptr<KvStoreSyncCallback> & sycnCb)474 int32_t DeviceProfileStorageManager::RegisterSyncCallback(const std::shared_ptr<KvStoreSyncCallback>& sycnCb)
475 {
476 std::lock_guard<std::mutex> autoLock(callbackLock_);
477 kvStoreSyncCallback_ = sycnCb;
478 if (onlineSyncTbl_->GetInitStatus() == StorageInitStatus::INIT_SUCCEED) {
479 return onlineSyncTbl_->RegisterSyncCallback(sycnCb);
480 }
481 return ERR_OK;
482 }
483
UnRegisterSyncCallback()484 int32_t DeviceProfileStorageManager::UnRegisterSyncCallback()
485 {
486 std::lock_guard<std::mutex> autoLock(callbackLock_);
487 kvStoreSyncCallback_ = nullptr;
488 return onlineSyncTbl_->UnRegisterSyncCallback();
489 }
490
OnNodeOnline(const std::shared_ptr<DeviceInfo> deviceInfo)491 void DeviceProfileStorageManager::OnNodeOnline(const std::shared_ptr<DeviceInfo> deviceInfo)
492 {
493 std::string deviceId = deviceInfo->GetDeviceId();
494 HILOGI("online deviceId %{public}s", DeviceProfileUtils::AnonymizeDeviceId(deviceId).c_str());
495 PostOnlineSync(deviceId, 0);
496 }
497
PostOnlineSync(const std::string & deviceId,int32_t retryTimes)498 void DeviceProfileStorageManager::PostOnlineSync(const std::string& deviceId, int32_t retryTimes)
499 {
500 if (retryTimes >= RETRY_TIMES_POST_ONLINE_SYNC) {
501 HILOGE("reach max retry times");
502 return;
503 }
504
505 auto onlineSyncTaks = [this, deviceId = std::move(deviceId), retryTimes = retryTimes]() mutable {
506 if (!SyncCoordinator::GetInstance().AcquireSync()) {
507 PostOnlineSync(deviceId, retryTimes++);
508 return;
509 }
510 HILOGI("current retry times = %{public}d", retryTimes);
511 std::vector<std::string> onlineDeviceId = { deviceId };
512 SyncCoordinator::GetInstance().SetSyncTrigger(true);
513 int32_t errCode = onlineSyncTbl_->SyncDeviceProfile(onlineDeviceId, SyncMode::PUSH);
514 if (errCode != ERR_OK) {
515 HILOGE("online sync errCode = %{public}d", errCode);
516 }
517 };
518 if (!storageHandler_->PostTask(onlineSyncTaks, INTREVAL_POST_ONLINE_SYNC_MS)) {
519 HILOGE("post task failed");
520 return;
521 }
522 }
523 } // namespace DeviceProfile
524 } // namespace OHOS
525