1 /*
2 * Copyright (c) 2022-2023 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 "dm_device_state_manager.h"
17
18 #include <pthread.h>
19
20 #include "dm_adapter_manager.h"
21 #include "dm_anonymous.h"
22 #include "dm_constants.h"
23 #include "dm_distributed_hardware_load.h"
24 #include "dm_log.h"
25
26 namespace OHOS {
27 namespace DistributedHardware {
28 const uint32_t DM_EVENT_QUEUE_CAPACITY = 20;
29 const uint32_t DM_EVENT_WAIT_TIMEOUT = 2;
30 constexpr const char* THREAD_LOOP = "ThreadLoop";
DmDeviceStateManager(std::shared_ptr<SoftbusConnector> softbusConnector,std::shared_ptr<IDeviceManagerServiceListener> listener,std::shared_ptr<HiChainConnector> hiChainConnector)31 DmDeviceStateManager::DmDeviceStateManager(std::shared_ptr<SoftbusConnector> softbusConnector,
32 std::shared_ptr<IDeviceManagerServiceListener> listener, std::shared_ptr<HiChainConnector> hiChainConnector)
33 : softbusConnector_(softbusConnector), listener_(listener), hiChainConnector_(hiChainConnector)
34 {
35 decisionSoName_ = "libdevicemanagerext_decision.z.so";
36 StartEventThread();
37 LOGI("DmDeviceStateManager constructor");
38 }
39
~DmDeviceStateManager()40 DmDeviceStateManager::~DmDeviceStateManager()
41 {
42 LOGI("DmDeviceStateManager destructor");
43 if (softbusConnector_ != nullptr) {
44 softbusConnector_->UnRegisterSoftbusStateCallback("DM_PKG_NAME");
45 }
46 StopEventThread();
47 }
48
SaveOnlineDeviceInfo(const std::string & pkgName,const DmDeviceInfo & info)49 void DmDeviceStateManager::SaveOnlineDeviceInfo(const std::string &pkgName, const DmDeviceInfo &info)
50 {
51 (void)pkgName;
52 LOGI("SaveOnlineDeviceInfo begin, deviceId = %s", GetAnonyString(std::string(info.deviceId)).c_str());
53 std::string udid;
54 if (SoftbusConnector::GetUdidByNetworkId(info.networkId, udid) == DM_OK) {
55 std::string uuid;
56 DmDeviceInfo saveInfo = info;
57 SoftbusConnector::GetUuidByNetworkId(info.networkId, uuid);
58 {
59 #if defined(__LITEOS_M__)
60 DmMutex mutexLock;
61 #else
62 std::lock_guard<std::mutex> mutexLock(remoteDeviceInfosMutex_);
63 #endif
64 remoteDeviceInfos_[uuid] = saveInfo;
65 }
66 LOGI("SaveOnlineDeviceInfo complete, networkId = %s, udid = %s, uuid = %s", GetAnonyString(
67 std::string(info.networkId)).c_str(), GetAnonyString(udid).c_str(), GetAnonyString(uuid).c_str());
68 }
69 }
70
DeleteOfflineDeviceInfo(const std::string & pkgName,const DmDeviceInfo & info)71 void DmDeviceStateManager::DeleteOfflineDeviceInfo(const std::string &pkgName, const DmDeviceInfo &info)
72 {
73 (void)pkgName;
74 LOGI("DeleteOfflineDeviceInfo begin, deviceId = %s", GetAnonyString(std::string(info.deviceId)).c_str());
75 #if defined(__LITEOS_M__)
76 DmMutex mutexLock;
77 #else
78 std::lock_guard<std::mutex> mutexLock(remoteDeviceInfosMutex_);
79 #endif
80 for (auto iter: remoteDeviceInfos_) {
81 if (iter.second.deviceId == info.deviceId) {
82 remoteDeviceInfos_.erase(iter.first);
83 LOGI("DeleteOfflineDeviceInfo complete");
84 break;
85 }
86 }
87 }
88
PostDeviceOnline(const std::string & pkgName,DmDeviceInfo & info)89 void DmDeviceStateManager::PostDeviceOnline(const std::string &pkgName, DmDeviceInfo &info)
90 {
91 LOGI("DmDeviceStateManager::PostDeviceOnline in");
92 if (listener_ != nullptr) {
93 DmDeviceState state = DEVICE_STATE_ONLINE;
94 info.authForm = GetAuthForm(info.networkId);
95 listener_->OnDeviceStateChange(pkgName, state, info);
96 }
97 LOGI("DmDeviceStateManager::PostDeviceOnline out");
98 }
99
PostDeviceOffline(const std::string & pkgName,const DmDeviceInfo & info)100 void DmDeviceStateManager::PostDeviceOffline(const std::string &pkgName, const DmDeviceInfo &info)
101 {
102 LOGI("DmDeviceStateManager::PostDeviceOffline in");
103 if (listener_ != nullptr) {
104 DmDeviceState state = DEVICE_STATE_OFFLINE;
105 listener_->OnDeviceStateChange(pkgName, state, info);
106 }
107 LOGI("DmDeviceStateManager::PostDeviceOffline out");
108 }
109
PostDeviceChanged(const std::string & pkgName,const DmDeviceInfo & info)110 void DmDeviceStateManager::PostDeviceChanged(const std::string &pkgName, const DmDeviceInfo &info)
111 {
112 LOGI("DmDeviceStateManager::PostDeviceChanged in");
113 if (listener_ != nullptr) {
114 DmDeviceState state = DEVICE_INFO_CHANGED;
115 listener_->OnDeviceStateChange(pkgName, state, info);
116 }
117 LOGI("DmDeviceStateManager::PostDeviceChanged out");
118 }
119
OnDeviceOnline(const std::string & pkgName,DmDeviceInfo & info)120 void DmDeviceStateManager::OnDeviceOnline(const std::string &pkgName, DmDeviceInfo &info)
121 {
122 LOGI("OnDeviceOnline function is called with pkgName: %s", pkgName.c_str());
123 RegisterOffLineTimer(info);
124 SaveOnlineDeviceInfo(pkgName, info);
125
126 DmAdapterManager &adapterMgrPtr = DmAdapterManager::GetInstance();
127 std::shared_ptr<IDecisionAdapter> decisionAdapter = adapterMgrPtr.GetDecisionAdapter(decisionSoName_);
128 #if defined(__LITEOS_M__)
129 DmMutex mutexLock;
130 #else
131 std::lock_guard<std::mutex> mutexLock(decisionInfosMutex_);
132 #endif
133 if (decisionAdapter == nullptr) {
134 LOGE("OnDeviceOnline decision adapter is null");
135 PostDeviceOnline(pkgName, info);
136 } else if (decisionInfos_.size() == 0) {
137 PostDeviceOnline(pkgName, info);
138 } else {
139 std::vector<DmDeviceInfo> infoList;
140 LOGI("OnDeviceOnline decision decisionInfos_ size: %d", decisionInfos_.size());
141 for (auto iter : decisionInfos_) {
142 std::string listenerPkgName = iter.first;
143 std::string extra = iter.second;
144 infoList.clear();
145 infoList.push_back(info);
146 decisionAdapter->FilterDeviceList(infoList, extra);
147 if (infoList.size() == 1) {
148 PostDeviceOnline(listenerPkgName, info);
149 }
150 }
151 }
152 LOGI("DmDeviceStateManager::OnDeviceOnline out");
153 }
154
OnDeviceOffline(const std::string & pkgName,const DmDeviceInfo & info)155 void DmDeviceStateManager::OnDeviceOffline(const std::string &pkgName, const DmDeviceInfo &info)
156 {
157 LOGI("OnDeviceOffline function is called with pkgName: %s", pkgName.c_str());
158 StartOffLineTimer(info);
159 DeleteOfflineDeviceInfo(pkgName, info);
160
161 DmAdapterManager &adapterMgrPtr = DmAdapterManager::GetInstance();
162 std::shared_ptr<IDecisionAdapter> decisionAdapter = adapterMgrPtr.GetDecisionAdapter(decisionSoName_);
163 #if defined(__LITEOS_M__)
164 DmMutex mutexLock;
165 #else
166 std::lock_guard<std::mutex> mutexLock(decisionInfosMutex_);
167 #endif
168 if (decisionAdapter == nullptr) {
169 LOGE("OnDeviceOffline decision adapter is null");
170 PostDeviceOffline(pkgName, info);
171 } else if (decisionInfos_.size() == 0) {
172 PostDeviceOffline(pkgName, info);
173 } else {
174 std::vector<DmDeviceInfo> infoList;
175 LOGI("OnDeviceOffline decision decisionInfos_ size: %d", decisionInfos_.size());
176 for (auto iter : decisionInfos_) {
177 std::string listenerPkgName = iter.first;
178 std::string extra = iter.second;
179 infoList.clear();
180 infoList.push_back(info);
181 decisionAdapter->FilterDeviceList(infoList, extra);
182 if (infoList.size() == 1) {
183 PostDeviceOffline(listenerPkgName, info);
184 }
185 }
186 }
187 LOGI("DmDeviceStateManager::OnDeviceOffline out");
188 }
189
OnDeviceChanged(const std::string & pkgName,const DmDeviceInfo & info)190 void DmDeviceStateManager::OnDeviceChanged(const std::string &pkgName, const DmDeviceInfo &info)
191 {
192 LOGI("OnDeviceChanged function is called with pkgName: %s", pkgName.c_str());
193 ChangeDeviceInfo(pkgName, info);
194 DmAdapterManager &adapterMgrPtr = DmAdapterManager::GetInstance();
195 std::shared_ptr<IDecisionAdapter> decisionAdapter = adapterMgrPtr.GetDecisionAdapter(decisionSoName_);
196 #if defined(__LITEOS_M__)
197 DmMutex mutexLock;
198 #else
199 std::lock_guard<std::mutex> mutexLock(decisionInfosMutex_);
200 #endif
201 if (decisionAdapter == nullptr) {
202 LOGE("OnDeviceChanged decision adapter is null");
203 PostDeviceChanged(pkgName, info);
204 } else if (decisionInfos_.size() == 0) {
205 PostDeviceChanged(pkgName, info);
206 } else {
207 std::vector<DmDeviceInfo> infoList;
208 LOGI("OnDeviceChanged decision decisionInfos_ size: %d", decisionInfos_.size());
209 for (auto iter : decisionInfos_) {
210 std::string listenerPkgName = iter.first;
211 std::string extra = iter.second;
212 infoList.clear();
213 infoList.push_back(info);
214 decisionAdapter->FilterDeviceList(infoList, extra);
215 if (infoList.size() == 1) {
216 PostDeviceChanged(listenerPkgName, info);
217 }
218 }
219 }
220 LOGI("DmDeviceStateManager::OnDeviceChanged out");
221 }
222
OnDeviceReady(const std::string & pkgName,const DmDeviceInfo & info)223 void DmDeviceStateManager::OnDeviceReady(const std::string &pkgName, const DmDeviceInfo &info)
224 {
225 LOGI("OnDeviceReady function is called back with pkgName: %s", pkgName.c_str());
226 }
227
OnDbReady(const std::string & pkgName,const std::string & deviceId)228 void DmDeviceStateManager::OnDbReady(const std::string &pkgName, const std::string &deviceId)
229 {
230 LOGI("OnDbReady function is called with pkgName: %s", pkgName.c_str());
231 if (pkgName.empty() || deviceId.empty()) {
232 LOGE("On db ready pkgName is empty or deviceId is deviceId");
233 return;
234 }
235 DmDeviceInfo saveInfo;
236 {
237 #if defined(__LITEOS_M__)
238 DmMutex mutexLock;
239 #else
240 std::lock_guard<std::mutex> mutexLock(remoteDeviceInfosMutex_);
241 #endif
242 auto iter = remoteDeviceInfos_.find(deviceId);
243 if (iter == remoteDeviceInfos_.end()) {
244 LOGE("OnDbReady complete not find deviceId: %s", GetAnonyString(deviceId).c_str());
245 return;
246 }
247 saveInfo = iter->second;
248 }
249 DmDistributedHardwareLoad::GetInstance().LoadDistributedHardwareFwk();
250 if (listener_ != nullptr) {
251 DmDeviceState state = DEVICE_INFO_READY;
252 listener_->OnDeviceStateChange(pkgName, state, saveInfo);
253 }
254 }
255
RegisterSoftbusStateCallback()256 int32_t DmDeviceStateManager::RegisterSoftbusStateCallback()
257 {
258 if (softbusConnector_ != nullptr) {
259 return softbusConnector_->RegisterSoftbusStateCallback(std::string(DM_PKG_NAME), shared_from_this());
260 }
261 return DM_OK;
262 }
263
RegisterDevStateCallback(const std::string & pkgName,const std::string & extra)264 void DmDeviceStateManager::RegisterDevStateCallback(const std::string &pkgName, const std::string &extra)
265 {
266 if (pkgName.empty()) {
267 LOGE("DmDeviceStateManager::RegisterDevStateCallback input param is empty");
268 return;
269 }
270 LOGI("DmDeviceStateManager::RegisterDevStateCallback pkgName = %s, extra = %s",
271 GetAnonyString(pkgName).c_str(), GetAnonyString(extra).c_str());
272 #if defined(__LITEOS_M__)
273 DmMutex mutexLock;
274 #else
275 std::lock_guard<std::mutex> mutexLock(decisionInfosMutex_);
276 #endif
277 if (decisionInfos_.count(pkgName) == 0) {
278 decisionInfos_.insert(std::map<std::string, std::string>::value_type (pkgName, extra));
279 }
280 }
281
UnRegisterDevStateCallback(const std::string & pkgName,const std::string & extra)282 void DmDeviceStateManager::UnRegisterDevStateCallback(const std::string &pkgName, const std::string &extra)
283 {
284 if (pkgName.empty()) {
285 LOGE("DmDeviceStateManager::UnRegisterDevStateCallback input param is empty");
286 return;
287 }
288 LOGI("DmDeviceStateManager::UnRegisterDevStateCallback pkgName = %s, extra = %s",
289 GetAnonyString(pkgName).c_str(), GetAnonyString(extra).c_str());
290 #if defined(__LITEOS_M__)
291 DmMutex mutexLock;
292 #else
293 std::lock_guard<std::mutex> mutexLock(decisionInfosMutex_);
294 #endif
295 if (decisionInfos_.count(pkgName) > 0) {
296 auto iter = decisionInfos_.find(pkgName);
297 if (iter != decisionInfos_.end()) {
298 decisionInfos_.erase(pkgName);
299 }
300 }
301 }
302
RegisterOffLineTimer(const DmDeviceInfo & deviceInfo)303 void DmDeviceStateManager::RegisterOffLineTimer(const DmDeviceInfo &deviceInfo)
304 {
305 std::string deviceUdid;
306 int32_t ret = softbusConnector_->GetUdidByNetworkId(deviceInfo.networkId, deviceUdid);
307 if (ret != DM_OK) {
308 LOGE("fail to get udid by networkId");
309 return;
310 }
311 LOGI("Register offline timer for deviceUdid: %s", GetAnonyString(deviceUdid).c_str());
312 #if defined(__LITEOS_M__)
313 DmMutex mutexLock;
314 #else
315 std::lock_guard<std::mutex> mutexLock(timerMapMutex_);
316 #endif
317 for (auto &iter : stateTimerInfoMap_) {
318 if ((iter.first == deviceUdid) && (timer_ != nullptr)) {
319 timer_->DeleteTimer(iter.second.timerName);
320 stateTimerInfoMap_.erase(iter.first);
321 break;
322 }
323 }
324 if (stateTimerInfoMap_.find(deviceUdid) == stateTimerInfoMap_.end()) {
325 std::string timerName = std::string(STATE_TIMER_PREFIX) + GetAnonyString(deviceUdid);
326 StateTimerInfo stateTimer = {
327 .timerName = timerName,
328 .networkId = deviceInfo.networkId,
329 .isStart = false,
330 };
331 stateTimerInfoMap_[deviceUdid] = stateTimer;
332 }
333 }
334
StartOffLineTimer(const DmDeviceInfo & deviceInfo)335 void DmDeviceStateManager::StartOffLineTimer(const DmDeviceInfo &deviceInfo)
336 {
337 #if defined(__LITEOS_M__)
338 DmMutex mutexLock;
339 #else
340 std::lock_guard<std::mutex> mutexLock(timerMapMutex_);
341 #endif
342 std::string networkId = deviceInfo.networkId;
343 LOGI("Start offline timer for networkId: %s", GetAnonyString(networkId).c_str());
344 if (timer_ == nullptr) {
345 timer_ = std::make_shared<DmTimer>();
346 }
347 for (auto &iter : stateTimerInfoMap_) {
348 if ((iter.second.networkId == networkId) && !iter.second.isStart) {
349 timer_->StartTimer(iter.second.timerName, OFFLINE_TIMEOUT,
350 [this] (std::string name) {
351 DmDeviceStateManager::DeleteTimeOutGroup(name);
352 });
353 iter.second.isStart = true;
354 }
355 }
356 }
357
DeleteTimeOutGroup(std::string name)358 void DmDeviceStateManager::DeleteTimeOutGroup(std::string name)
359 {
360 #if defined(__LITEOS_M__)
361 DmMutex mutexLock;
362 #else
363 std::lock_guard<std::mutex> mutexLock(timerMapMutex_);
364 #endif
365 for (auto iter = stateTimerInfoMap_.begin(); iter != stateTimerInfoMap_.end(); iter++) {
366 if (((iter->second).timerName == name) && (hiChainConnector_ != nullptr)) {
367 LOGI("remove hichain group with deviceId: %s", GetAnonyString(iter->first).c_str());
368 hiChainConnector_->DeleteTimeOutGroup((iter->first).c_str());
369 stateTimerInfoMap_.erase(iter);
370 break;
371 }
372 }
373 }
374
StartEventThread()375 void DmDeviceStateManager::StartEventThread()
376 {
377 LOGI("StartEventThread begin");
378 eventTask_.threadRunning_ = true;
379 eventTask_.queueThread_ = std::thread(&DmDeviceStateManager::ThreadLoop, this);
380 LOGI("StartEventThread complete");
381 }
382
StopEventThread()383 void DmDeviceStateManager::StopEventThread()
384 {
385 LOGI("StopEventThread begin");
386 eventTask_.threadRunning_ = false;
387 eventTask_.queueCond_.notify_all();
388 eventTask_.queueFullCond_.notify_all();
389 if (eventTask_.queueThread_.joinable()) {
390 eventTask_.queueThread_.join();
391 }
392 LOGI("StopEventThread complete");
393 }
394
AddTask(const std::shared_ptr<NotifyEvent> & task)395 int32_t DmDeviceStateManager::AddTask(const std::shared_ptr<NotifyEvent> &task)
396 {
397 LOGI("AddTask begin, eventId: %d", task->GetEventId());
398 {
399 std::unique_lock<std::mutex> lock(eventTask_.queueMtx_);
400 while (eventTask_.queue_.size() >= DM_EVENT_QUEUE_CAPACITY) {
401 eventTask_.queueFullCond_.wait_for(lock, std::chrono::seconds(DM_EVENT_WAIT_TIMEOUT));
402 }
403 eventTask_.queue_.push(task);
404 }
405 eventTask_.queueCond_.notify_one();
406 LOGI("AddTask complete");
407 return DM_OK;
408 }
409
ThreadLoop()410 void DmDeviceStateManager::ThreadLoop()
411 {
412 LOGI("ThreadLoop begin");
413 int32_t ret = pthread_setname_np(pthread_self(), THREAD_LOOP);
414 if (ret != DM_OK) {
415 LOGE("ThreadLoop setname failed.");
416 }
417 while (eventTask_.threadRunning_) {
418 std::shared_ptr<NotifyEvent> task = nullptr;
419 {
420 std::unique_lock<std::mutex> lock(eventTask_.queueMtx_);
421 while (eventTask_.queue_.empty() && eventTask_.threadRunning_) {
422 eventTask_.queueCond_.wait_for(lock, std::chrono::seconds(DM_EVENT_WAIT_TIMEOUT));
423 }
424 if (!eventTask_.queue_.empty()) {
425 task = eventTask_.queue_.front();
426 eventTask_.queue_.pop();
427 eventTask_.queueFullCond_.notify_one();
428 }
429 }
430 if (task != nullptr) {
431 RunTask(task);
432 }
433 }
434 LOGI("ThreadLoop end");
435 }
436
RunTask(const std::shared_ptr<NotifyEvent> & task)437 void DmDeviceStateManager::RunTask(const std::shared_ptr<NotifyEvent> &task)
438 {
439 LOGI("RunTask begin, eventId: %d", task->GetEventId());
440 if (task->GetEventId() == DM_NOTIFY_EVENT_ONDEVICEREADY) {
441 OnDbReady(std::string(DM_PKG_NAME), task->GetDeviceId());
442 }
443 LOGI("RunTask complete");
444 }
445
GetAuthForm(const std::string & networkId)446 DmAuthForm DmDeviceStateManager::GetAuthForm(const std::string &networkId)
447 {
448 LOGI("GetAuthForm start");
449 if (hiChainConnector_ == nullptr) {
450 LOGE("hiChainConnector_ is nullptr");
451 return DmAuthForm::INVALID_TYPE;
452 }
453
454 if (networkId.empty()) {
455 LOGE("networkId is empty");
456 return DmAuthForm::INVALID_TYPE;
457 }
458
459 std::string udid;
460 if (SoftbusConnector::GetUdidByNetworkId(networkId.c_str(), udid) == DM_OK) {
461 return hiChainConnector_->GetGroupType(udid);
462 }
463
464 return DmAuthForm::INVALID_TYPE;
465 }
466
ProcNotifyEvent(const std::string & pkgName,const int32_t eventId,const std::string & deviceId)467 int32_t DmDeviceStateManager::ProcNotifyEvent(const std::string &pkgName, const int32_t eventId,
468 const std::string &deviceId)
469 {
470 (void)pkgName;
471 LOGI("ProcNotifyEvent in, eventId: %d", eventId);
472 return AddTask(std::make_shared<NotifyEvent>(eventId, deviceId));
473 }
474
ChangeDeviceInfo(const std::string & pkgName,const DmDeviceInfo & info)475 void DmDeviceStateManager::ChangeDeviceInfo(const std::string &pkgName, const DmDeviceInfo &info)
476 {
477 (void)pkgName;
478 #if defined(__LITEOS_M__)
479 DmMutex mutexLock;
480 #else
481 std::lock_guard<std::mutex> mutexLock(remoteDeviceInfosMutex_);
482 #endif
483 for (auto iter: remoteDeviceInfos_) {
484 if (iter.second.deviceId == info.deviceId) {
485 if (memcpy_s(iter.second.deviceName, sizeof(iter.second.deviceName), info.deviceName,
486 sizeof(info.deviceName)) != DM_OK) {
487 LOGE("ChangeDeviceInfo copy deviceName failed");
488 }
489 if (memcpy_s(iter.second.networkId, sizeof(iter.second.networkId), info.networkId,
490 sizeof(info.networkId)) != DM_OK) {
491 LOGE("ChangeDeviceInfo copy networkId failed");
492 }
493 iter.second.deviceTypeId = info.deviceTypeId;
494 LOGI("ChangeDeviceInfo complete");
495 break;
496 }
497 }
498 }
499 } // namespace DistributedHardware
500 } // namespace OHOS