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 "input_manager.h"
33 #include "napi_constants.h"
34 #include "utility.h"
35
36 #undef LOG_TAG
37 #define LOG_TAG "DeviceManager"
38
39 namespace OHOS {
40 namespace Msdp {
41 namespace DeviceStatus {
42 namespace {
43 constexpr size_t EXPECTED_N_SUBMATCHES { 2 };
44 constexpr size_t EXPECTED_SUBMATCH { 1 };
45 const std::string FINGER_PRINT { "hw_fingerprint_mouse" };
46 const std::string WATCH { "WATCH" };
47 const std::string PENCIL { "Pencil" };
48 const std::string VIRTUAL_TRACK_PAD_NAME { "VirtualTrackpad" };
49 constexpr int32_t INVALID_DEVICE_ID { -1 };
50 } // namespace
51
HotplugHandler(DeviceManager & devMgr)52 DeviceManager::HotplugHandler::HotplugHandler(DeviceManager &devMgr)
53 : devMgr_(devMgr)
54 {}
55
AddDevice(const std::string & devNode)56 void DeviceManager::HotplugHandler::AddDevice(const std::string &devNode)
57 {
58 devMgr_.AddDevice(devNode);
59 }
60
RemoveDevice(const std::string & devNode)61 void DeviceManager::HotplugHandler::RemoveDevice(const std::string &devNode)
62 {
63 devMgr_.RemoveDevice(devNode);
64 }
65
DeviceManager()66 DeviceManager::DeviceManager()
67 : hotplug_(*this)
68 {
69 monitor_ = std::make_shared<Monitor>();
70 }
71
Init(IContext * context)72 int32_t DeviceManager::Init(IContext *context)
73 {
74 CALL_INFO_TRACE;
75 CHKPR(context, RET_ERR);
76 int32_t ret = context->GetDelegateTasks().PostSyncTask([this, context] {
77 return this->OnInit(context);
78 });
79 if (ret != RET_OK) {
80 FI_HILOGE("Post sync task failed");
81 }
82 return ret;
83 }
84
OnInit(IContext * context)85 int32_t DeviceManager::OnInit(IContext *context)
86 {
87 CALL_INFO_TRACE;
88 CHKPR(context, RET_ERR);
89 context_ = context;
90 monitor_->SetDeviceMgr(&hotplug_);
91 enumerator_.SetDeviceMgr(&hotplug_);
92 return RET_OK;
93 }
94
Enable()95 int32_t DeviceManager::Enable()
96 {
97 CALL_INFO_TRACE;
98 CHKPR(context_, RET_ERR);
99 int32_t ret = context_->GetDelegateTasks().PostSyncTask([this] {
100 return this->OnEnable();
101 });
102 if (ret != RET_OK) {
103 FI_HILOGE("Post sync task failed");
104 }
105 return ret;
106 }
107
OnEnable()108 int32_t DeviceManager::OnEnable()
109 {
110 CALL_DEBUG_ENTER;
111 if (!epollMgr_.Open()) {
112 FI_HILOGE("EpollMgr::Open fail");
113 return RET_ERR;
114 }
115 CHKPR(monitor_, RET_ERR);
116 auto ret = monitor_->Enable();
117 if (ret != RET_OK) {
118 goto CLOSE_EPOLL;
119 }
120 if (!epollMgr_.Add(monitor_)) {
121 ret = RET_ERR;
122 goto DISABLE_MONITOR;
123 }
124 enumerator_.ScanDevices();
125 return RET_OK;
126
127 DISABLE_MONITOR:
128 monitor_->Disable();
129
130 CLOSE_EPOLL:
131 epollMgr_.Close();
132 return ret;
133 }
134
Disable()135 int32_t DeviceManager::Disable()
136 {
137 CALL_INFO_TRACE;
138 CHKPR(context_, RET_ERR);
139 int32_t ret = context_->GetDelegateTasks().PostSyncTask([this] {
140 return this->OnDisable();
141 });
142 if (ret != RET_OK) {
143 FI_HILOGE("PostSyncTask failed");
144 }
145 return ret;
146 }
147
OnDisable()148 int32_t DeviceManager::OnDisable()
149 {
150 epollMgr_.Remove(monitor_);
151 monitor_->Disable();
152 epollMgr_.Close();
153 return RET_OK;
154 }
155
FindDevice(const std::string & devPath)156 std::shared_ptr<IDevice> DeviceManager::FindDevice(const std::string &devPath)
157 {
158 auto tIter = std::find_if(devices_.cbegin(), devices_.cend(),
159 [devPath](const auto &item) {
160 return ((item.second != nullptr) && (item.second->GetDevPath() == devPath));
161 });
162 return (tIter != devices_.cend() ? tIter->second : nullptr);
163 }
164
ParseDeviceId(const std::string & devNode)165 int32_t DeviceManager::ParseDeviceId(const std::string &devNode)
166 {
167 CALL_DEBUG_ENTER;
168 std::regex pattern("^event(\\d+)$");
169 std::smatch mr;
170
171 if (std::regex_match(devNode, mr, pattern)) {
172 if (mr.ready() && mr.size() == EXPECTED_N_SUBMATCHES) {
173 return std::stoi(mr[EXPECTED_SUBMATCH].str());
174 }
175 }
176 return RET_ERR;
177 }
178
AddDevice(const std::string & devNode)179 std::shared_ptr<IDevice> DeviceManager::AddDevice(const std::string &devNode)
180 {
181 CALL_INFO_TRACE;
182 const std::string SYS_INPUT_PATH { "/sys/class/input/" };
183 const std::string devPath { DEV_INPUT_PATH + devNode };
184 struct stat statbuf;
185
186 if (stat(devPath.c_str(), &statbuf) != 0) {
187 FI_HILOGE("Invalid device path:%{private}s", devPath.c_str());
188 return nullptr;
189 }
190 if (!S_ISCHR(statbuf.st_mode)) {
191 FI_HILOGE("Not character device:%{public}s", devPath.c_str());
192 return nullptr;
193 }
194
195 int32_t deviceId = ParseDeviceId(devNode);
196 if (deviceId < 0) {
197 FI_HILOGE("Parsing device name failed:%{public}s", devNode.c_str());
198 return nullptr;
199 }
200
201 std::shared_ptr<IDevice> dev = FindDevice(devPath);
202 if (dev != nullptr) {
203 FI_HILOGD("Already exists:%{public}s", devPath.c_str());
204 return dev;
205 }
206
207 const std::string lSysPath { SYS_INPUT_PATH + devNode };
208 char rpath[PATH_MAX];
209 if (realpath(lSysPath.c_str(), rpath) == nullptr) {
210 FI_HILOGE("Invalid sysPath:%{private}s", lSysPath.c_str());
211 return nullptr;
212 }
213
214 dev = std::make_shared<Device>(deviceId);
215 dev->SetDevPath(devPath);
216 dev->SetSysPath(std::string(rpath));
217 if (dev->Open() != RET_OK) {
218 FI_HILOGE("Unable to open \'%{public}s\'", devPath.c_str());
219 return nullptr;
220 }
221 auto ret = devices_.insert_or_assign(dev->GetId(), dev);
222 if (ret.second) {
223 FI_HILOGI("\'%{public}s\' added", dev->GetName().c_str());
224 OnDeviceAdded(dev);
225 }
226 return dev;
227 }
228
IsLocalPointerDevice(std::shared_ptr<MMI::InputDevice> device)229 bool DeviceManager::IsLocalPointerDevice(std::shared_ptr<MMI::InputDevice> device)
230 {
231 CHKPR(device, false);
232 return device->HasCapability(MMI::InputDeviceCapability::INPUT_DEV_CAP_POINTER);
233 }
234
IsVirtualTrackpad(std::shared_ptr<MMI::InputDevice> device)235 bool DeviceManager::IsVirtualTrackpad(std::shared_ptr<MMI::InputDevice> device)
236 {
237 CHKPR(device, false);
238 return device->GetName() == VIRTUAL_TRACK_PAD_NAME;
239 }
240
RemoveDevice(const std::string & devNode)241 std::shared_ptr<IDevice> DeviceManager::RemoveDevice(const std::string &devNode)
242 {
243 CALL_INFO_TRACE;
244 const std::string devPath { DEV_INPUT_PATH + devNode };
245
246 for (auto devIter = devices_.begin(); devIter != devices_.end(); ++devIter) {
247 std::shared_ptr<IDevice> dev = devIter->second;
248 CHKPC(dev);
249 if (dev->GetDevPath() == devPath) {
250 devices_.erase(devIter);
251 FI_HILOGI("\'%{public}s\' removed", dev->GetName().c_str());
252 dev->Close();
253 OnDeviceRemoved(dev);
254 return dev;
255 }
256 }
257 FI_HILOGE("\'%{public}s\' was not found", devNode.c_str());
258 return nullptr;
259 }
260
OnDeviceAdded(std::shared_ptr<IDevice> dev)261 void DeviceManager::OnDeviceAdded(std::shared_ptr<IDevice> dev)
262 {
263 DeviceInfo(dev);
264 for (const auto &observer : observers_) {
265 std::shared_ptr<IDeviceObserver> ptr = observer.lock();
266 CHKPC(ptr);
267 ptr->OnDeviceAdded(dev);
268 }
269 }
270
DeviceInfo(std::shared_ptr<IDevice> dev)271 void DeviceManager::DeviceInfo(std::shared_ptr<IDevice> dev)
272 {
273 CHKPV(dev);
274 FI_HILOGI("Add device %{public}d:%{private}s", dev->GetId(), dev->GetDevPath().c_str());
275 FI_HILOGI(" sysPath: \"%{private}s\"", dev->GetSysPath().c_str());
276 FI_HILOGD(" bus: %{public}04x", dev->GetBus());
277 FI_HILOGI(" vendor: %{public}04x", dev->GetVendor());
278 FI_HILOGD(" product: %{public}04x", dev->GetProduct());
279 FI_HILOGD(" version: %{public}04x", dev->GetVersion());
280 FI_HILOGI(" name: \"%{public}s\"", Utility::Anonymize(dev->GetName()).c_str());
281 FI_HILOGD(" location: \"%{public}s\"", dev->GetPhys().c_str());
282 FI_HILOGD(" unique id: \"%{private}s\"", dev->GetUniq().c_str());
283 FI_HILOGI(" is pointer: %{public}s, is keyboard:%{public}s",
284 dev->IsPointerDevice() ? "True" : "False", dev->IsKeyboard() ? "True" : "False");
285 }
286
OnDeviceRemoved(std::shared_ptr<IDevice> dev)287 void DeviceManager::OnDeviceRemoved(std::shared_ptr<IDevice> dev)
288 {
289 for (const auto &observer : observers_) {
290 std::shared_ptr<IDeviceObserver> ptr = observer.lock();
291 CHKPC(ptr);
292 ptr->OnDeviceRemoved(dev);
293 }
294 }
295
Dispatch(const struct epoll_event & ev)296 void DeviceManager::Dispatch(const struct epoll_event &ev)
297 {
298 CALL_DEBUG_ENTER;
299 CHKPV(context_);
300 int32_t ret = context_->GetDelegateTasks().PostAsyncTask([this, &ev] {
301 return this->OnEpollDispatch(ev.events);
302 });
303 if (ret != RET_OK) {
304 FI_HILOGE("PostAsyncTask failed");
305 }
306 }
307
OnEpollDispatch(uint32_t events)308 int32_t DeviceManager::OnEpollDispatch(uint32_t events)
309 {
310 struct epoll_event ev {};
311 ev.events = events;
312 ev.data.ptr = &epollMgr_;
313
314 epollMgr_.Dispatch(ev);
315 return RET_OK;
316 }
317
GetDevice(int32_t id) const318 std::shared_ptr<IDevice> DeviceManager::GetDevice(int32_t id) const
319 {
320 CHKPP(context_);
321 std::packaged_task<std::shared_ptr<IDevice>(int32_t)> task {[this](int32_t id) {
322 return this->OnGetDevice(id);
323 }};
324 auto fu = task.get_future();
325
326 int32_t ret = context_->GetDelegateTasks().PostSyncTask([this, &task, id] {
327 return this->RunGetDevice(std::ref(task), id);
328 });
329 if (ret != RET_OK) {
330 FI_HILOGE("Post task failed");
331 return nullptr;
332 }
333 return fu.get();
334 }
335
OnGetDevice(int32_t id) const336 std::shared_ptr<IDevice> DeviceManager::OnGetDevice(int32_t id) const
337 {
338 if (auto devIter = devices_.find(id); devIter != devices_.cend()) {
339 return devIter->second;
340 }
341 FI_HILOGE("Device id not found");
342 return nullptr;
343 }
344
RunGetDevice(std::packaged_task<std::shared_ptr<IDevice> (int32_t)> & task,int32_t id) const345 int32_t DeviceManager::RunGetDevice(std::packaged_task<std::shared_ptr<IDevice>(int32_t)> &task,
346 int32_t id) const
347 {
348 task(id);
349 return RET_OK;
350 }
351
RetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)352 void DeviceManager::RetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)
353 {
354 CALL_INFO_TRACE;
355 CHKPV(context_);
356 int32_t ret = context_->GetDelegateTasks().PostSyncTask([this, observer] {
357 return this->OnRetriggerHotplug(observer);
358 });
359 if (ret != RET_OK) {
360 FI_HILOGE("Post task failed");
361 }
362 }
363
OnRetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)364 int32_t DeviceManager::OnRetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)
365 {
366 CALL_INFO_TRACE;
367 CHKPR(observer, RET_ERR);
368 std::shared_ptr<IDeviceObserver> ptr = observer.lock();
369 CHKPR(ptr, RET_ERR);
370 std::for_each(devices_.cbegin(), devices_.cend(),
371 [ptr] (const auto &item) {
372 if (item.second != nullptr) {
373 ptr->OnDeviceAdded(item.second);
374 }
375 });
376 return RET_OK;
377 }
378
AddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)379 int32_t DeviceManager::AddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
380 {
381 CALL_DEBUG_ENTER;
382 CHKPR(context_, RET_ERR);
383 int32_t ret = context_->GetDelegateTasks().PostSyncTask([this, observer] {
384 return this->OnAddDeviceObserver(observer);
385 });
386 if (ret != RET_OK) {
387 FI_HILOGE("Post task failed");
388 }
389 return ret;
390 }
391
OnAddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)392 int32_t DeviceManager::OnAddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
393 {
394 CALL_INFO_TRACE;
395 CHKPR(observer, RET_ERR);
396 auto ret = observers_.insert(observer);
397 if (!ret.second) {
398 FI_HILOGW("Observer is duplicated");
399 }
400 return RET_OK;
401 }
402
RemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)403 void DeviceManager::RemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
404 {
405 CALL_INFO_TRACE;
406 CHKPV(context_);
407 int32_t ret = context_->GetDelegateTasks().PostSyncTask([this, observer] {
408 return this->OnRemoveDeviceObserver(observer);
409 });
410 if (ret != RET_OK) {
411 FI_HILOGE("Post task failed");
412 }
413 }
414
OnRemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)415 int32_t DeviceManager::OnRemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
416 {
417 CALL_INFO_TRACE;
418 CHKPR(observer, RET_ERR);
419 observers_.erase(observer);
420 return RET_OK;
421 }
422
AnyOf(std::function<bool (std::shared_ptr<IDevice>)> pred)423 bool DeviceManager::AnyOf(std::function<bool(std::shared_ptr<IDevice>)> pred)
424 {
425 return std::any_of(devices_.cbegin(), devices_.cend(), [pred](const auto &item) {
426 return (pred != nullptr ? pred(item.second) : false);
427 });
428 }
429
HasLocalPointerDevice()430 bool DeviceManager::HasLocalPointerDevice()
431 {
432 return AnyOf([this](std::shared_ptr<IDevice> dev) {
433 DeviceInfo(dev);
434 if ((dev == nullptr) || IsSpecialPointerDevice(dev)) {
435 return false;
436 }
437 return (dev->IsPointerDevice() && !dev->IsRemote());
438 });
439 }
440
IsSpecialPointerDevice(std::shared_ptr<IDevice> dev)441 bool DeviceManager::IsSpecialPointerDevice(std::shared_ptr<IDevice> dev)
442 {
443 if (dev == nullptr) {
444 return false;
445 }
446 std::string deviceName = dev->GetName();
447 return (deviceName == FINGER_PRINT || deviceName.find(WATCH) != std::string::npos
448 || deviceName.find(PENCIL) != std::string::npos);
449 }
450
HasLocalKeyboardDevice()451 bool DeviceManager::HasLocalKeyboardDevice()
452 {
453 return AnyOf([this](std::shared_ptr<IDevice> dev) {
454 CHKPR(dev, false);
455 return (dev->IsKeyboard() && !dev->IsRemote());
456 });
457 }
458
HasKeyboard()459 bool DeviceManager::HasKeyboard()
460 {
461 return AnyOf([this](std::shared_ptr<IDevice> dev) {
462 if ((dev == nullptr)) {
463 return false;
464 }
465 return (dev->IsKeyboard() && !dev->IsRemote() &&
466 dev->GetKeyboardType() == IDevice::KeyboardType::KEYBOARD_TYPE_ALPHABETICKEYBOARD);
467 });
468 }
469
GetKeyboard()470 std::vector<std::shared_ptr<IDevice>> DeviceManager::GetKeyboard()
471 {
472 std::vector<std::shared_ptr<IDevice>> keyboards;
473 for (const auto &dev : devices_) {
474 if (dev.second->IsKeyboard() && !dev.second->IsRemote() &&
475 dev.second->GetKeyboardType() == IDevice::KeyboardType::KEYBOARD_TYPE_ALPHABETICKEYBOARD) {
476 keyboards.push_back(dev.second);
477 }
478 }
479 return keyboards;
480 }
481
GetPointerDevice()482 std::vector<std::shared_ptr<IDevice>> DeviceManager::GetPointerDevice()
483 {
484 if (!HasLocalPointerDevice()) {
485 return {};
486 }
487 std::vector<std::shared_ptr<IDevice>> pointerDevices;
488 for (const auto &dev : devices_) {
489 if (dev.second->IsPointerDevice() && !dev.second->IsRemote() && dev.second->GetName() != FINGER_PRINT) {
490 pointerDevices.push_back(dev.second);
491 }
492 }
493 return pointerDevices;
494 }
495
GetVirTrackPad()496 std::vector<std::shared_ptr<IDevice>> DeviceManager::GetVirTrackPad()
497 {
498 std::vector<int32_t> deviceIds;
499 std::vector<std::shared_ptr<IDevice>> VirTrackPadDevices;
500 if (MMI::InputManager::GetInstance()->GetDeviceIds(
501 [&deviceIds](std::vector<int32_t> &ids) { deviceIds = ids; }) != RET_OK) {
502 FI_HILOGE("GetDeviceIds failed");
503 return VirTrackPadDevices;
504 }
505 for (int32_t dev : deviceIds) {
506 std::shared_ptr<Device> virDev = std::make_shared<Device>(INVALID_DEVICE_ID);
507 auto ret = MMI::InputManager::GetInstance()->GetDevice(dev,
508 [virDev, &VirTrackPadDevices, dev, this] (
509 std::shared_ptr<MMI::InputDevice> device) {
510 if (this->IsLocalPointerDevice(device) && this->IsVirtualTrackpad(device)) {
511 FI_HILOGI("Has VirtualTrackpad");
512 virDev->SetName(device->GetName().c_str());
513 virDev->SetId(dev);
514 VirTrackPadDevices.push_back(virDev);
515 }
516 });
517 if (ret != RET_OK) {
518 FI_HILOGE("GetDevice failed");
519 }
520 }
521 return VirTrackPadDevices;
522 }
523 } // namespace DeviceStatus
524 } // namespace Msdp
525 } // namespace OHOS