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