• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "device_manager.h"
17 
18 #include <algorithm>
19 #include <cstring>
20 #include <regex>
21 #include <unistd.h>
22 
23 #include <sys/epoll.h>
24 #include <sys/stat.h>
25 
26 #ifdef OHOS_BUILD_ENABLE_COORDINATION
27 #include "coordination_util.h"
28 #endif // OHOS_BUILD_ENABLE_COORDINATION
29 #include "device.h"
30 #include "devicestatus_define.h"
31 #include "fi_log.h"
32 #include "napi_constants.h"
33 
34 namespace OHOS {
35 namespace Msdp {
36 namespace DeviceStatus {
37 namespace {
38 constexpr OHOS::HiviewDFX::HiLogLabel LABEL { LOG_CORE, MSDP_DOMAIN_ID, "DeviceManager" };
39 constexpr int32_t MAX_N_EVENTS { 64 };
40 constexpr size_t EXPECTED_N_SUBMATCHES { 2 };
41 constexpr size_t EXPECTED_SUBMATCH { 1 };
42 } // namespace
43 
HotplugHandler(DeviceManager & devMgr)44 DeviceManager::HotplugHandler::HotplugHandler(DeviceManager &devMgr)
45     : devMgr_(devMgr)
46 {}
47 
AddDevice(const std::string & devNode)48 void DeviceManager::HotplugHandler::AddDevice(const std::string &devNode)
49 {
50     devMgr_.AddDevice(devNode);
51 }
52 
RemoveDevice(const std::string & devNode)53 void DeviceManager::HotplugHandler::RemoveDevice(const std::string &devNode)
54 {
55     devMgr_.RemoveDevice(devNode);
56 }
57 
DeviceManager()58 DeviceManager::DeviceManager()
59     : hotplug_(*this)
60 {}
61 
Init(IContext * context)62 int32_t DeviceManager::Init(IContext *context)
63 {
64     CALL_INFO_TRACE;
65     CHKPR(context, RET_ERR);
66     int32_t ret = context->GetDelegateTasks().PostSyncTask(
67         std::bind(&DeviceManager::OnInit, this, context));
68     if (ret != RET_OK) {
69         FI_HILOGE("Post sync task failed");
70     }
71     return ret;
72 }
73 
OnInit(IContext * context)74 int32_t DeviceManager::OnInit(IContext *context)
75 {
76     CALL_INFO_TRACE;
77     CHKPR(context, RET_ERR);
78     context_ = context;
79     monitor_.SetDeviceMgr(&hotplug_);
80     enumerator_.SetDeviceMgr(&hotplug_);
81     return RET_OK;
82 }
83 
Enable()84 int32_t DeviceManager::Enable()
85 {
86     CALL_INFO_TRACE;
87     CHKPR(context_, RET_ERR);
88     int32_t ret = context_->GetDelegateTasks().PostSyncTask(
89         std::bind(&DeviceManager::OnEnable, this));
90     if (ret != RET_OK) {
91         FI_HILOGE("Post sync task failed");
92     }
93     return ret;
94 }
95 
OnEnable()96 int32_t DeviceManager::OnEnable()
97 {
98     CALL_DEBUG_ENTER;
99     int32_t ret = EpollCreate();
100     if (ret != RET_OK) {
101         FI_HILOGE("EpollCreate failed");
102         return ret;
103     }
104     ret = monitor_.Enable();
105     if (ret != RET_OK) {
106         FI_HILOGE("Failed to enable monitor");
107         goto CLOSE_EPOLL;
108     }
109     ret = EpollAdd(&monitor_);
110     if (ret != RET_OK) {
111         FI_HILOGE("EpollAdd failed");
112         goto DISABLE_MONITOR;
113     }
114     enumerator_.ScanDevices();
115     return RET_OK;
116 
117 DISABLE_MONITOR:
118     monitor_.Disable();
119 
120 CLOSE_EPOLL:
121     EpollClose();
122     return ret;
123 }
124 
Disable()125 int32_t DeviceManager::Disable()
126 {
127     CALL_INFO_TRACE;
128     CHKPR(context_, RET_ERR);
129     int32_t ret = context_->GetDelegateTasks().PostSyncTask(
130         std::bind(&DeviceManager::OnDisable, this));
131     if (ret != RET_OK) {
132         FI_HILOGE("PostSyncTask failed");
133     }
134     return ret;
135 }
136 
OnDisable()137 int32_t DeviceManager::OnDisable()
138 {
139     EpollDel(&monitor_);
140     monitor_.Disable();
141     EpollClose();
142     return RET_OK;
143 }
144 
FindDevice(const std::string & devPath)145 std::shared_ptr<IDevice> DeviceManager::FindDevice(const std::string &devPath)
146 {
147     auto tIter = std::find_if(devices_.cbegin(), devices_.cend(),
148         [devPath](const auto &item) {
149             return ((item.second != nullptr) && (item.second->GetDevPath() == devPath));
150         });
151     return (tIter != devices_.cend() ? tIter->second : nullptr);
152 }
153 
ParseDeviceId(const std::string & devNode)154 int32_t DeviceManager::ParseDeviceId(const std::string &devNode)
155 {
156     CALL_DEBUG_ENTER;
157     std::regex pattern("^event(\\d+)$");
158     std::smatch mr;
159 
160     if (std::regex_match(devNode, mr, pattern)) {
161         if (mr.ready() && mr.size() == EXPECTED_N_SUBMATCHES) {
162             return std::stoi(mr[EXPECTED_SUBMATCH].str());
163         }
164     }
165     return RET_ERR;
166 }
167 
AddDevice(const std::string & devNode)168 std::shared_ptr<IDevice> DeviceManager::AddDevice(const std::string &devNode)
169 {
170     CALL_INFO_TRACE;
171     const std::string SYS_INPUT_PATH { "/sys/class/input/" };
172     const std::string devPath { DEV_INPUT_PATH + devNode };
173     struct stat statbuf;
174 
175     if (stat(devPath.c_str(), &statbuf) != 0) {
176         FI_HILOGD("Invalid device path:%{public}s", devPath.c_str());
177         return nullptr;
178     }
179     if (!S_ISCHR(statbuf.st_mode)) {
180         FI_HILOGD("Not character device:%{public}s", devPath.c_str());
181         return nullptr;
182     }
183 
184     int32_t deviceId = ParseDeviceId(devNode);
185     if (deviceId < 0) {
186         FI_HILOGE("Parsing device name failed:%{public}s", devNode.c_str());
187         return nullptr;
188     }
189 
190     std::shared_ptr<IDevice> dev = FindDevice(devPath);
191     if (dev != nullptr) {
192         FI_HILOGD("Already exists:%{public}s", devPath.c_str());
193         return dev;
194     }
195 
196     const std::string lSysPath { SYS_INPUT_PATH + devNode };
197     char rpath[PATH_MAX];
198     if (realpath(lSysPath.c_str(), rpath) == nullptr) {
199         FI_HILOGD("Invalid sysPath:%{public}s", lSysPath.c_str());
200         return nullptr;
201     }
202 
203     dev = std::make_shared<Device>(deviceId);
204     dev->SetDevPath(devPath);
205     dev->SetSysPath(std::string(rpath));
206     if (dev->Open() != RET_OK) {
207         FI_HILOGE("Unable to open \'%{public}s\'", devPath.c_str());
208         return nullptr;
209     }
210     auto ret = devices_.insert_or_assign(dev->GetId(), dev);
211     if (ret.second) {
212         FI_HILOGD("\'%{public}s\' added", dev->GetName().c_str());
213         OnDeviceAdded(dev);
214     }
215     return dev;
216 }
217 
RemoveDevice(const std::string & devNode)218 std::shared_ptr<IDevice> DeviceManager::RemoveDevice(const std::string &devNode)
219 {
220     CALL_INFO_TRACE;
221     const std::string devPath { DEV_INPUT_PATH + devNode };
222 
223     for (auto devIter = devices_.begin(); devIter != devices_.end(); ++devIter) {
224         std::shared_ptr<IDevice> dev = devIter->second;
225         CHKPC(dev);
226         if (dev->GetDevPath() == devPath) {
227             devices_.erase(devIter);
228             FI_HILOGD("\'%{public}s\' removed", dev->GetName().c_str());
229             dev->Close();
230             OnDeviceRemoved(dev);
231             return dev;
232         }
233     }
234     FI_HILOGD("\'%{public}s\' was not found", devNode.c_str());
235     return nullptr;
236 }
237 
OnDeviceAdded(std::shared_ptr<IDevice> dev)238 void DeviceManager::OnDeviceAdded(std::shared_ptr<IDevice> dev)
239 {
240     CHKPV(dev);
241     FI_HILOGI("add device %{public}d:%{public}s", dev->GetId(), dev->GetDevPath().c_str());
242     FI_HILOGI("  sysPath:       \"%{public}s\"", dev->GetSysPath().c_str());
243     FI_HILOGI("  bus:           %{public}04x", dev->GetBus());
244     FI_HILOGI("  vendor:        %{public}04x", dev->GetVendor());
245     FI_HILOGI("  product:       %{public}04x", dev->GetProduct());
246     FI_HILOGI("  version:       %{public}04x", dev->GetVersion());
247     FI_HILOGI("  name:          \"%{public}s\"", dev->GetName().c_str());
248     FI_HILOGI("  location:      \"%{public}s\"", dev->GetPhys().c_str());
249     FI_HILOGI("  unique id:     \"%{public}s\"", dev->GetUniq().c_str());
250     FI_HILOGI("  is pointer:    %{public}s", dev->IsPointerDevice() ? "True" : "False");
251     FI_HILOGI("  is keyboard:   %{public}s", dev->IsKeyboard() ? "True" : "False");
252 
253     for (auto observer : observers_) {
254         std::shared_ptr<IDeviceObserver> ptr = observer.lock();
255         CHKPC(ptr);
256         ptr->OnDeviceAdded(dev);
257     }
258 }
259 
OnDeviceRemoved(std::shared_ptr<IDevice> dev)260 void DeviceManager::OnDeviceRemoved(std::shared_ptr<IDevice> dev)
261 {
262     for (auto observer : observers_) {
263         std::shared_ptr<IDeviceObserver> ptr = observer.lock();
264         CHKPC(ptr);
265         ptr->OnDeviceRemoved(dev);
266     }
267 }
268 
EpollCreate()269 int32_t DeviceManager::EpollCreate()
270 {
271     CALL_DEBUG_ENTER;
272     epollFd_ = epoll_create1(EPOLL_CLOEXEC);
273     if (epollFd_ < 0) {
274         FI_HILOGE("epoll_create1 failed");
275         return RET_ERR;
276     }
277     return RET_OK;
278 }
279 
EpollAdd(IEpollEventSource * source)280 int32_t DeviceManager::EpollAdd(IEpollEventSource *source)
281 {
282     CALL_DEBUG_ENTER;
283     CHKPR(source, RET_ERR);
284     struct epoll_event ev {};
285     ev.events = EPOLLIN | EPOLLHUP | EPOLLERR;
286     ev.data.ptr = source;
287     int32_t ret = epoll_ctl(epollFd_, EPOLL_CTL_ADD, source->GetFd(), &ev);
288     if (ret != 0) {
289         FI_HILOGE("epoll_ctl failed:%{public}s", strerror(errno));
290         return RET_ERR;
291     }
292     return RET_OK;
293 }
294 
EpollDel(IEpollEventSource * source)295 void DeviceManager::EpollDel(IEpollEventSource *source)
296 {
297     CALL_DEBUG_ENTER;
298     CHKPV(source);
299     int32_t ret = epoll_ctl(epollFd_, EPOLL_CTL_DEL, source->GetFd(), nullptr);
300     if (ret != 0) {
301         FI_HILOGE("epoll_ctl failed:%{public}s", strerror(errno));
302     }
303 }
304 
EpollClose()305 void DeviceManager::EpollClose()
306 {
307     CALL_DEBUG_ENTER;
308     if (epollFd_ >= 0) {
309         if (close(epollFd_) < 0) {
310             FI_HILOGE("Close epoll fd failed, error:%{public}s, epollFd_:%{public}d", strerror(errno), epollFd_);
311         }
312         epollFd_ = -1;
313     }
314 }
315 
Dispatch(const struct epoll_event & ev)316 void DeviceManager::Dispatch(const struct epoll_event &ev)
317 {
318     CALL_DEBUG_ENTER;
319     if ((ev.events & EPOLLIN) == EPOLLIN) {
320         CHKPV(context_);
321         int32_t ret = context_->GetDelegateTasks().PostAsyncTask(
322             std::bind(&DeviceManager::OnEpollDispatch, this));
323         if (ret != RET_OK) {
324             FI_HILOGE("PostAsyncTask failed");
325         }
326     } else if ((ev.events & (EPOLLHUP | EPOLLERR)) != 0) {
327         FI_HILOGE("Epoll hangup:%{public}s", strerror(errno));
328     }
329 }
330 
OnEpollDispatch()331 int32_t DeviceManager::OnEpollDispatch()
332 {
333     struct epoll_event evs[MAX_N_EVENTS];
334     int32_t cnt = epoll_wait(epollFd_, evs, MAX_N_EVENTS, 0);
335     if (cnt < 0) {
336         FI_HILOGE("epoll_wait failed");
337         return RET_ERR;
338     }
339     for (int32_t index = 0; index < cnt; ++index) {
340         IEpollEventSource *source = reinterpret_cast<IEpollEventSource *>(evs[index].data.ptr);
341         CHKPC(source);
342         if ((evs[index].events & EPOLLIN) == EPOLLIN) {
343             source->Dispatch(evs[index]);
344         } else if ((evs[index].events & (EPOLLHUP | EPOLLERR)) != 0) {
345             FI_HILOGE("Epoll hangup:%{public}s", strerror(errno));
346         }
347     }
348     return RET_OK;
349 }
350 
GetDevice(int32_t id) const351 std::shared_ptr<IDevice> DeviceManager::GetDevice(int32_t id) const
352 {
353     CHKPP(context_);
354     std::packaged_task<std::shared_ptr<IDevice>(int32_t)> task {
355         std::bind(&DeviceManager::OnGetDevice, this, std::placeholders::_1) };
356     auto fu = task.get_future();
357 
358     int32_t ret = context_->GetDelegateTasks().PostSyncTask(
359         std::bind(&DeviceManager::RunGetDevice, this, std::ref(task), id));
360     if (ret != RET_OK) {
361         FI_HILOGE("Post task failed");
362         return nullptr;
363     }
364     return fu.get();
365 }
366 
OnGetDevice(int32_t id) const367 std::shared_ptr<IDevice> DeviceManager::OnGetDevice(int32_t id) const
368 {
369     if (auto devIter = devices_.find(id); devIter != devices_.cend()) {
370         return devIter->second;
371     }
372     FI_HILOGE("Device id not found");
373     return nullptr;
374 }
375 
RunGetDevice(std::packaged_task<std::shared_ptr<IDevice> (int32_t)> & task,int32_t id) const376 int32_t DeviceManager::RunGetDevice(std::packaged_task<std::shared_ptr<IDevice>(int32_t)> &task,
377                                     int32_t id) const
378 {
379     task(id);
380     return RET_OK;
381 }
382 
RetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)383 void DeviceManager::RetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)
384 {
385     CALL_INFO_TRACE;
386     CHKPV(context_);
387     int32_t ret = context_->GetDelegateTasks().PostAsyncTask(
388         std::bind(&DeviceManager::OnRetriggerHotplug, this, observer));
389     if (ret != RET_OK) {
390         FI_HILOGE("Post task failed");
391     }
392 }
393 
OnRetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)394 int32_t DeviceManager::OnRetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)
395 {
396     CALL_INFO_TRACE;
397     CHKPR(observer, RET_ERR);
398     std::shared_ptr<IDeviceObserver> ptr = observer.lock();
399     CHKPR(ptr, RET_ERR);
400     std::for_each(devices_.cbegin(), devices_.cend(),
401         [ptr] (const auto &item) {
402             if (item.second != nullptr) {
403                 ptr->OnDeviceAdded(item.second);
404             }
405         });
406     return RET_OK;
407 }
408 
AddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)409 int32_t DeviceManager::AddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
410 {
411     CALL_INFO_TRACE;
412     CHKPR(context_, RET_ERR);
413     int32_t ret = context_->GetDelegateTasks().PostAsyncTask(
414         std::bind(&DeviceManager::OnAddDeviceObserver, this, observer));
415     if (ret != RET_OK) {
416         FI_HILOGE("Post task failed");
417     }
418     return ret;
419 }
420 
OnAddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)421 int32_t DeviceManager::OnAddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
422 {
423     CALL_INFO_TRACE;
424     CHKPR(observer, RET_ERR);
425     auto ret = observers_.insert(observer);
426     if (!ret.second) {
427         FI_HILOGW("Observer is duplicated");
428     }
429     return RET_OK;
430 }
431 
RemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)432 void DeviceManager::RemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
433 {
434     CALL_INFO_TRACE;
435     CHKPV(context_);
436     int32_t ret = context_->GetDelegateTasks().PostAsyncTask(
437         std::bind(&DeviceManager::OnRemoveDeviceObserver, this, observer));
438     if (ret != RET_OK) {
439         FI_HILOGE("Post task failed");
440     }
441 }
442 
OnRemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)443 int32_t DeviceManager::OnRemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
444 {
445     CALL_INFO_TRACE;
446     CHKPR(observer, RET_ERR);
447     observers_.erase(observer);
448     return RET_OK;
449 }
450 } // namespace DeviceStatus
451 } // namespace Msdp
452 } // namespace OHOS