本篇只会讲到触发ViewGroup的dispatchTouchEvent为止,因为接下去的一搜一大把,或者说有点基础的应该都了解。
-
从触摸开始
首先,请你打开命令行工具。输入
adb shell
进入到shell命令,然后输入getevent
,会监听打印触摸屏幕的event信息。add device 1: /dev/input/event5 name: "msm8974-taiko-mtp-snd-card Headset Jack" add device 2: /dev/input/event4 name: "msm8974-taiko-mtp-snd-card Button Jack" add device 3: /dev/input/event3 name: "hs_detect" add device 4: /dev/input/event1 name: "touch_dev" add device 5: /dev/input/event0 name: "qpnp_pon" add device 6: /dev/input/event2 name: "gpio-keys"
当你使出你的一阳指点击屏幕的时候,变回不断的去获取到你的点击事件,就像这样:
/dev/input/event1: 0000 0000 00000000 /dev/input/event1: 0003 0039 000005cf /dev/input/event1: 0003 0035 0000020b /dev/input/event1: 0003 0036 0000068d /dev/input/event1: 0000 0000 00000000 /dev/input/event1: 0003 0036 0000068c /dev/input/event1: 0003 0030 00000005 /dev/input/event1: 0000 0000 00000000 /dev/input/event1: 0003 0039 ffffffff /dev/input/event1: 0000 0000 00000000
这些操作全都是Linux Kernel去做的,只要你点击了屏幕了,硬件设备变回产生硬件终端,Kernel收到硬件终端之后,会对其进行加工,包装成event事件之后添加到/dev/input/目录下,就像如上所示的event1。
-
Android系统的监听
Android会不断的去监控/dev/input/目录下的所有的设备节点,一旦发现有新的设备节点可读时就会立马读出事件并进行处理。
-
WMS
而这里的复杂步骤涉及到frameWork层,我们就从WMS开始吧,
先是有SystemServer启动的WMS。SystemServer.java的startOtherServices()wm = WindowManagerService.main(context, inputManager, mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL, !mFirstBoot, mOnlyCore);
并且同样在这个方法中初始化了InputManagerService,掌管输入事件的服务。
inputManager = new InputManagerService(context);
我们看到
WindowManagerService
的main方法传入的就是这个inputManager。
在InputManagerService的构造方法中,用到了mPtr = nativeInit(this, mContext, mHandler.getLooper().getQueue());
native的方法,nativce层不是重点,我这边就快速的将过去了。
在frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
中(没有在本地编译过源码的同学可以去 http://androidxref.com/ 查看,基于当前最新的7.1.1)static jlong nativeInit(JNIEnv* env, jclass /* clazz */, jobject serviceObj, jobject contextObj, jobject messageQueueObj) { sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL) { jniThrowRuntimeException(env, "MessageQueue is not initialized."); return 0; } NativeInputManager* im = new NativeInputManager(contextObj, serviceObj, messageQueue->getLooper()); im->incStrong(0); eturn reinterpret_cast<jlong>(im); }
然后看内部类nativeInputManger
NativeInputManager::NativeInputManager(jobject contextObj, ... sp<EventHub> eventHub = new EventHub(); mInputManager = new InputManager(eventHub, this, this); }
我们看到创建了一个EventHub类,并且将其交给InputManger并生成一个InputManger对象。
/frameworks/native/services/inputflinger/InputManager.cppInputManager::InputManager( const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& readerPolicy, const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) { mDispatcher = new InputDispatcher(dispatcherPolicy); mReader = new InputReader(eventHub, readerPolicy, mDispatcher); initialize(); }
一个分发对象,一个reader对象,并且调用initialize方法
void InputManager::initialize() { mReaderThread = new InputReaderThread(mReader); mDispatcherThread = new InputDispatcherThread(mDispatcher); }
创建读线程和分发线程
至此,所有的初始化先都ok了,在SystemServer.java,创建了InputManagerService之后没几行就调用了
inputManager.start();
,public void start() { ... nativeStart(mPtr); ... }
又看到了native。。。来吧继续相当枯燥的native,我要快进了,我有点写的想吐。。
frameworks/base/services/core/jni/com_android_server_input_InputManagerService.cpp
static void nativeStart(JNIEnv* env, jclass /* clazz */, jlong ptr) { NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr); status_t result = im->getInputManager()->start(); if (result) { jniThrowRuntimeException(env, "Input manager could not be started."); } }
/frameworks/native/services/inputflinger/InputManager.cpp
status_t InputManager::start() { status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); if (result) { ALOGE("Could not start InputDispatcher thread due to error %d.", result); return result; } result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); if (result) { ALOGE("Could not start InputReader thread due to error %d.", result); mDispatcherThread->requestExit(); return result; } return OK; }
启动了读线程和分发线程
/frameworks/native/services/inputflinger/InputReader.cpp
bool InputReaderThread::threadLoop() { mReader->loopOnce(); return true; } void InputReader::loopOnce() { ... size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); ... }
不断的loop去通过EventHub去getEvents(越来越偏了,getEvents不继续往下了,知道这个深度已经对于非framework工程师来说已经够了)
在getEvents方法中去从dev/input/目录下读取设备节点并加工,并返回给InputReader进行处理。之后的处理过程以及一系列跳转也是相当复杂,由于本文的初衷并非详解最底层的东西, 故而此处一并略过直接到底层将event回传给java层的最末
-
InputEventReceiver
在此我们只需要知道由InputChannel构建起了UI进程和底层system_server进程的socket通道。
最终会从NativeInputEventReceiver.cpp处调起InputEventReceiver的方法// Called from native code. @SuppressWarnings("unused") private void dispatchInputEvent(int seq, InputEvent event) { mSeqMap.put(event.getSequenceNumber(), seq); onInputEvent(event); }
InputEventReceiver是个抽象类,我们在ViewRootImpl中定义了如下
final class WindowInputEventReceiver extends InputEventReceiver { public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) { super(inputChannel, looper); } @Override public void onInputEvent(InputEvent event) { enqueueInputEvent(event, this, 0, true); } @Override public void onBatchedInputEventPending() { if (mUnbufferedInputDispatch) { super.onBatchedInputEventPending(); } else { scheduleConsumeBatchedInput(); } } @Override public void dispose() { unscheduleConsumeBatchedInput(); super.dispose(); } }
那么我们就看看enqueueInputEvent到底做了些什么操作:
void enqueueInputEvent(InputEvent event, InputEventReceiver receiver, int flags, boolean processImmediately) { ... if (processImmediately) { doProcessInputEvents(); } else { scheduleProcessInputEvents(); } } void doProcessInputEvents() { while (mPendingInputEventHead != null) { ... deliverInputEvent(q); } ... } private void deliverInputEvent(QueuedInputEvent q) { ... if (stage != null) { stage.deliver(q); } else { finishInputEvent(q); } }
最终就在这个deliver方法中,而这个stage是个InputStage对象,这个类内部是链表结构,最终会将q分发到可以处理的窗口ViewPostImeInputStage,由它的processPointerEvent方法来处理
private int processPointerEvent(QueuedInputEvent q) { final MotionEvent event = (MotionEvent)q.mEvent; final View eventTarget = (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ? mCapturingView : mView; ... boolean handled = eventTarget.dispatchPointerEvent(event); ... return handled ? FINISH_HANDLED : FORWARD; }
调用的view的dispatchPointerEvent方法:
public final boolean dispatchPointerEvent(MotionEvent event) { if (event.isTouchEvent()) { return dispatchTouchEvent(event); } else { return dispatchGenericMotionEvent(event); } }
而我们知道,window的最底层的View就是DecorView,那么这个时候调用的应该就是DecorView的dispatchTouchEvent方法
@Override public boolean dispatchTouchEvent(MotionEvent ev) { final Window.Callback cb = mWindow.getCallback(); return cb != null && !mWindow.isDestroyed() && mFeatureId < 0 ? cb.dispatchTouchEvent(ev) : super.dispatchTouchEvent(ev); }
还记的callBack是谁么,在Activity的attach方法中,
mWindow.setCallback(this);
这个callback就是activity本身,所以我们要去Activity中查看它的dispatchTouchEvent方法public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { return true; } return onTouchEvent(ev); }
这里分了两步,先去getWindow().superDispatchTouchEvent(ev),这一步会从PhoneWindow->DecorView->ViewGroup(DecorView继承FrameLayout就是ViewGroup),最后实际上是触发了ViewGroup的dispatchTouchEvent方法,也就是activity会先将事件交给DecorView去处理,如果被消耗掉,就返回true。如果没有消耗这个事件,就回调Activity自己的onTouchEvent。
-
总结
-
那么把上面的一大坨我们简略的来讲如下的流程:
- 用户触摸屏幕产生设备节点中断并保存到/dev/input/目录下
- 底层的EventHub监听目录,将事件读出并加工返回给随着WMS一起启动的底层的InputReader
- InputReader处理加工之后交给InputDispatcher来进行分发,通过socket通知UI进程的InputEventReceiver接收到事件
- InputEventReceiver将回调事件一步步传递给Activity来进行分发
- Activity先将事件交给DecorView来进行处理,如果DecorView消耗则返回true,否则自己回调onTouchEvent方法
以上!