Android is an event-driven system, so goals and tasks of the input system is
WATCH task: watch meta events (e.g., x, y, gps) comming from environment (system, user, or sensors),
PARSE task: parses these meta events to RawEvent with type and arguments, and,
DISPATCH task: convert the typed RawEvent to specific typed DispatchEntry, and then dispatches them to correct connections (event consumers)
Work of the input system is a result of cooperations coming from the lower-lever device/kernel, to higher-level framework; and components involved in this process include:
WATCH
driver: each device has a driver file under /dev/input/, and devices write their meta events to the driver file
EventHub: EventHub blocks to watch meta events from drivers, and is waked up by kernel when there are
PARSE
EventHub: whenever waked up, EventHub parses the meta events to RawEvent
InputReader: InputReader looply read RawEvents from EventHub (if no events, EventHub will block), converts to specific typed NotifyArgses, then put them to InputDispatcher's queue
DISPATCH
InputDispatcher: InputDispatcher looply read NotifyArgs from its queue, parse them to specific DispatchEntry, and dispatches all registered Connections
Connection: Connection will consume the DispatchEntrys (e.g., convert to MotionEvent, and pass to Activity)
Above figure shows the relationship of these components.
One can see the overall link that the touch experienced is
IMS is created as an other server of system server, while creating (ims = InputManagerService()),
IMS registers to run itself in android.display thread (see #98)
IMS creates a JNI Level IMS (JniIMS)
JniIMS creates EventHub
EventHub registers to watch changes of /dev/input/ (in implementation, uses syscall inotify to watch IN_DELETE, IN_CREATE inotify event)
JniIMS creates a Native Level IMS (NIMS)
NIMS creates an InputReader for reading raw events from EventHub
NIMS creates an InputDispathcer for listening events read by InputReader, and then dispatching to the target window
After created, IMS is started (ims.start()),
NIMS starts InputDispatcher thread
NIMS starts InputReader thread
As one can see, there are at least 2 process and 4 threads that are involed in input system:
systerm server process
android.display thread: IMS runs in this thread to handle message
InputReader thread: InputReader runs in a standalone threat that looply retrieves next event from EventHub (but it is not a Looper), and put to InputDispatcher's queue
InputDispatcher thread: InputDispatcher runs in a standalone thread that looply retrieves next event from its queue, and dispatches to registered connections
app process: the process that consumes the DispatchEntry
InputReader
InputReader is a component and a thread that connects top to InputDispatcher and bottom to EventHub; InputReader works like the following pseudo-code
while (true) {
RawEvent next = mEventHub.getEventsOrBlock();
switch (next.type) {
case Motion: mDispatcher.notifyMotion(toNotifyMotionArgs.fromRawEvent(next)); break;
case Key: mDispatcher.notifyKey(toNotifyKeyArgs.fromRawEvent(next)); break;
...
}
}
EventHub
Actually there are at least 3 events that need to be watched:
DEVICE_ADDED: there is a device added
DEVICE_REMOVED: there is a device removed
data events: there are events from current devices
Since each device has a device file under /dev/input/, the addition and deletion of devices can be told by file creation and deletion. And thereby EventHub enforces the inotify mechanism of linux of watch such event
Since events happended on devices can be told by content changes of their files, EventHub opens the device files and wait for their changes
For better performance, EventHub then enforces epoll on all of them, specifically,
it creates an epoll fd mEpollFd for watching epoll events
DEVICE_ADDED/DEVICE_REMOVED (see EventHub#<init>())
it registered an mINotifyFd using inotify_init()
it watches IN_CREATE and IN_DELETION inotify event of mINofityFd
it adds mINotifyFd to mEpollFd, and watches its EPOLLIN event
data events for each device, (see EventHub#openDeviceLocked())
it opens it device file as fd
it add fd to mEpollFd, and watches its EPOLLIN event
For better performance a further step, the devices ain't opened until the first EventHub#getEvents() is invoked
The following pseudo-code shows the workflow of EventHub
Input System
Android is an event-driven system, so goals and tasks of the input system is
RawEvent
with type and arguments, and,RawEvent
to specific typedDispatchEntry
, and then dispatches them to correct connections (event consumers)Work of the input system is a result of cooperations coming from the lower-lever device/kernel, to higher-level framework; and components involved in this process include:
/dev/input/
, and devices write their meta events to the driver fileEventHub
: EventHub blocks to watch meta events from drivers, and is waked up by kernel when there areEventHub
: whenever waked up, EventHub parses the meta events toRawEvent
InputReader
: InputReader looply readRawEvent
s from EventHub (if no events, EventHub will block), converts to specific typedNotifyArgs
es, then put them toInputDispatcher
's queueInputDispatcher
: InputDispatcher looply readNotifyArgs
from its queue, parse them to specificDispatchEntry
, and dispatches all registeredConnection
sConnection
: Connection will consume theDispatchEntry
s (e.g., convert toMotionEvent
, and pass toActivity
)Above figure shows the relationship of these components.
One can see the overall link that the touch experienced is
References
Start Process
IMS is created as an other server of system server, while creating (
ims = InputManagerService()
),android.display
thread (see #98)/dev/input/
(in implementation, uses syscallinotify
to watchIN_DELETE
,IN_CREATE
inotify event)After created, IMS is started (
ims.start()
),InputDispatcher
threadInputReader
threadAs one can see, there are at least 2 process and 4 threads that are involed in input system:
android.display
thread: IMS runs in this thread to handle messageInputReader
thread: InputReader runs in a standalone threat that looply retrieves next event fromEventHub
(but it is not aLooper
), and put to InputDispatcher's queueInputDispatcher
thread: InputDispatcher runs in a standalone thread that looply retrieves next event from its queue, and dispatches to registered connectionsDispatchEntry
InputReader
InputReader is a component and a thread that connects top to InputDispatcher and bottom to EventHub; InputReader works like the following pseudo-code
EventHub
Actually there are at least 3 events that need to be watched:
Since each device has a device file under
/dev/input/
, the addition and deletion of devices can be told by file creation and deletion. And thereby EventHub enforces theinotify
mechanism of linux of watch such eventSince events happended on devices can be told by content changes of their files, EventHub opens the device files and wait for their changes
For better performance, EventHub then enforces
epoll
on all of them, specifically,mEpollFd
for watching epoll eventsDEVICE_ADDED
/DEVICE_REMOVED
(seeEventHub#<init>()
)mINotifyFd
usinginotify_init()
IN_CREATE
andIN_DELETION
inotify event ofmINofityFd
mINotifyFd
tomEpollFd
, and watches itsEPOLLIN
eventEventHub#openDeviceLocked()
)fd
fd
tomEpollFd
, and watches itsEPOLLIN
eventFor better performance a further step, the devices ain't opened until the first
EventHub#getEvents()
is invokedThe following pseudo-code shows the workflow of EventHub
References
InputDispatcher
:warning: TO BE ADDED
IPC, WMS and InputDispatcher
:warning: TO BE ADDED