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