Check if /dev/input exists before accessing the path
It is possible that development platforms don't have any input devices,
hence /dev/input directory won't be created. Hence check if /dev/input exists
before adding inotify watch and scanDirLocked for /dev/input.
inotify_add_watch is also added for /dev/input when it is created. for e.g.
during EventHubTest.
Test: atest inputflinger_tests (on a development board with no input
devices)
Signed-off-by: Usama Arif <usama.arif@arm.com>
Change-Id: I8675921280e351dd8885becce79a7cb4a9936c10
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index b19b419..68d5e7c 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -63,9 +63,9 @@
namespace android {
-static const char* DEVICE_PATH = "/dev/input";
+static const char* DEVICE_INPUT_PATH = "/dev/input";
// v4l2 devices go directly into /dev
-static const char* VIDEO_DEVICE_PATH = "/dev";
+static const char* DEVICE_PATH = "/dev";
static constexpr size_t OBFUSCATED_LENGTH = 8;
@@ -685,15 +685,23 @@
LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance: %s", strerror(errno));
mINotifyFd = inotify_init();
- mInputWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
- LOG_ALWAYS_FATAL_IF(mInputWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH,
- strerror(errno));
- if (isV4lScanningEnabled()) {
- mVideoWd = inotify_add_watch(mINotifyFd, VIDEO_DEVICE_PATH, IN_DELETE | IN_CREATE);
- LOG_ALWAYS_FATAL_IF(mVideoWd < 0, "Could not register INotify for %s: %s",
- VIDEO_DEVICE_PATH, strerror(errno));
+
+ std::error_code errorCode;
+ bool isDeviceInotifyAdded = false;
+ if (std::filesystem::exists(DEVICE_INPUT_PATH, errorCode)) {
+ addDeviceInputInotify();
} else {
- mVideoWd = -1;
+ addDeviceInotify();
+ isDeviceInotifyAdded = true;
+ if (errorCode) {
+ ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(),
+ errorCode.message().c_str());
+ }
+ }
+
+ if (isV4lScanningEnabled() && !isDeviceInotifyAdded) {
+ addDeviceInotify();
+ } else {
ALOGI("Video device scanning disabled");
}
@@ -733,6 +741,23 @@
::close(mWakeWritePipeFd);
}
+/**
+ * On devices that don't have any input devices (like some development boards), the /dev/input
+ * directory will be absent. However, the user may still plug in an input device at a later time.
+ * Add watch for contents of /dev/input only when /dev/input appears.
+ */
+void EventHub::addDeviceInputInotify() {
+ mDeviceInputWd = inotify_add_watch(mINotifyFd, DEVICE_INPUT_PATH, IN_DELETE | IN_CREATE);
+ LOG_ALWAYS_FATAL_IF(mDeviceInputWd < 0, "Could not register INotify for %s: %s",
+ DEVICE_INPUT_PATH, strerror(errno));
+}
+
+void EventHub::addDeviceInotify() {
+ mDeviceWd = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE);
+ LOG_ALWAYS_FATAL_IF(mDeviceWd < 0, "Could not register INotify for %s: %s", DEVICE_PATH,
+ strerror(errno));
+}
+
InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
std::scoped_lock _l(mLock);
Device* device = getDeviceLocked(deviceId);
@@ -1739,14 +1764,24 @@
}
void EventHub::scanDevicesLocked() {
- status_t result = scanDirLocked(DEVICE_PATH);
- if (result < 0) {
- ALOGE("scan dir failed for %s", DEVICE_PATH);
+ status_t result;
+ std::error_code errorCode;
+
+ if (std::filesystem::exists(DEVICE_INPUT_PATH, errorCode)) {
+ result = scanDirLocked(DEVICE_INPUT_PATH);
+ if (result < 0) {
+ ALOGE("scan dir failed for %s", DEVICE_INPUT_PATH);
+ }
+ } else {
+ if (errorCode) {
+ ALOGW("Could not run filesystem::exists() due to error %d : %s.", errorCode.value(),
+ errorCode.message().c_str());
+ }
}
if (isV4lScanningEnabled()) {
- result = scanVideoDirLocked(VIDEO_DEVICE_PATH);
+ result = scanVideoDirLocked(DEVICE_PATH);
if (result != OK) {
- ALOGE("scan video dir failed for %s", VIDEO_DEVICE_PATH);
+ ALOGE("scan video dir failed for %s", DEVICE_PATH);
}
}
if (mDevices.find(ReservedInputDeviceId::VIRTUAL_KEYBOARD_ID) == mDevices.end()) {
@@ -2357,23 +2392,25 @@
while (res >= (int)sizeof(*event)) {
event = (struct inotify_event*)(event_buf + event_pos);
if (event->len) {
- if (event->wd == mInputWd) {
- std::string filename = std::string(DEVICE_PATH) + "/" + event->name;
+ if (event->wd == mDeviceInputWd) {
+ std::string filename = std::string(DEVICE_INPUT_PATH) + "/" + event->name;
if (event->mask & IN_CREATE) {
openDeviceLocked(filename);
} else {
ALOGI("Removing device '%s' due to inotify event\n", filename.c_str());
closeDeviceByPathLocked(filename);
}
- } else if (event->wd == mVideoWd) {
+ } else if (event->wd == mDeviceWd) {
if (isV4lTouchNode(event->name)) {
- std::string filename = std::string(VIDEO_DEVICE_PATH) + "/" + event->name;
+ std::string filename = std::string(DEVICE_PATH) + "/" + event->name;
if (event->mask & IN_CREATE) {
openVideoDeviceLocked(filename);
} else {
ALOGI("Removing video device '%s' due to inotify event", filename.c_str());
closeVideoDeviceByPathLocked(filename);
}
+ } else if (strcmp(event->name, "input") == 0 && event->mask & IN_CREATE) {
+ addDeviceInputInotify();
}
} else {
LOG_ALWAYS_FATAL("Unexpected inotify event, wd = %i", event->wd);