Android中的事件包括两类,Touch触摸事件和Key按键事件,我们都知道事件会先传递给Activity,但事件不是凭空产生的,那么它是从哪里传递到Activity的呢?
Android中的事件,在底层涉及到InputReader,InputDispatcher,InputManager,EventHub。在上层涉及到Window,Activity,ViewGroup,View。
它们是怎么传递的呢?传递则涉及到InputChannel,InputEventReceiver。
Source
驱动层:
1 2 3 4 5
| /frameworks/native/services/inputflinger/ InputReader.cpp (Thread) InputDispatcher.cpp (Thread) InputManager.cpp EventHub.cpp
|
中间传输层:
1 2 3
| /frameworks/base/core/jni/ android_view_InputChannel.cpp android_view_InputEventReceiver.cpp
|
应用层:
dispatchTouchEvent下行流程:
1
| Activity -> ViewGroup -> ViewGroup.onInterceptTouchEvent -> View -> View.onTouchEvent -> ViewGroup.onTouchEvent;
|
InputManagerService的创建是在SystemServer#startOtherServices中,直接通过new
InputManagerService()创建实例对象,然后调用IMS#nativeInit()方法来对底层进行初始化。
1 2 3 4 5 6 7 8 9 10
| SystemServer#startOtherServices { ims = new InputManagerService() { nativeInit(this, mContext, mHandler.getLooper().getQueue()); LocalServices.addService(InputManagerInternal.class, new LocalService()); } ims.setWindowManagerCallbacks(wm.getInputMonitor()); ims.start(); }
|
InputManagerService构造函数中的主要工作
- 创建一个InputDispatcher对象用于分发事件
- 创建一个InputReader对象用于读事件并把事件交给InputDispatcher分发
- 调用initialize()初始化,其实也就是创建了InputReaderThread和InputDispatcherThread。
事件传递
使用InputEventReceiver和InputChannel传递事件。
ViewRootImpl#setView中创建InputEventReceiver。
1 2 3 4 5 6
| if (mInputQueueCallback != null) { mInputQueue = new InputQueue(); mInputQueueCallback.onInputQueueCreated(mInputQueue); } mInputEventReceiver = new WindowInputEventReceiver(mInputChannel, Looper.myLooper());
|
InputEventReceiver.java
1 2 3 4 5 6 7 8 9 10
| @SuppressWarnings("unused") private void dispatchInputEvent(int seq, InputEvent event, int displayId) { onInputEvent(event, displayId); } public void onInputEvent(InputEvent event, int displayId) { finishInputEvent(event, false); }
|
底层android_view_InputEventReceiver.cpp中有个for循环,如果捕获到输入事件,则通过Java层dispatchInputEvent方法的methodId,调用到Java层的dispatchInputEvent方法,这样就将事件从native层传递到了Java层。
InputEventReceiver接收到的事件,并不是InputDispatcher直接调用到了InputEventReceiver的方法,从上面的创建过程可以得知,InputEventReceiver是运行于应用程序进程内的,而事件是产生在系统进程的,这中间涉及到了进程通信,实际是它是使用InputChannel来通信的。
Linux本地socket,可以在进程间进行通信。
设置FocusWindow
事件从System_Process中,传递到应用程序进程中,怎么对应上需要接收事件的Window呢,这就是需要了解FocusWindow了。
1 2 3 4
| WMS.addWindow -> WMS.mInputMonitor.updateInputWindowsLw(false ); -> IMS.updateInputWindows -> IMS.setInputWindows
|
InputManagerService.java
1 2 3 4 5 6 7 8 9 10 11 12 13
| public void setInputWindows(InputWindowHandle[] windowHandles, InputWindowHandle focusedWindowHandle) { final IWindow newFocusedWindow = focusedWindowHandle != null ? focusedWindowHandle.clientWindow : null; if (mFocusedWindow != newFocusedWindow) { mFocusedWindow = newFocusedWindow; if (mFocusedWindowHasCapture) { setPointerCapture(false); } } nativeSetInputWindows(mPtr, windowHandles); }
|