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