• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "input_interface_device_info.h"
17 
18 #include <system_error>
19 
20 #include <sys/inotify.h>
21 #include <dirent.h>
22 #include <fcntl.h>
23 #include <sys/epoll.h>
24 #include <unistd.h>
25 #include <linux/input.h>
26 #include "hdf_log.h"
27 #include "securec.h"
28 #include "input_type.h"
29 #include "input_event_operate.h"
30 
31 namespace OHOS {
32 namespace Input {
33 constexpr int32_t WAIT_TIME_FOR_INPUT = 10;
34 constexpr int32_t MAX_RETRY_COUNT = 5;
35 constexpr int32_t MAX_EVENT_BUF_SIZE = 512;
36 constexpr int32_t MAX_EVENT_SIZE = 100;
37 constexpr int32_t EPOLL_WAIT_TIME = 5 * 1000;
38 constexpr int32_t LOG_BUFFER_LEN = 256;
39 constexpr int32_t IOCTL_BUFFER_LEN = 256;
40 const std::string INPUT_DEVICES_PATH = "/dev/input/";
41 
SystemError()42 auto SystemError()
43 {
44     return std::error_code{errno, std::system_category()};
45 }
46 
HdfLogFunc(struct libinput * input,libinput_log_priority priority,const char * fmt,va_list args)47 void HdfLogFunc(struct libinput* input, libinput_log_priority priority, const char* fmt, va_list args)
48 {
49     if (input == nullptr || fmt == nullptr) {
50         HDF_LOGE("hi log func failed");
51         return;
52     }
53     char buffer[LOG_BUFFER_LEN] = {};
54     if (vsnprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, fmt, args) == -1) {
55         HDF_LOGE("Call vsnprintf_s failed");
56         va_end(args);
57         return;
58     }
59     HDF_LOGE("PrintLog_Info:%{public}s", buffer);
60     va_end(args);
61 }
62 
63 constexpr static libinput_interface LIBINPUT_INTERFACE = {
__anon3f83c6760102()64     .open_restricted = [](const char *path, int32_t flags, void *user_data)->int32_t {
65         if (path == nullptr) {
66             HDF_LOGI("Input device path is nullptr");
67             return -1;
68         }
69         char realPath[PATH_MAX] = {};
70         if (realpath(path, realPath) == nullptr) {
71             std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_TIME_FOR_INPUT));
72             HDF_LOGI("The error path is %{public}s", path);
73             return -1;
74         }
75         int32_t fd;
76         for (int32_t i = 0; i < MAX_RETRY_COUNT; i++) {
77             fd = open(realPath, flags);
78             if (fd >= 0) {
79                 break;
80             }
81             std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_TIME_FOR_INPUT));
82         }
83         int32_t errNo = errno;
84         HDF_LOGI("Libinput .open_restricted path:%{public}s,fd:%{public}d,errno:%{public}d", path, fd, errNo);
85         return fd < 0 ? -1 : fd;
86     },
87     .close_restricted = [](int32_t fd, void *user_data)
__anon3f83c6760202() 88     {
89         HDF_LOGI("Libinput .close_restricted fd:%{public}d", fd);
90         close(fd);
91     },
92 };
93 
InitHotPlug()94 RetStatus DeviceInfo::InitHotPlug()
95 {
96     HDF_LOGI("Init hot plug");
97     inotifyFd_ = inotify_init1(IN_CLOEXEC);
98     if (inotifyFd_ < 0) {
99         HDF_LOGE("Failed to initialize inotify. errno: %{public}d.", errno);
100         return INPUT_FAILURE;
101     }
102     if (inotify_add_watch(inotifyFd_, INPUT_DEVICES_PATH.c_str(), IN_DELETE | IN_CREATE) < 0) {
103         HDF_LOGE("Failed to add watch for input devices. errno: %{public}d.", errno);
104         return INPUT_FAILURE;
105     }
106     return Scan();
107 }
108 
IsDeviceSupported(const std::string & path,bool & supported)109 RetStatus DeviceInfo::IsDeviceSupported(const std::string &path, bool &supported)
110 {
111     HDF_LOGI("is device supported");
112     int32_t fd = open(path.c_str(), O_RDWR);
113     if (fd < 0) {
114         HDF_LOGE("open file failed, errno: %{public}d", errno);
115         return INPUT_FAILURE;
116     }
117 
118     char buffer[IOCTL_BUFFER_LEN];
119     (void)memset_s(buffer, sizeof(buffer), 0, sizeof(buffer));
120 
121     int32_t ret = ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer);
122     close(fd);
123     if (ret < 1) {
124         HDF_LOGE("get device name failed error: %{public}d", errno);
125         return INPUT_FAILURE;
126     }
127     for (const auto &each : supportedDevice) {
128         if (std::string(buffer).find(each) != std::string::npos) {
129             supported = true;
130             return INPUT_SUCCESS;
131         }
132     }
133     supported = false;
134     return INPUT_SUCCESS;
135 }
136 
Scan()137 RetStatus DeviceInfo::Scan()
138 {
139     HDF_LOGI("scan");
140     using namespace std::literals::string_literals;
141     auto* dir = opendir(INPUT_DEVICES_PATH.c_str());
142     if (dir == nullptr) {
143         HDF_LOGE("Failed to open device input dir. errno: %{public}d.", errno);
144         return INPUT_FAILURE;
145     }
146     dirent* entry = nullptr;
147     while ((entry = readdir(dir)) != nullptr) {
148         if (entry->d_name == "."s || entry->d_name == ".."s) {
149             continue;
150         }
151         bool supported = false;
152         std::string path = std::string{INPUT_DEVICES_PATH} + entry->d_name;
153         auto ret = IsDeviceSupported(path, supported);
154         if (ret != INPUT_SUCCESS) {
155             continue;
156         }
157         if (supported) {
158             OnDeviceAdded(path);
159         }
160     }
161     closedir(dir);
162     return INPUT_SUCCESS;
163 }
164 
OnHotPlugEvent()165 void DeviceInfo::OnHotPlugEvent()
166 {
167     constexpr int32_t EVSIZE = static_cast<int32_t>(sizeof(inotify_event));
168     if (inotifyFd_ < 0) {
169         return;
170     }
171     std::byte event_buf[MAX_EVENT_BUF_SIZE];
172     int32_t res = read(inotifyFd_, event_buf, sizeof(event_buf));
173     if (res < EVSIZE) {
174         auto err = SystemError();
175         if (err != std::errc::resource_unavailable_try_again) {
176             HDF_LOGE("Filed to read inotify event. Error: %{public}s.", err.message().c_str());
177         }
178         return;
179     }
180     inotify_event event;
181     for (int32_t pos = 0; res > EVSIZE;) {
182         std::copy_n(event_buf + pos, sizeof(event), reinterpret_cast<std::byte*>(&event));
183         if (event.len != 0) {
184             auto path = INPUT_DEVICES_PATH + std::string{reinterpret_cast<char*>(event_buf + pos + sizeof(event))};
185             if (event.mask & IN_CREATE) {
186                 OnDeviceAdded(path);
187             } else {
188                 OnDeviceRemoved(path);
189             }
190         }
191         int32_t consumed = EVSIZE + event.len;
192         pos += consumed;
193         res -= consumed;
194     }
195 }
196 
197 
EpollCreate()198 RetStatus DeviceInfo::EpollCreate()
199 {
200     HDF_LOGI("Epoll create");
201     epollFd_ = epoll_create(MAX_EVENT_SIZE);
202     if (epollFd_ < 0) {
203         HDF_LOGE("epoll_create return %{public}d", epollFd_);
204         return INPUT_FAILURE;
205     }
206     HDF_LOGI("epoll_create, epollFd_:%{public}d", epollFd_);
207     return INPUT_SUCCESS;
208 }
209 
CreateLibinputContext()210 RetStatus DeviceInfo::CreateLibinputContext()
211 {
212     HDF_LOGI("Create libinput context");
213     input_ = libinput_path_create_context(&LIBINPUT_INTERFACE, nullptr);
214     if (input_ == nullptr) {
215         HDF_LOGE("create libinput context failed");
216         return INPUT_FAILURE;
217     }
218     libinput_log_set_handler(input_, &HdfLogFunc);
219     libinputFd_ = libinput_get_fd(input_);
220     if (libinputFd_ < 0) {
221         libinput_unref(input_);
222         libinputFd_ = -1;
223         HDF_LOGE("The fd_ is less than 0");
224         return INPUT_FAILURE;
225     }
226     return INPUT_SUCCESS;
227 }
228 
AddToEpoll(int32_t fd)229 RetStatus DeviceInfo::AddToEpoll(int32_t fd)
230 {
231     HDF_LOGI("Add to epoll");
232     struct epoll_event eventItem;
233     (void)memset_s(&eventItem, sizeof(eventItem), 0, sizeof(eventItem));
234     eventItem.events = EPOLLIN;
235     eventItem.data.fd = fd;
236     int32_t ret = epoll_ctl(epollFd_, EPOLL_CTL_ADD, fd, &eventItem);
237     if (ret < 0) {
238         HDF_LOGE("add fd to epoll failed, ret=%d, errno=%d", ret, errno);
239         return INPUT_FAILURE;
240     }
241     return INPUT_SUCCESS;
242 }
243 
RemoveEpoll(int32_t fd)244 RetStatus DeviceInfo::RemoveEpoll(int32_t fd)
245 {
246     HDF_LOGI("remove from epoll");
247     int32_t ret = epoll_ctl(epollFd_, EPOLL_CTL_DEL, fd, nullptr);
248     if (ret < 0) {
249         HDF_LOGE("remove fd from epoll failed, ret=%d, errno=%d", ret, errno);
250         return INPUT_FAILURE;
251     }
252     return INPUT_SUCCESS;
253 }
254 
EpollWaitThread()255 void DeviceInfo::EpollWaitThread()
256 {
257     HDF_LOGI("epoll wait thread begin");
258     ProcessPendingEvents();
259     while (threadState_ == ThreadState::RUNNING) {
260         epoll_event ev[MAX_EVENT_SIZE] = {};
261         int32_t count = epoll_wait(epollFd_, ev, MAX_EVENT_SIZE, EPOLL_WAIT_TIME);
262         if (count < 0) {
263             HDF_LOGE("epoll wait failed, count=%d, errno=%d", count, errno);
264             continue;
265         }
266         for (int32_t i = 0; i < count && threadState_ == ThreadState::RUNNING; i++) {
267             if (ev[i].data.fd == inotifyFd_) {
268                 OnHotPlugEvent();
269                 continue;
270             }
271             OnLibinputEvent();
272         }
273         if (threadState_ == ThreadState::STOP) {
274             break;
275         }
276     }
277     HDF_LOGI("epoll wait thread thread stop");
278 }
279 
Init()280 RetStatus DeviceInfo::Init()
281 {
282     HDF_LOGI("init libinput");
283     RetStatus ret = INPUT_FAILURE;
284     do {
285         ret = EpollCreate();
286         if (ret != INPUT_SUCCESS) {
287             break;
288         }
289         ret = CreateLibinputContext();
290         if (ret != INPUT_SUCCESS) {
291             break;
292         }
293         ret = InitHotPlug();
294         if (ret != INPUT_SUCCESS) {
295             break;
296         }
297         ret = AddToEpoll(inotifyFd_);
298         if (ret != INPUT_SUCCESS) {
299             break;
300         }
301         ret = AddToEpoll(libinputFd_);
302         if (ret != INPUT_SUCCESS) {
303             break;
304         }
305         threadState_ = ThreadState::RUNNING;
306         t_ = std::thread(std::bind(&DeviceInfo::EpollWaitThread, this));
307 
308     }while (0);
309 
310     if (ret != INPUT_SUCCESS) {
311         Stop();
312         return ret;
313     }
314     return INPUT_SUCCESS;
315 }
316 
Stop()317 void DeviceInfo::Stop()
318 {
319     HDF_LOGI("stop thread and libinput");
320     threadState_ = ThreadState::STOP;
321     t_.join();
322     HDF_LOGI("epoll wait thread stopped");
323     if (libinputFd_ >= 0) {
324         close(libinputFd_);
325         libinputFd_ = INVALID_FD;
326     }
327     if (input_ != nullptr) {
328         libinput_unref(input_);
329         input_ = nullptr;
330     }
331     if (inotifyFd_ >= 0) {
332         close(inotifyFd_);
333         inotifyFd_ = INVALID_FD;
334     }
335     if (epollFd_ >= 0) {
336         close(epollFd_);
337         epollFd_ = INVALID_FD;
338     }
339 }
340 
ProcessPendingEvents()341 void DeviceInfo::ProcessPendingEvents()
342 {
343     OnLibinputEvent();
344 }
345 
OnLibinputEvent()346 void DeviceInfo::OnLibinputEvent()
347 {
348     if (libinput_dispatch(input_) != 0) {
349         HDF_LOGE("Failed to dispatch libinput");
350         return;
351     }
352 
353     libinput_event *event = nullptr;
354     int i = 0;
355     (void)memset_s(eventInfo_, sizeof(eventInfo_), 0, sizeof(eventInfo_));
356     while ((event = libinput_get_event(input_))) {
357         auto ret = TransformEvent(eventInfo_[i], event);
358         libinput_event_destroy(event);
359         if (ret != INPUT_SUCCESS) {
360             continue;
361         }
362         i++;
363         if (i == MAX_REPORT_EVENT_SIZE) {
364             ReportLibinputEvent(i);
365             (void)memset_s(eventInfo_, sizeof(eventInfo_), 0, sizeof(eventInfo_));
366             i = 0;
367         }
368     }
369     if (i > 0) {
370         ReportLibinputEvent(i);
371     }
372 }
373 
ReportLibinputEvent(int eventNum)374 void DeviceInfo::ReportLibinputEvent(int eventNum)
375 {
376     if (reporterSptr == nullptr) {
377         HDF_LOGE("reporterSptr is nullptr");
378         return;
379     }
380     (void)reporterSptr->ReportEvent(eventInfo_, eventNum);
381 }
382 
OnDeviceAdded(const std::string & path)383 void DeviceInfo::OnDeviceAdded(const std::string &path)
384 {
385     HDF_LOGI("device added");
386     std::lock_guard<std::mutex> guard(devicesMtx_);
387     libinput_device* device = libinput_path_add_device(input_, path.c_str());
388     if (device == nullptr) {
389         HDF_LOGE("add device failed");
390         return;
391     }
392     devices_[path] = libinput_device_ref(device);
393     // Libinput doesn't signal device adding event in path mode. Process manually.
394     OnLibinputEvent();
395 }
396 
OnDeviceRemoved(const std::string & path)397 void DeviceInfo::OnDeviceRemoved(const std::string &path)
398 {
399     HDF_LOGI("device removed");
400     std::lock_guard<std::mutex> guard(devicesMtx_);
401     auto pos = devices_.find(path);
402     if (pos != devices_.end()) {
403         libinput_path_remove_device(pos->second);
404         libinput_device_unref(pos->second);
405         devices_.erase(pos);
406         // Libinput doesn't signal device removing event in path mode. Process manually.
407         OnLibinputEvent();
408     }
409 }
410 } // namespace Input
411 } // namespace OHOS
412