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 size_t EXPECTED_N_SUBMATCHES { 2 };
40 constexpr size_t EXPECTED_SUBMATCH { 1 };
41 } // namespace
42
HotplugHandler(DeviceManager & devMgr)43 DeviceManager::HotplugHandler::HotplugHandler(DeviceManager &devMgr)
44 : devMgr_(devMgr)
45 {}
46
AddDevice(const std::string & devNode)47 void DeviceManager::HotplugHandler::AddDevice(const std::string &devNode)
48 {
49 devMgr_.AddDevice(devNode);
50 }
51
RemoveDevice(const std::string & devNode)52 void DeviceManager::HotplugHandler::RemoveDevice(const std::string &devNode)
53 {
54 devMgr_.RemoveDevice(devNode);
55 }
56
DeviceManager()57 DeviceManager::DeviceManager()
58 : hotplug_(*this)
59 {}
60
Init(IContext * context)61 int32_t DeviceManager::Init(IContext *context)
62 {
63 CALL_INFO_TRACE;
64 CHKPR(context, RET_ERR);
65 int32_t ret = context->GetDelegateTasks().PostSyncTask(
66 std::bind(&DeviceManager::OnInit, this, context));
67 if (ret != RET_OK) {
68 FI_HILOGE("Post sync task failed");
69 }
70 return ret;
71 }
72
OnInit(IContext * context)73 int32_t DeviceManager::OnInit(IContext *context)
74 {
75 CALL_INFO_TRACE;
76 CHKPR(context, RET_ERR);
77 context_ = context;
78 monitor_.SetDeviceMgr(&hotplug_);
79 enumerator_.SetDeviceMgr(&hotplug_);
80 return RET_OK;
81 }
82
Enable()83 int32_t DeviceManager::Enable()
84 {
85 CALL_INFO_TRACE;
86 CHKPR(context_, RET_ERR);
87 int32_t ret = context_->GetDelegateTasks().PostSyncTask(
88 std::bind(&DeviceManager::OnEnable, this));
89 if (ret != RET_OK) {
90 FI_HILOGE("Post sync task failed");
91 }
92 return ret;
93 }
94
OnEnable()95 int32_t DeviceManager::OnEnable()
96 {
97 CALL_DEBUG_ENTER;
98 epollMgr_ = std::make_shared<EpollManager>();
99 int32_t ret = epollMgr_->Open();
100 if (ret != RET_OK) {
101 return ret;
102 }
103 ret = monitor_.Enable();
104 if (ret != RET_OK) {
105 goto CLOSE_EPOLL;
106 }
107 ret = epollMgr_->Add(monitor_);
108 if (ret != RET_OK) {
109 goto DISABLE_MONITOR;
110 }
111 enumerator_.ScanDevices();
112 return RET_OK;
113
114 DISABLE_MONITOR:
115 monitor_.Disable();
116
117 CLOSE_EPOLL:
118 epollMgr_.reset();
119 return ret;
120 }
121
Disable()122 int32_t DeviceManager::Disable()
123 {
124 CALL_INFO_TRACE;
125 CHKPR(context_, RET_ERR);
126 int32_t ret = context_->GetDelegateTasks().PostSyncTask(
127 std::bind(&DeviceManager::OnDisable, this));
128 if (ret != RET_OK) {
129 FI_HILOGE("PostSyncTask failed");
130 }
131 return ret;
132 }
133
OnDisable()134 int32_t DeviceManager::OnDisable()
135 {
136 CHKPR(epollMgr_, RET_ERR);
137 epollMgr_->Remove(monitor_);
138 monitor_.Disable();
139 epollMgr_.reset();
140 return RET_OK;
141 }
142
FindDevice(const std::string & devPath)143 std::shared_ptr<IDevice> DeviceManager::FindDevice(const std::string &devPath)
144 {
145 auto tIter = std::find_if(devices_.cbegin(), devices_.cend(),
146 [devPath](const auto &item) {
147 return ((item.second != nullptr) && (item.second->GetDevPath() == devPath));
148 });
149 return (tIter != devices_.cend() ? tIter->second : nullptr);
150 }
151
ParseDeviceId(const std::string & devNode)152 int32_t DeviceManager::ParseDeviceId(const std::string &devNode)
153 {
154 CALL_DEBUG_ENTER;
155 std::regex pattern("^event(\\d+)$");
156 std::smatch mr;
157
158 if (std::regex_match(devNode, mr, pattern)) {
159 if (mr.ready() && mr.size() == EXPECTED_N_SUBMATCHES) {
160 return std::stoi(mr[EXPECTED_SUBMATCH].str());
161 }
162 }
163 return RET_ERR;
164 }
165
AddDevice(const std::string & devNode)166 std::shared_ptr<IDevice> DeviceManager::AddDevice(const std::string &devNode)
167 {
168 CALL_DEBUG_ENTER;
169 const std::string SYS_INPUT_PATH { "/sys/class/input/" };
170 const std::string devPath { DEV_INPUT_PATH + devNode };
171 struct stat statbuf;
172
173 if (stat(devPath.c_str(), &statbuf) != 0) {
174 FI_HILOGD("Invalid device path:%{public}s", devPath.c_str());
175 return nullptr;
176 }
177 if (!S_ISCHR(statbuf.st_mode)) {
178 FI_HILOGD("Not character device:%{public}s", devPath.c_str());
179 return nullptr;
180 }
181
182 int32_t deviceId = ParseDeviceId(devNode);
183 if (deviceId < 0) {
184 FI_HILOGE("Parsing device name failed:%{public}s", devNode.c_str());
185 return nullptr;
186 }
187
188 std::shared_ptr<IDevice> dev = FindDevice(devPath);
189 if (dev != nullptr) {
190 FI_HILOGD("Already exists:%{public}s", devPath.c_str());
191 return dev;
192 }
193
194 const std::string lSysPath { SYS_INPUT_PATH + devNode };
195 char rpath[PATH_MAX];
196 if (realpath(lSysPath.c_str(), rpath) == nullptr) {
197 FI_HILOGD("Invalid sysPath:%{public}s", lSysPath.c_str());
198 return nullptr;
199 }
200
201 dev = std::make_shared<Device>(deviceId);
202 dev->SetDevPath(devPath);
203 dev->SetSysPath(std::string(rpath));
204 if (dev->Open() != RET_OK) {
205 FI_HILOGE("Unable to open \'%{public}s\'", devPath.c_str());
206 return nullptr;
207 }
208 auto ret = devices_.insert_or_assign(dev->GetId(), dev);
209 if (ret.second) {
210 FI_HILOGD("\'%{public}s\' added", dev->GetName().c_str());
211 OnDeviceAdded(dev);
212 }
213 return dev;
214 }
215
RemoveDevice(const std::string & devNode)216 std::shared_ptr<IDevice> DeviceManager::RemoveDevice(const std::string &devNode)
217 {
218 CALL_INFO_TRACE;
219 const std::string devPath { DEV_INPUT_PATH + devNode };
220
221 for (auto devIter = devices_.begin(); devIter != devices_.end(); ++devIter) {
222 std::shared_ptr<IDevice> dev = devIter->second;
223 CHKPC(dev);
224 if (dev->GetDevPath() == devPath) {
225 devices_.erase(devIter);
226 FI_HILOGD("\'%{public}s\' removed", dev->GetName().c_str());
227 dev->Close();
228 OnDeviceRemoved(dev);
229 return dev;
230 }
231 }
232 FI_HILOGD("\'%{public}s\' was not found", devNode.c_str());
233 return nullptr;
234 }
235
OnDeviceAdded(std::shared_ptr<IDevice> dev)236 void DeviceManager::OnDeviceAdded(std::shared_ptr<IDevice> dev)
237 {
238 CHKPV(dev);
239 FI_HILOGI("Add device %{public}d:%{public}s", dev->GetId(), dev->GetDevPath().c_str());
240 FI_HILOGD(" sysPath: \"%{public}s\"", dev->GetSysPath().c_str());
241 FI_HILOGD(" bus: %{public}04x", dev->GetBus());
242 FI_HILOGD(" vendor: %{public}04x", dev->GetVendor());
243 FI_HILOGD(" product: %{public}04x", dev->GetProduct());
244 FI_HILOGD(" version: %{public}04x", dev->GetVersion());
245 FI_HILOGI(" name: \"%{public}s\"", dev->GetName().c_str());
246 FI_HILOGD(" location: \"%{public}s\"", dev->GetPhys().c_str());
247 FI_HILOGD(" unique id: \"%{public}s\"", dev->GetUniq().c_str());
248 FI_HILOGI(" is pointer: %{public}s, is keyboard:%{public}s",
249 dev->IsPointerDevice() ? "True" : "False", dev->IsKeyboard() ? "True" : "False");
250
251 for (const auto &observer : observers_) {
252 std::shared_ptr<IDeviceObserver> ptr = observer.lock();
253 CHKPC(ptr);
254 ptr->OnDeviceAdded(dev);
255 }
256 }
257
OnDeviceRemoved(std::shared_ptr<IDevice> dev)258 void DeviceManager::OnDeviceRemoved(std::shared_ptr<IDevice> dev)
259 {
260 for (const auto &observer : observers_) {
261 std::shared_ptr<IDeviceObserver> ptr = observer.lock();
262 CHKPC(ptr);
263 ptr->OnDeviceRemoved(dev);
264 }
265 }
266
Dispatch(const struct epoll_event & ev)267 void DeviceManager::Dispatch(const struct epoll_event &ev)
268 {
269 CALL_DEBUG_ENTER;
270 CHKPV(context_);
271 int32_t ret = context_->GetDelegateTasks().PostAsyncTask(
272 std::bind(&DeviceManager::OnEpollDispatch, this, ev.events));
273 if (ret != RET_OK) {
274 FI_HILOGE("PostAsyncTask failed");
275 }
276 }
277
OnEpollDispatch(uint32_t events)278 int32_t DeviceManager::OnEpollDispatch(uint32_t events)
279 {
280 struct epoll_event ev {};
281 ev.events = events;
282 ev.data.ptr = epollMgr_.get();
283
284 CHKPR(epollMgr_, RET_ERR);
285 epollMgr_->Dispatch(ev);
286 return RET_OK;
287 }
288
GetDevice(int32_t id) const289 std::shared_ptr<IDevice> DeviceManager::GetDevice(int32_t id) const
290 {
291 CHKPP(context_);
292 std::packaged_task<std::shared_ptr<IDevice>(int32_t)> task {
293 std::bind(&DeviceManager::OnGetDevice, this, std::placeholders::_1) };
294 auto fu = task.get_future();
295
296 int32_t ret = context_->GetDelegateTasks().PostSyncTask(
297 std::bind(&DeviceManager::RunGetDevice, this, std::ref(task), id));
298 if (ret != RET_OK) {
299 FI_HILOGE("Post task failed");
300 return nullptr;
301 }
302 return fu.get();
303 }
304
OnGetDevice(int32_t id) const305 std::shared_ptr<IDevice> DeviceManager::OnGetDevice(int32_t id) const
306 {
307 if (auto devIter = devices_.find(id); devIter != devices_.cend()) {
308 return devIter->second;
309 }
310 FI_HILOGE("Device id not found");
311 return nullptr;
312 }
313
RunGetDevice(std::packaged_task<std::shared_ptr<IDevice> (int32_t)> & task,int32_t id) const314 int32_t DeviceManager::RunGetDevice(std::packaged_task<std::shared_ptr<IDevice>(int32_t)> &task,
315 int32_t id) const
316 {
317 task(id);
318 return RET_OK;
319 }
320
RetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)321 void DeviceManager::RetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)
322 {
323 CALL_INFO_TRACE;
324 CHKPV(context_);
325 int32_t ret = context_->GetDelegateTasks().PostAsyncTask(
326 std::bind(&DeviceManager::OnRetriggerHotplug, this, observer));
327 if (ret != RET_OK) {
328 FI_HILOGE("Post task failed");
329 }
330 }
331
OnRetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)332 int32_t DeviceManager::OnRetriggerHotplug(std::weak_ptr<IDeviceObserver> observer)
333 {
334 CALL_INFO_TRACE;
335 CHKPR(observer, RET_ERR);
336 std::shared_ptr<IDeviceObserver> ptr = observer.lock();
337 CHKPR(ptr, RET_ERR);
338 std::for_each(devices_.cbegin(), devices_.cend(),
339 [ptr] (const auto &item) {
340 if (item.second != nullptr) {
341 ptr->OnDeviceAdded(item.second);
342 }
343 });
344 return RET_OK;
345 }
346
AddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)347 int32_t DeviceManager::AddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
348 {
349 CALL_DEBUG_ENTER;
350 CHKPR(context_, RET_ERR);
351 int32_t ret = context_->GetDelegateTasks().PostAsyncTask(
352 std::bind(&DeviceManager::OnAddDeviceObserver, this, observer));
353 if (ret != RET_OK) {
354 FI_HILOGE("Post task failed");
355 }
356 return ret;
357 }
358
OnAddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)359 int32_t DeviceManager::OnAddDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
360 {
361 CALL_INFO_TRACE;
362 CHKPR(observer, RET_ERR);
363 auto ret = observers_.insert(observer);
364 if (!ret.second) {
365 FI_HILOGW("Observer is duplicated");
366 }
367 return RET_OK;
368 }
369
RemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)370 void DeviceManager::RemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
371 {
372 CALL_INFO_TRACE;
373 CHKPV(context_);
374 int32_t ret = context_->GetDelegateTasks().PostAsyncTask(
375 std::bind(&DeviceManager::OnRemoveDeviceObserver, this, observer));
376 if (ret != RET_OK) {
377 FI_HILOGE("Post task failed");
378 }
379 }
380
OnRemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)381 int32_t DeviceManager::OnRemoveDeviceObserver(std::weak_ptr<IDeviceObserver> observer)
382 {
383 CALL_INFO_TRACE;
384 CHKPR(observer, RET_ERR);
385 observers_.erase(observer);
386 return RET_OK;
387 }
388 } // namespace DeviceStatus
389 } // namespace Msdp
390 } // namespace OHOS