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 #undef LOG_TAG
35 #define LOG_TAG "DeviceManager"
36
37 namespace OHOS {
38 namespace Msdp {
39 namespace DeviceStatus {
40 namespace {
41 constexpr size_t EXPECTED_N_SUBMATCHES { 2 };
42 constexpr size_t EXPECTED_SUBMATCH { 1 };
43 } // namespace
44
HotplugHandler(DeviceManager & devMgr)45 DeviceManager::HotplugHandler::HotplugHandler(DeviceManager &devMgr)
46 : devMgr_(devMgr)
47 {}
48
AddDevice(const std::string & devNode)49 void DeviceManager::HotplugHandler::AddDevice(const std::string &devNode)
50 {
51 devMgr_.AddDevice(devNode);
52 }
53
RemoveDevice(const std::string & devNode)54 void DeviceManager::HotplugHandler::RemoveDevice(const std::string &devNode)
55 {
56 devMgr_.RemoveDevice(devNode);
57 }
58
DeviceManager()59 DeviceManager::DeviceManager()
60 : hotplug_(*this)
61 {}
62
Init(IContext * context)63 int32_t DeviceManager::Init(IContext *context)
64 {
65 CALL_INFO_TRACE;
66 CHKPR(context, RET_ERR);
67 int32_t ret = context->GetDelegateTasks().PostSyncTask(
68 std::bind(&DeviceManager::OnInit, this, context));
69 if (ret != RET_OK) {
70 FI_HILOGE("Post sync task failed");
71 }
72 return ret;
73 }
74
OnInit(IContext * context)75 int32_t DeviceManager::OnInit(IContext *context)
76 {
77 CALL_INFO_TRACE;
78 CHKPR(context, RET_ERR);
79 context_ = context;
80 monitor_.SetDeviceMgr(&hotplug_);
81 enumerator_.SetDeviceMgr(&hotplug_);
82 return RET_OK;
83 }
84
Enable()85 int32_t DeviceManager::Enable()
86 {
87 CALL_INFO_TRACE;
88 CHKPR(context_, RET_ERR);
89 int32_t ret = context_->GetDelegateTasks().PostSyncTask(
90 std::bind(&DeviceManager::OnEnable, this));
91 if (ret != RET_OK) {
92 FI_HILOGE("Post sync task failed");
93 }
94 return ret;
95 }
96
OnEnable()97 int32_t DeviceManager::OnEnable()
98 {
99 CALL_DEBUG_ENTER;
100 epollMgr_ = std::make_shared<EpollManager>();
101 int32_t ret = epollMgr_->Open();
102 if (ret != RET_OK) {
103 return ret;
104 }
105 ret = monitor_.Enable();
106 if (ret != RET_OK) {
107 goto CLOSE_EPOLL;
108 }
109 ret = epollMgr_->Add(monitor_);
110 if (ret != RET_OK) {
111 goto DISABLE_MONITOR;
112 }
113 enumerator_.ScanDevices();
114 return RET_OK;
115
116 DISABLE_MONITOR:
117 monitor_.Disable();
118
119 CLOSE_EPOLL:
120 epollMgr_.reset();
121 return ret;
122 }
123
Disable()124 int32_t DeviceManager::Disable()
125 {
126 CALL_INFO_TRACE;
127 CHKPR(context_, RET_ERR);
128 int32_t ret = context_->GetDelegateTasks().PostSyncTask(
129 std::bind(&DeviceManager::OnDisable, this));
130 if (ret != RET_OK) {
131 FI_HILOGE("PostSyncTask failed");
132 }
133 return ret;
134 }
135
OnDisable()136 int32_t DeviceManager::OnDisable()
137 {
138 CHKPR(epollMgr_, RET_ERR);
139 epollMgr_->Remove(monitor_);
140 monitor_.Disable();
141 epollMgr_.reset();
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_DEBUG_ENTER;
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_DEBUG_ENTER;
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_HILOGD("Add device %{public}d:%{public}s", dev->GetId(), dev->GetDevPath().c_str());
242 FI_HILOGD(" sysPath: \"%{public}s\"", dev->GetSysPath().c_str());
243 FI_HILOGD(" bus: %{public}04x", dev->GetBus());
244 FI_HILOGD(" vendor: %{public}04x", dev->GetVendor());
245 FI_HILOGD(" product: %{public}04x", dev->GetProduct());
246 FI_HILOGD(" version: %{public}04x", dev->GetVersion());
247 FI_HILOGD(" name: \"%{public}s\"", dev->GetName().c_str());
248 FI_HILOGD(" location: \"%{public}s\"", dev->GetPhys().c_str());
249 FI_HILOGD(" unique id: \"%{public}s\"", dev->GetUniq().c_str());
250 FI_HILOGD(" is pointer: %{public}s, is keyboard:%{public}s",
251 dev->IsPointerDevice() ? "True" : "False", dev->IsKeyboard() ? "True" : "False");
252
253 for (const 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 (const auto &observer : observers_) {
263 std::shared_ptr<IDeviceObserver> ptr = observer.lock();
264 CHKPC(ptr);
265 ptr->OnDeviceRemoved(dev);
266 }
267 }
268
Dispatch(const struct epoll_event & ev)269 void DeviceManager::Dispatch(const struct epoll_event &ev)
270 {
271 CALL_DEBUG_ENTER;
272 CHKPV(context_);
273 int32_t ret = context_->GetDelegateTasks().PostAsyncTask(
274 std::bind(&DeviceManager::OnEpollDispatch, this, ev.events));
275 if (ret != RET_OK) {
276 FI_HILOGE("PostAsyncTask failed");
277 }
278 }
279
OnEpollDispatch(uint32_t events)280 int32_t DeviceManager::OnEpollDispatch(uint32_t events)
281 {
282 struct epoll_event ev {};
283 ev.events = events;
284 ev.data.ptr = epollMgr_.get();
285
286 CHKPR(epollMgr_, RET_ERR);
287 epollMgr_->Dispatch(ev);
288 return RET_OK;
289 }
290
GetDevice(int32_t id) const291 std::shared_ptr<IDevice> DeviceManager::GetDevice(int32_t id) const
292 {
293 CHKPP(context_);
294 std::packaged_task<std::shared_ptr<IDevice>(int32_t)> task {
295 std::bind(&DeviceManager::OnGetDevice, this, std::placeholders::_1) };
296 auto fu = task.get_future();
297
298 int32_t ret = context_->GetDelegateTasks().PostSyncTask(
299 std::bind(&DeviceManager::RunGetDevice, this, std::ref(task), id));
300 if (ret != RET_OK) {
301 FI_HILOGE("Post task failed");
302 return nullptr;
303 }
304 return fu.get();
305 }
306
OnGetDevice(int32_t id) const307 std::shared_ptr<IDevice> DeviceManager::OnGetDevice(int32_t id) const
308 {
309 if (auto devIter = devices_.find(id); devIter != devices_.cend()) {
310 return devIter->second;
311 }
312 FI_HILOGE("Device id not found");
313 return nullptr;
314 }
315
RunGetDevice(std::packaged_task<std::shared_ptr<IDevice> (int32_t)> & task,int32_t id) const316 int32_t DeviceManager::RunGetDevice(std::packaged_task<std::shared_ptr<IDevice>(int32_t)> &task,
317 int32_t id) const
318 {
319 task(id);
320 return RET_OK;
321 }
322
RetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)323 void DeviceManager::RetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)
324 {
325 CALL_INFO_TRACE;
326 CHKPV(context_);
327 int32_t ret = context_->GetDelegateTasks().PostSyncTask(
328 std::bind(&DeviceManager::OnRetriggerHotplug, this, observer));
329 if (ret != RET_OK) {
330 FI_HILOGE("Post task failed");
331 }
332 }
333
OnRetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)334 int32_t DeviceManager::OnRetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)
335 {
336 CALL_INFO_TRACE;
337 CHKPR(observer, RET_ERR);
338 std::shared_ptr<IDeviceObserver> ptr = observer.lock();
339 CHKPR(ptr, RET_ERR);
340 std::for_each(devices_.cbegin(), devices_.cend(),
341 [ptr] (const auto &item) {
342 if (item.second != nullptr) {
343 ptr->OnDeviceAdded(item.second);
344 }
345 });
346 return RET_OK;
347 }
348
AddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)349 int32_t DeviceManager::AddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
350 {
351 CALL_DEBUG_ENTER;
352 CHKPR(context_, RET_ERR);
353 int32_t ret = context_->GetDelegateTasks().PostSyncTask(
354 std::bind(&DeviceManager::OnAddDeviceObserver, this, observer));
355 if (ret != RET_OK) {
356 FI_HILOGE("Post task failed");
357 }
358 return ret;
359 }
360
OnAddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)361 int32_t DeviceManager::OnAddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
362 {
363 CALL_INFO_TRACE;
364 CHKPR(observer, RET_ERR);
365 auto ret = observers_.insert(observer);
366 if (!ret.second) {
367 FI_HILOGW("Observer is duplicated");
368 }
369 return RET_OK;
370 }
371
RemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)372 void DeviceManager::RemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
373 {
374 CALL_INFO_TRACE;
375 CHKPV(context_);
376 int32_t ret = context_->GetDelegateTasks().PostSyncTask(
377 std::bind(&DeviceManager::OnRemoveDeviceObserver, this, observer));
378 if (ret != RET_OK) {
379 FI_HILOGE("Post task failed");
380 }
381 }
382
OnRemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)383 int32_t DeviceManager::OnRemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
384 {
385 CALL_INFO_TRACE;
386 CHKPR(observer, RET_ERR);
387 observers_.erase(observer);
388 return RET_OK;
389 }
390
AnyOf(std::function<bool (std::shared_ptr<IDevice>)> pred)391 bool DeviceManager::AnyOf(std::function<bool(std::shared_ptr<IDevice>)> pred)
392 {
393 return std::any_of(devices_.cbegin(), devices_.cend(), [pred](const auto &item) {
394 return (pred != nullptr ? pred(item.second) : false);
395 });
396 }
397 } // namespace DeviceStatus
398 } // namespace Msdp
399 } // namespace OHOS