Understanding Android EventHub: Architecture and Event Handling
EventHub acts as the bridge between Linux input devices and Android’s InputReader by monitoring /dev/input with inotify and epoll, detecting device additions, opening and registering new devices, reading raw input_event structures, converting them into RawEvent objects, and handling closures, rescans, and wake‑up signals in a continuous loop.
Android is built on the Linux kernel and is composed of multiple subsystems. The Input subsystem is responsible for handling events from various input devices. EventHub serves as a crucial bridge between the low‑level input devices and the upper‑level InputReader.
EventHub works by having the InputReader’s loop call EventHub::getEvents() . Inside this function, epoll_wait blocks until new input events arrive, after which the events are processed and returned to the InputReader.
1. New Device Addition
(1) A new device appears under /dev/input/ .
(2) The path is monitored by mINotifyFd , which receives an IN_CREATE event.
(3) mINotifyFd is also watched by mEpollFd ; the event wakes epoll_wait .
(4) The event source is identified as mINotifyFd , setting mPendingINotify to true and triggering readNotifyLocked() on the next loop.
(5) openDeviceLocked() is called to open the device and configure its identifier, classes, keymap, etc.
(6) The device is added to mEpollFd monitoring and stored in mDevices and mOpeningDevices .
(7) In the following iteration, mOpeningDevices contains the new device, and an event is generated for it.
2. Device Event Retrieval
(1) The device generates a new event.
(2) Because the device was added to mEpollFd , epoll_wait returns.
(3) Device* device = getDeviceByFdLocked(eventItem.data.fd) locates the device by its file descriptor.
(4) read(device->fd, readBuffer, sizeof(struct input_event) * capacity) reads raw input events.
(5) count = size_t(readSize) / sizeof(struct input_event) calculates the number of events.
(6) The events are parsed and transformed into RawEvent objects, which are returned to the InputReader.
3. EventHub Constructor
The constructor registers INotify and Epoll to monitor device addition/removal and input events. INotify watches filesystem changes, while Epoll can wait on multiple descriptors.
Construction steps:
(1) Initialize various member variables.
(2) Create the epoll object and the inotify object.
(3) Add mINotifyFd as a monitored descriptor of mEpollFd .
(4) Create a wake‑up pipe; wake() writes to the write end, and the read end is monitored by mEpollFd .
4. getEvents(): Listening and Reading Input Device Events
getEvents() is invoked by the InputReader’s loop and itself runs an infinite loop that ends with epoll_wait . When a new input event arrives, the function exits the wait, processes the event according to its type, updates the RawEvent buffer, and then returns to waiting.
Handled event types include:
1. Device close – iterates over devices pending closure and removes them.
2. Device reopen – closes all devices and rescans for available input devices.
3. Device scan and open – scanDevicesLocked() scans /dev/input , creates DEVICE_ADDED events for newly opened devices, and finally emits a FINISHED_DEVICE_SCAN event.
4. Input event processing – iterates over pending events, determines the source via the epoll data field, and processes EPOLLIN events by reading input_event structures and converting them to RawEvent . EPOLLHUP indicates a hung‑up device and triggers its closure.
5. If the event originates from INotify ( EPOLLIN ), readNotifyLocked() is called to load or unload the device.
After processing, the loop returns to epoll_wait for new events.
5. scanDevicesLocked() & openDeviceLocked(): Scanning and Loading Available Devices
scanDevicesLocked() scans the /dev/input directory via scanDirLocked() and opens each discovered device with openDeviceLocked() .
openDeviceLocked() opens the device node, obtains an InputDeviceIdentifier structure, and reads the device’s bitmask to determine its type (e.g., keyboard, touch, joystick). The device is then registered with epoll using registerDeviceForEpollLocked(device) and added to the internal device list.
Conclusion
Although the EventHub code is relatively compact, it is an indispensable component of Android’s input subsystem, linking low‑level input devices with the higher‑level InputReader. Understanding its workflow provides valuable insight into how Android processes input events.
OPPO Kernel Craftsman
Sharing Linux kernel-related cutting-edge technology, technical articles, technical news, and curated tutorials
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.