您的位置:首页 > 移动开发 > Android开发

Android Input Event Propagation

2013-11-11 22:54 531 查看
https://gist.github.com/jieyu/4262418

https://gist.github.com/jieyu/4262418/raw/c1d0fc34eac41be55017ac6d8fc3b4b46cc7fe94/AndroidInputEventPropagation.md

# Android Input Event Propagation

This document discusses how an input event from user (e.g. user key stroke) is propagated in Android framework, and how it is delivered to the corresponding event handler in the application.

This document is based on the code of Android 4.1.1_r6.1 (Jelly Bean).

For each application, a `ViewRootImpl` object is created to handle communications with the remote system `WindowManagerService` object. The communication is through a Linux pipe which is encapsulated in an `InputChannel` object (`mInputChannel` field in class `ViewRootImpl`). The `ViewRootImpl` object also registers an instance of `InputEventReceiver` when the first `View` object is registered with it.

frameworks/base/core/java/android/view/ViewRootImpl.java +482

482  public void setView(View view, ...) {
...
626    mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper());
...
644  }

The constructor of class `WindowInputEventReceiver` (class `WindowManagerService` extends from class `InputEventReceiver`) calls a native methond `nativeInit(...)`:

frameworks/base/core/java/android/view/InputEventReceiver.java +58

58   public InputEventReceiver(InputChannel inputChannel, Looper looper) {
...
66     mInputChannel = inputChannel;
67     mMessageQueue = looper.getQueue();
68     mReceiverPtr = nativeInit(this, inputChannel, mMessageQueue);
...
71   }

Three parameters are passed to the native function `nativeInit`: 1) The receiver object itself; 2) The `InputChannel` object passed from the `ViewRootImpl` object. 3) The main message queue (an object of class `MessageQueue`) of the application.

The native function `nativeInit` is shown as follows:

frameworks/base/core/jni/android_view_InputEventReceiver.cpp +227

227  static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
228      jobject inputChannelObj, jobject messageQueueObj) {
229    sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,
230        inputChannelObj);
...
236    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
...
242    sp<NativeInputEventReceiver> receiver = new NativeInputEventReceiver(env,
243             receiverObj, inputChannel, messageQueue);
244    status_t status = receiver->initialize();
...
254  }

The function first gets a pointer to a `NativeInputChannel` object (line 229) and a pointer to a `NativeMessageQueue` object (line 236), then creates and initializes a `NativeInputEventReceiver` object (line 242-244) using these two pointers and the receiver object itself. In the `initialize()` function of class `NativeInputEventReceiver`, the file descriptor of the Linux pipe (which is passed from `ViewRootImpl` in the object of `InputChannel`) is sent to the looper for polling. When the file descriptor becomes readable which means the system `WindowManagerService` object has detected an input event from the kernel, a callback function will be invoked.

frameworks/base/core/jni/android_view_InputEventReceiver.cpp +92

92   status_t NativeInputEventReceiver::initialize() {
93     int receiveFd = mInputConsumer.getChannel()->getFd();
94     mMessageQueue->getLooper()->addFd(receiveFd, 0, ALOOPER_EVENT_INPUT, this, NULL);
95     return OK;
96   }

The callback function is the `handleEvent(...)` function in the same class `NativeInputEventReceiver`:

frameworks/base/core/jni/android_view_InputEventReceiver.cpp +119

119  int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {
...
132     JNIEnv* env = AndroidRuntime::getJNIEnv();
133     status_t status = consumeEvents(env, false /*consumeBatches*/, -1);
134     mMessageQueue->raiseAndClearException(env, "handleReceiveCallback");
135     return status == OK || status == NO_MEMORY ? 1 : 0;
136  }

138  status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,
139      bool consumeBatches, nsecs_t frameTime) {
...
187    inputEventObj = android_view_KeyEvent_fromNative(env,
188        static_cast<KeyEvent*>(inputEvent));
...
208    env->CallVoidMethod(mReceiverObjGlobal,
209        gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);
...
224  }

As shown above, function `handleEvent(...)` invokes a Java function `InputEventReceiver.dispatchInputEvent(...)` (line 208), which will eventually invoke `onInputEvent(...)` in class `WindowInputEventReceiver`:

frameworks/base/core/java/android/view/ViewRootImpl.java +4223

4223 public void onInputEvent(InputEvent event) {
4224   enqueueInputEvent(event, this, 0, true);
4225 }

This function will eventually call `doProcessInputEvents()` (line 4147) which will then call `deliverInputEvent(...)` (line 3109) which will then call `deliverKeyEvent(...)` (line 3495). Finally, the event will be dispatch to the `View` object by calling `mView.dispatchKeyEvent(event)` (line 3575).

Now, the question is how the system `WindowManagerService` object detects events from the kernel? It is actually quite simple, it polls several device files (e.g. /dev/input/eventX) exposed by the kernel. For more details, refer to this [blog](http://cjix.info/blog/misc/internal-input-event-handling-in-the-linux-kernel-and-the-android-userspace/).
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: