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 #if !(defined(__LITEOS_M__) || defined(LITE_DEVICE))
26 #include "deviceprofile_connector.h"
27 #endif
28
29 namespace OHOS {
30 namespace DistributedHardware {
31 const uint32_t DM_EVENT_QUEUE_CAPACITY = 20;
32 const uint32_t DM_EVENT_WAIT_TIMEOUT = 2;
33 constexpr const char* THREAD_LOOP = "ThreadLoop";
DmDeviceStateManager(std::shared_ptr<SoftbusConnector> softbusConnector,std::shared_ptr<IDeviceManagerServiceListener> listener,std::shared_ptr<HiChainConnector> hiChainConnector,std::shared_ptr<HiChainAuthConnector> hiChainAuthConnector)34 DmDeviceStateManager::DmDeviceStateManager(std::shared_ptr<SoftbusConnector> softbusConnector,
35 std::shared_ptr<IDeviceManagerServiceListener> listener, std::shared_ptr<HiChainConnector> hiChainConnector,
36 std::shared_ptr<HiChainAuthConnector> hiChainAuthConnector)
37 : softbusConnector_(softbusConnector), listener_(listener), hiChainConnector_(hiChainConnector),
38 hiChainAuthConnector_(hiChainAuthConnector)
39 {
40 decisionSoName_ = "libdevicemanagerext_decision.z.so";
41 StartEventThread();
42 LOGI("DmDeviceStateManager constructor");
43 }
44
~DmDeviceStateManager()45 DmDeviceStateManager::~DmDeviceStateManager()
46 {
47 LOGI("DmDeviceStateManager destructor");
48 softbusConnector_->UnRegisterSoftbusStateCallback();
49 StopEventThread();
50 }
51
RegisterSoftbusStateCallback()52 int32_t DmDeviceStateManager::RegisterSoftbusStateCallback()
53 {
54 if (softbusConnector_ != nullptr) {
55 return softbusConnector_->RegisterSoftbusStateCallback(shared_from_this());
56 }
57 return DM_OK;
58 }
59
SaveOnlineDeviceInfo(const DmDeviceInfo & info)60 void DmDeviceStateManager::SaveOnlineDeviceInfo(const DmDeviceInfo &info)
61 {
62 LOGI("SaveOnlineDeviceInfo begin, deviceId = %s", GetAnonyString(std::string(info.deviceId)).c_str());
63 std::string udid;
64 if (SoftbusConnector::GetUdidByNetworkId(info.networkId, udid) == DM_OK) {
65 std::string uuid;
66 DmDeviceInfo saveInfo = info;
67 SoftbusConnector::GetUuidByNetworkId(info.networkId, uuid);
68 {
69 std::lock_guard<std::mutex> mutexLock(remoteDeviceInfosMutex_);
70 remoteDeviceInfos_[uuid] = saveInfo;
71 stateDeviceInfos_[udid] = saveInfo;
72 }
73 LOGI("SaveOnlineDeviceInfo complete, networkId = %s, udid = %s, uuid = %s",
74 GetAnonyString(std::string(info.networkId)).c_str(),
75 GetAnonyString(udid).c_str(), GetAnonyString(uuid).c_str());
76 }
77 }
78
DeleteOfflineDeviceInfo(const DmDeviceInfo & info)79 void DmDeviceStateManager::DeleteOfflineDeviceInfo(const DmDeviceInfo &info)
80 {
81 LOGI("DeleteOfflineDeviceInfo begin, deviceId = %s", GetAnonyString(std::string(info.deviceId)).c_str());
82 std::lock_guard<std::mutex> mutexLock(remoteDeviceInfosMutex_);
83 std::string deviceId = std::string(info.deviceId);
84 for (auto iter: remoteDeviceInfos_) {
85 if (std::string(iter.second.deviceId) == deviceId) {
86 remoteDeviceInfos_.erase(iter.first);
87 LOGI("Delete remoteDeviceInfos complete");
88 break;
89 }
90 }
91 for (auto iter: stateDeviceInfos_) {
92 if (std::string(iter.second.deviceId) == deviceId) {
93 stateDeviceInfos_.erase(iter.first);
94 LOGI("Delete stateDeviceInfos complete");
95 break;
96 }
97 }
98 }
99
OnDeviceOnline(std::string deviceId)100 void DmDeviceStateManager::OnDeviceOnline(std::string deviceId)
101 {
102 LOGI("DmDeviceStateManager::OnDeviceOnline, deviceId = %s", GetAnonyString(deviceId).c_str());
103 DmDeviceInfo devInfo = softbusConnector_->GetDeviceInfoByDeviceId(deviceId);
104 {
105 std::lock_guard<std::mutex> mutexLock(remoteDeviceInfosMutex_);
106 stateDeviceInfos_[deviceId] = devInfo;
107 }
108 std::vector<std::string> pkgName = softbusConnector_->GetPkgName();
109 if (pkgName.size() == 0) {
110 listener_->OnDeviceStateChange(std::string(DM_PKG_NAME), DEVICE_STATE_ONLINE, devInfo);
111 } else {
112 for (auto item : pkgName) {
113 listener_->OnDeviceStateChange(item, DEVICE_STATE_ONLINE, devInfo);
114 }
115 }
116 softbusConnector_->ClearPkgName();
117 }
118
OnDeviceOffline(std::string deviceId)119 void DmDeviceStateManager::OnDeviceOffline(std::string deviceId)
120 {
121 LOGI("DmDeviceStateManager::OnDeviceOffline, deviceId = %s", GetAnonyString(deviceId).c_str());
122 {
123 std::lock_guard<std::mutex> mutexLock(remoteDeviceInfosMutex_);
124 if (stateDeviceInfos_.find(deviceId) == stateDeviceInfos_.end()) {
125 LOGE("DmDeviceStateManager::OnDeviceOnline not find deviceId");
126 return;
127 }
128 }
129 DmDeviceInfo devInfo = stateDeviceInfos_[deviceId];
130 std::vector<std::string> pkgName = softbusConnector_->GetPkgName();
131 if (pkgName.size() == 0) {
132 listener_->OnDeviceStateChange(std::string(DM_PKG_NAME), DEVICE_STATE_OFFLINE, devInfo);
133 } else {
134 for (auto item : pkgName) {
135 listener_->OnDeviceStateChange(item, DEVICE_STATE_OFFLINE, devInfo);
136 }
137 }
138 softbusConnector_->ClearPkgName();
139 }
140
HandleDeviceStatusChange(DmDeviceState devState,DmDeviceInfo & devInfo)141 void DmDeviceStateManager::HandleDeviceStatusChange(DmDeviceState devState, DmDeviceInfo &devInfo)
142 {
143 LOGI("Handle device status change: devState=%d, deviceId=%s.", devState, GetAnonyString(devInfo.deviceId).c_str());
144 switch (devState) {
145 case DEVICE_STATE_ONLINE:
146 RegisterOffLineTimer(devInfo);
147 SaveOnlineDeviceInfo(devInfo);
148 devInfo.authForm = GetAuthForm(devInfo.networkId);
149 DmDistributedHardwareLoad::GetInstance().LoadDistributedHardwareFwk();
150 break;
151 case DEVICE_STATE_OFFLINE:
152 StartOffLineTimer(devInfo);
153 DeleteOfflineDeviceInfo(devInfo);
154 if (softbusConnector_ != nullptr) {
155 std::string udid;
156 softbusConnector_->GetUdidByNetworkId(devInfo.networkId, udid);
157 softbusConnector_->EraseUdidFromMap(udid);
158 }
159 break;
160 case DEVICE_INFO_CHANGED:
161 ChangeDeviceInfo(devInfo);
162 break;
163 default:
164 LOGE("HandleDeviceStatusChange error, unknown device state = %d", devState);
165 break;
166 }
167 if (listener_ == nullptr) {
168 LOGE("HandleDeviceStatusChange failed, device manager client listener is null.");
169 return;
170 }
171 if (softbusConnector_ != nullptr) {
172 std::vector<std::string> pkgName = softbusConnector_->GetPkgName();
173 if (pkgName.size() == 0) {
174 listener_->OnDeviceStateChange(std::string(DM_PKG_NAME), devState, devInfo);
175 } else {
176 for (auto item : pkgName) {
177 listener_->OnDeviceStateChange(item, devState, devInfo);
178 }
179 }
180 softbusConnector_->ClearPkgName();
181 }
182 }
183
OnDbReady(const std::string & pkgName,const std::string & uuid)184 void DmDeviceStateManager::OnDbReady(const std::string &pkgName, const std::string &uuid)
185 {
186 LOGI("OnDbReady function is called with pkgName: %s and uuid = %s",
187 pkgName.c_str(), GetAnonyString(uuid).c_str());
188 if (pkgName.empty() || uuid.empty()) {
189 LOGE("On db ready pkgName is empty or uuid is empty");
190 return;
191 }
192 DmDeviceInfo saveInfo;
193 {
194 std::lock_guard<std::mutex> mutexLock(remoteDeviceInfosMutex_);
195 auto iter = remoteDeviceInfos_.find(uuid);
196 if (iter == remoteDeviceInfos_.end()) {
197 LOGE("OnDbReady complete not find uuid: %s", GetAnonyString(uuid).c_str());
198 return;
199 }
200 saveInfo = iter->second;
201 }
202 if (listener_ != nullptr) {
203 DmDeviceState state = DEVICE_INFO_READY;
204 listener_->OnDeviceStateChange(pkgName, state, saveInfo);
205 }
206 }
207
RegisterOffLineTimer(const DmDeviceInfo & deviceInfo)208 void DmDeviceStateManager::RegisterOffLineTimer(const DmDeviceInfo &deviceInfo)
209 {
210 std::string deviceUdid;
211 int32_t ret = softbusConnector_->GetUdidByNetworkId(deviceInfo.networkId, deviceUdid);
212 if (ret != DM_OK) {
213 LOGE("fail to get udid by networkId");
214 return;
215 }
216 LOGI("Register offline timer for deviceUdid: %s", GetAnonyString(deviceUdid).c_str());
217 std::lock_guard<std::mutex> mutexLock(timerMapMutex_);
218 for (auto &iter : stateTimerInfoMap_) {
219 if ((iter.first == deviceUdid) && (timer_ != nullptr)) {
220 timer_->DeleteTimer(iter.second.timerName);
221 stateTimerInfoMap_.erase(iter.first);
222 break;
223 }
224 }
225 if (stateTimerInfoMap_.find(deviceUdid) == stateTimerInfoMap_.end()) {
226 std::string timerName = std::string(STATE_TIMER_PREFIX) + GetAnonyString(deviceUdid);
227 StateTimerInfo stateTimer = {
228 .timerName = timerName,
229 .networkId = deviceInfo.networkId,
230 .isStart = false,
231 };
232 stateTimerInfoMap_[deviceUdid] = stateTimer;
233 }
234 }
235
StartOffLineTimer(const DmDeviceInfo & deviceInfo)236 void DmDeviceStateManager::StartOffLineTimer(const DmDeviceInfo &deviceInfo)
237 {
238 std::lock_guard<std::mutex> mutexLock(timerMapMutex_);
239 std::string networkId = deviceInfo.networkId;
240 LOGI("Start offline timer for networkId: %s", GetAnonyString(networkId).c_str());
241 if (timer_ == nullptr) {
242 timer_ = std::make_shared<DmTimer>();
243 }
244 for (auto &iter : stateTimerInfoMap_) {
245 if ((iter.second.networkId == networkId) && !iter.second.isStart) {
246 timer_->StartTimer(iter.second.timerName, OFFLINE_TIMEOUT,
247 [this] (std::string name) {
248 DmDeviceStateManager::DeleteTimeOutGroup(name);
249 });
250 iter.second.isStart = true;
251 }
252 }
253 }
254
DeleteTimeOutGroup(std::string name)255 void DmDeviceStateManager::DeleteTimeOutGroup(std::string name)
256 {
257 std::lock_guard<std::mutex> mutexLock(timerMapMutex_);
258 for (auto iter = stateTimerInfoMap_.begin(); iter != stateTimerInfoMap_.end(); iter++) {
259 if (((iter->second).timerName == name) && (hiChainConnector_ != nullptr)) {
260 LOGI("remove hichain group with deviceId: %s", GetAnonyString(iter->first).c_str());
261 hiChainConnector_->DeleteTimeOutGroup((iter->first).c_str());
262 #if !(defined(__LITEOS_M__) || defined(LITE_DEVICE))
263 uint32_t res = DeviceProfileConnector::GetInstance().DeleteTimeOutAcl(iter->first);
264 if (res == 0) {
265 hiChainAuthConnector_->DeleteCredential(iter->first,
266 MultipleUserConnector::GetCurrentAccountUserID());
267 }
268 #endif
269 stateTimerInfoMap_.erase(iter);
270 break;
271 }
272 }
273 }
274
StartEventThread()275 void DmDeviceStateManager::StartEventThread()
276 {
277 LOGI("StartEventThread begin");
278 eventTask_.threadRunning_ = true;
279 eventTask_.queueThread_ = std::thread(&DmDeviceStateManager::ThreadLoop, this);
280 LOGI("StartEventThread complete");
281 }
282
StopEventThread()283 void DmDeviceStateManager::StopEventThread()
284 {
285 LOGI("StopEventThread begin");
286 eventTask_.threadRunning_ = false;
287 eventTask_.queueCond_.notify_all();
288 eventTask_.queueFullCond_.notify_all();
289 if (eventTask_.queueThread_.joinable()) {
290 eventTask_.queueThread_.join();
291 }
292 LOGI("StopEventThread complete");
293 }
294
AddTask(const std::shared_ptr<NotifyEvent> & task)295 int32_t DmDeviceStateManager::AddTask(const std::shared_ptr<NotifyEvent> &task)
296 {
297 LOGI("AddTask begin, eventId: %d", task->GetEventId());
298 {
299 std::unique_lock<std::mutex> lock(eventTask_.queueMtx_);
300 while (eventTask_.queue_.size() >= DM_EVENT_QUEUE_CAPACITY) {
301 eventTask_.queueFullCond_.wait_for(lock, std::chrono::seconds(DM_EVENT_WAIT_TIMEOUT));
302 }
303 eventTask_.queue_.push(task);
304 }
305 eventTask_.queueCond_.notify_one();
306 LOGI("AddTask complete");
307 return DM_OK;
308 }
309
ThreadLoop()310 void DmDeviceStateManager::ThreadLoop()
311 {
312 LOGI("ThreadLoop begin");
313 int32_t ret = pthread_setname_np(pthread_self(), THREAD_LOOP);
314 if (ret != DM_OK) {
315 LOGE("ThreadLoop setname failed.");
316 }
317 while (eventTask_.threadRunning_) {
318 std::shared_ptr<NotifyEvent> task = nullptr;
319 {
320 std::unique_lock<std::mutex> lock(eventTask_.queueMtx_);
321 while (eventTask_.queue_.empty() && eventTask_.threadRunning_) {
322 eventTask_.queueCond_.wait_for(lock, std::chrono::seconds(DM_EVENT_WAIT_TIMEOUT));
323 }
324 if (!eventTask_.queue_.empty()) {
325 task = eventTask_.queue_.front();
326 eventTask_.queue_.pop();
327 eventTask_.queueFullCond_.notify_one();
328 }
329 }
330 if (task != nullptr) {
331 RunTask(task);
332 }
333 }
334 LOGI("ThreadLoop end");
335 }
336
RunTask(const std::shared_ptr<NotifyEvent> & task)337 void DmDeviceStateManager::RunTask(const std::shared_ptr<NotifyEvent> &task)
338 {
339 LOGI("RunTask begin, eventId: %d", task->GetEventId());
340 if (task->GetEventId() == DM_NOTIFY_EVENT_ONDEVICEREADY) {
341 OnDbReady(std::string(DM_PKG_NAME), task->GetDeviceId());
342 }
343 LOGI("RunTask complete");
344 }
345
GetAuthForm(const std::string & networkId)346 DmAuthForm DmDeviceStateManager::GetAuthForm(const std::string &networkId)
347 {
348 LOGI("GetAuthForm start");
349 if (hiChainConnector_ == nullptr) {
350 LOGE("hiChainConnector_ is nullptr");
351 return DmAuthForm::INVALID_TYPE;
352 }
353
354 if (networkId.empty()) {
355 LOGE("networkId is empty");
356 return DmAuthForm::INVALID_TYPE;
357 }
358
359 std::string udid;
360 if (SoftbusConnector::GetUdidByNetworkId(networkId.c_str(), udid) == DM_OK) {
361 return hiChainConnector_->GetGroupType(udid);
362 }
363
364 return DmAuthForm::INVALID_TYPE;
365 }
366
ProcNotifyEvent(const int32_t eventId,const std::string & deviceId)367 int32_t DmDeviceStateManager::ProcNotifyEvent(const int32_t eventId, const std::string &deviceId)
368 {
369 LOGI("ProcNotifyEvent in, eventId: %d", eventId);
370 return AddTask(std::make_shared<NotifyEvent>(eventId, deviceId));
371 }
372
ChangeDeviceInfo(const DmDeviceInfo & info)373 void DmDeviceStateManager::ChangeDeviceInfo(const DmDeviceInfo &info)
374 {
375 std::lock_guard<std::mutex> mutexLock(remoteDeviceInfosMutex_);
376 for (auto iter: remoteDeviceInfos_) {
377 if (iter.second.deviceId == info.deviceId) {
378 if (memcpy_s(iter.second.deviceName, sizeof(iter.second.deviceName), info.deviceName,
379 sizeof(info.deviceName)) != DM_OK) {
380 LOGE("ChangeDeviceInfo copy deviceName failed");
381 }
382 if (memcpy_s(iter.second.networkId, sizeof(iter.second.networkId), info.networkId,
383 sizeof(info.networkId)) != DM_OK) {
384 LOGE("ChangeDeviceInfo copy networkId failed");
385 }
386 iter.second.deviceTypeId = info.deviceTypeId;
387 LOGI("ChangeDeviceInfo complete");
388 break;
389 }
390 }
391 }
392 } // namespace DistributedHardware
393 } // namespace OHOS