Note: The following content is based on Android API Version 27 (Android 8.1) Linux Kernel 3.18.0

An overview of the

Android receives and distributes input events in the WindowManagerService (WMS) process, that is, the System_server process. The INPUT system has two key threads on the WMS side: the reader thread and the distributor thread. The reader thread scans the input device and actively reads the input event from the device, then passes the event to the dispatcher thread. When App process adds Windows to WMS, WMS will create an InputChannel. One end of the channel is returned to App process, and one end is registered with the INPUT dispatch thread. Meanwhile, WMS will pass the hierarchy and size of all current Windows to the Input dispatch thread. Input After receiving the event, the dispatchthread looks at the current Focused window or window that can handle the current event and sends the event directly to the window through the event channel. The App process adds the FD(file descriptor) of the event channel returned from the WMS to its main thread Looper. The main thread processes the event directly upon receipt of the input event.

Event passing process

IMS side

Input Is the InputManagerService (IMS) at the Java layer. IMS is started with the System_server process. During the startup of IMS, two threads (InputReaderThread) are started. An event dispatcherThread (InputDispatcherThread).

WMS uses IMS directly. Through IMS, WMS transmits window information to event dispatches and sets the current Focused window. WMS is also responsible for creating and registering the InputChannel through which System_server and App processes transmit events. WMS registers the event sender InputChannel to IMS, and IMS finally calls the InputManager of Native layer.

Applications access IMS through the Java layer’s InputManager, which wraps the IMS binder agent objects.

IMS holds the Native layer’s NativeInputManager, and the NativeInputManager holds the NativeInputManager.

The Native layer InputManager contains an InputDispatcher and an InputReader, and the InputReader contains an EventHub.

InputDispatcher inherits InputListenerInterface and implements notifyKey and notifyMotion. InputDispatcher is passed to InputReader when InputReader is created. InputReader holds InputDispatcher of type InputListenerInterface.

InputReader has a corresponding InputReaderThread. A loop call to EventHub in InputReaderThread retrieves the event.

EventHub is responsible for opening all devices in the /dev/input directory, listening for device file changes under /dev/input through inotify, and reading all FDS.

EventHub uses the epoll system call to monitor inotify and device file FD for readable events. When a device is readable, it returns from epoll_wait, followed by reading event data from the device with data and returning the data to the InputReader. InputReader processes the original generation event to the mature event and hands it to InputDispather.

InputDispatcher corresponds to an InputDispatcherThread thread, in which the InputDispatcherThread uses the Looper of the Native layer to wait for the response of dispatched events. Also, if InputReader has an event, InputDispatcher will be called to add the event to a queue (mInboundQueue) and wake up the InputDispatcherThread. After the InputDispatcherThread is woken up, InputDispatcher is called to dispatch events in the event queue.

The event dispatch process is to find the current Window, then find the Connection based on the window, add the event to the Connection’s outboundQueue, and fetch a message from the outboundQueue header. InputPublisher calls the Connection to send the event, and InputPublisher eventually calls InputChannel, which calls socketPair’s senMsg function with its saved FD to send the event.

A Window corresponds to an InputChannel corresponds to a Connection.

After sending the event, log the message to the end of the Connection’s waitQueue. The InputDispatcherThread waits on The Looper again. After the App window finishes consuming the event and sends the Finish event, the InputDispatcherThread wakes up. It then finds the Connection based on the FD of the message that occurred (one FD for each window), finds the event based on the event sequence number (SEQ), removes the event from the waitQueue, and continues to distribute messages belonging to this Connction.

The App end

When App window calls addWindow of WMS, WMS will establish a pair of InputChannels for App window. Inputchannels are based on Socketpair (the two ends of socketpair are peer, there is no server and client). One end is used by InputDispatcher and the other end is returned to the App process for receiving events. WMS will register the InputChannel of the server with InputDispatcher, so that InputDispather can be used to send events to Windows and receive window events. The principle of receiving events is to add the FD of InputChannel to the Looper of InputDispather, because the InputDispatherThread blocks on Looper. PollOnce. When InputDispather receives a finish event from the window, InputDispatherThread is awakened and InputDistather processes the Finish message.

After the App process gets the InputChannel, it adds the FD of the socketpair inside it to the FD listening list of main Looper. If the event is received later, the event processing will occur directly in the main thread. After main Looper listens to the data on the FD, the callback function of the FD binding will be called. The callback function reads the Event and encapsulates it into the corresponding Event object, which is then passed layer by layer to the ViewRootImpl. The ViewRootImpl uses a responsibility chain to determine the order and manner in which events are processed. Some events may be sent to the input window first for consumption. If the input window does not consume, they will continue to be sent to the View Tree. ViewRootImpl -> DecorView -> Activity -> View(DecorView) -> child View of DecorView

