• 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 #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