If the App process has no handled event (i.e. the Activity, View, etc.), the finish event that the App sends to InputDispather signals that the event has been handled as false. When InputDispatcher receives the handled event as false it asks IMS if it’s a fallback event and IMS finally goes to the PhoneWindowManager via WMS to ask if it’s a fallback event. If so, add alternate events returned by PhoneWindowManager to the head of the connection outboundQueue corresponding to the window. Send this event to the window in the next window dispatch loop (note the large loop for InputDispather’s mInboundQueue and the window event mini-loop for connection’s outboundQueue).

Alternative events: The system can configure rollback for certain events. For example, if a button is not processed by App, the system can send a button event with similar functions to this button to try to be processed by App.

Each event is dispatched in at least one thread loop. For the window that is currently sending events, the event sends one feedback and then the next one. If no feedback is received this time, the next one is not sent. If the user presses the HOME button or triggers an event targeted at another window, and InputDispatcher finds that the current window is waiting for feedback from the previous event, it discards all events scheduled for the current window and sends HOME events or events that belong to another window to the corresponding target.

Event system key components

Linux Kenel and device drivers

  • Depending on the inserted device/dev/inputDirectory creationevent0~eventNTwo device nodes.
  • Hardware interrupt caused by listening for device input.
  • Caching the data wakes up the process waiting for the data on the device file.

EventHub (Managing input devices and reading input events)

  • useinotifyListen for input devices to be added and removed.
  • useepollMechanism listens for data changes on input devices.
  • Read data from a device file.
  • Returns raw data (generated events) toInputReader.

InputReader (Process spawning event to maturity event)

  • readIMSConfiguration information provided, such as keyboard layout.
  • According to theIMSThe provided configuration information (including keyboard layout, display information) performs a conversion on the original event.
  • Combine multiple events into one that can be consumed by upper levels (for example, combine a set of original touchscreen events into oneACTION_DOWNEvents).

InputDispatcher (Dispatch event)

  • According to theIMSProvides pre-dispatch policy filtering and blocking events (such as the HOME button)
  • For key events that generate simulated press repeat events, the start repeat delay is500msAnd the repeated interval is50ms.
  • WMSWill pass all current Windows and window information toInputDispatcherforInputDispatcherFind the dispatch window, find the window that can receive the event (for example, the key event looks for the focus window, the motion event looks for the window that contains the event coordinates) and send the event to the window.

InputChannel

  • InputChannelSupports cross-process transfer.
  • savesocketpairtheFD, the App process holds one end,WMSThe process holds one end.
  • InputChannelResponsible for the final read and write of events.

InputEventReceiver

  • The packagingInputChannel, is responsible forInputChanneltheFDJoin main Looper and be responsible for reading and writingInputChannel.
  • Send up events encapsulated as Java layer event objectsViewRootImpl.

ViewRootImpl

  • After receiving the event, send it to the View tree according to certain policies

aboutANR

InputDispatcher finds the target window based on the event. It depends on whether the target window can accept the event. If yes, it does not send the event this time, records the ANR start time and suspend the event. If a new event is added to the list and causes the thread to wake up, the thread sends the suspended event again, checks whether the current window can accept the event and updates the ANR time. When the ANR time reaches 5s, the IMS notifies the thread to process the ANR event. (If a new event belonging to another window or the event of the HOME button is added, all the events waiting for dispatch in the current window will be discarded. Except the events that have been added to the dispatch queue of the window, these times will be sent to the window one by one after the response of the events waiting for response in front of them)

For key and motion events, key events in the same window must be finish to send a, the next event to find window again to distribute, because an event could lead to the focus window changes, such as remote control, the user ordered a button and bring up a popup window, and the next event should be sent to the new pop-up window, The user’s expectation is that one key is processed and then another key is processed.

And motion event, if the current window is processing the event, subsequent events as long as it is in the first did not respond to events have occurred within 0.5 s of or add to this window own distributed queue, such as distributed event finished then in front of the queue distributed other events, if more than 0.5 s do not join the current queue provided by the window. Instead, wait for the next distribution cycle to find the window again and record the ANR start time. In this way, the motion events generally do not take into account the focus, and the expected time should be given to the window that the user is currently seeing. Even if the event being processed will cause the window to switch, as long as the user is still seeing the window, the events within 0.5 seconds will be given to the window. Events that exceed 0.5 seconds are determined by the newly found window.

ANR is a dialog, is AMS pop, the source of the event is InputDispatcher, through InputDispatcher -> NativeInputManager -> InputManagerService -> AMS

Event injection

Event injection helps us automate UI testing, and there are several ways to do it on Android.

1. Use the Instrumentation class to call the method such as sendPointerSync.

2. Use the ADB getevent/putevent command line tool

InjectInputEvent (App process can access IMS through InputManager). InjectInputEvent is API hide method, so it can only be accessed through hack.

Pay attention to

  • becauseANRwhenAMSWill send out aandroid.intent.action.ANRBroadcast, by listening to this broadcast can collect AppANREvents are reported to the server.
  • HOMEKeys will be distributed beforeIMSIntercept, becauseIMSisInputDispatcherBefore the dispatch ofpolocy.IMSWill forward the event toPhoneWindowManagerBy thePhoneWindowManagerStart theHOMEDesktop and consume events.