一、 初识Android输入系统

第4章通过分析WMS详细讨论了Android的窗口管理、布局及动画的工作机制。窗口不仅是内容绘制的载体,同时也是用户输入事件的目标。本章将详细讨论Android输入系统的工作原理,包括输入设备的管理、输入事件的加工方式以及派发流程。因此本章的探讨对象有两个:输入设备、输入事件。

触摸屏与键盘是Android最普遍也是最标准的输入设备。其实Android所支持的输入设备的种类不止这两个,鼠标、游戏手柄均在内建的支持之列。当输入设备可用时,Linux内核会在/dev/input/下创建对应的名为event0~n或其他名称的设备节点。而当输入设备不可用时,则会将对应的节点删除。在用户空间可以通过ioctl的方式从这些设备节点中获取其对应的输入设备的类型、厂商、描述等信息。

当用户操作输入设备时,Linux内核接收到相应的硬件中断,然后将中断加工成原始的输入事件数据并写入其对应的设备节点中,在用户空间可以通过read()函数将事件数据读出。

Android输入系统的工作原理概括来说,就是监控/dev/input/下的所有设备节点,当某个节点有数据可读时,将数据读出并进行一系列的翻译加工,然后在所有的窗口中寻找合适的事件接收者,并派发给它。

以Nexus4为例,其/dev/input/下有evnet0~5六个输入设备的节点。它们都是什么输入设备呢?用户的一次输入操作会产生什么样的事件数据呢?获取答案的最简单的办法就是是用getevent与sendevent工具。

  getevent与sendevent工具

Android系统提供了getevent与sendevent两个工具供开发者从设备节点中直接读取输入事件或写入输入事件。

getevent监听输入设备节点的内容,当输入事件被写入到节点中时,getevent会将其读出并打印在屏幕上。由于getevent不会对事件数据做任何加工,因此其输出的内容是由内核提供的最原始的事件。其用法如下:


adb shell getevent [-选项] [device_path]

其中device_path是可选参数,用以指明需要监听的设备节点路径。如果省略此参数,则监听所有设备节点的事件。

打开模拟器,执行adb shell getevent –t(-t参数表示打印事件的时间戳),并按一下电源键(不要松手),可以得到以下一条输出,输出的部分数值会因机型的不同而有所差异,但格式一致:


[   1262.443489] /dev/input/event0: 0001 0074 00000001

松开电源键时,又会产生以下一条输出:


[   1262.557130] /dev/input/event0: 0001 0074 00000000

时间戳、类型、代码、值便是原始事件的四项基本元素。除时间戳外,其他三项元素的实际意义依照设备类型及厂商的不同而有所区别。在本例中,类型0x01表示此事件为一条按键事件,代码0x74表示电源键的扫描码,值0x01表示按下,0x00则表示抬起。这两条原始数据被输入系统包装成两个KeyEvent对象,作为两个按键事件派发给Framework中感兴趣的模块或应用程序。


注意一条原始事件所包含的信息量是比较有限的。而在Android API中所使用的某些输入事件,如触摸屏点击/滑动,包含了很多的信息,如XY坐标,触摸点索引等,其实是输入系统整合了多个原始事件后的结果。这个过程将在5.2.4节中详细探讨。


为了对原始事件有一个感性的认识,读者可以在运行getevent的过程中尝试一下其他的输入操作,观察一下每种输入所对应的设备节点及四项元素的取值。

输入设备的节点不仅在用户空间可读,而且是可写的,因此可以将将原始事件写入到节点中,从而实现模拟用户输入的功能。sendevent工具的作用正是如此。其用法如下:


sendevent <节点路径> <类型><代码> <值>


可以看出,sendevent的输入参数与getevent的输出是对应的,只不过sendevent的参数为十进制。电源键的代码0x74的十进制为116,因此可以通过快速执行如下两条命令实现点击电源键的效果:


adb shell sendevent /dev/input/event0 1 116 1 #按下电源键
 adb shell sendevent /dev/input/event0 1 116 0 #抬起电源键

[1]

现在,读者对输入设备节点以及原始事件有了直观的认识,接下来看一下Android输入系统的基本原理。

  Android输入系统简介

上一节讲述了输入事件的源头是位于/dev/input/下的设备节点,而输入系统的终点是由WMS管理的某个窗口。最初的输入事件为内核生成的原始事件,而最终交付给窗口的则是KeyEvent或MotionEvent对象。因此Android输入系统的主要工作是读取设备节点中的原始事件,将其加工封装,然后派发给一个特定的窗口以及窗口中的控件。这个过程由InputManagerService(以下简称IMS)系统服务为核心的多个参与者共同完成。

输入系统的总体流程和参与者如图5-1所示。


input type ios 输入点 input phone_Android

图 5-1 输入系统的总体流程与参与者

图5-1描述了输入事件的处理流程以及输入系统中最基本的参与者。它们是:

·  Linux内核,接受输入设备的中断,并将原始事件的数据写入到设备节点中。

·  设备节点,作为内核与IMS的桥梁,它将原始事件的数据暴露给用户空间,以便IMS可以从中读取事件。

·  InputManagerService,一个Android系统服务,它分为Java层和Native层两部分。Java层负责与WMS的通信。而Native层则是InputReader和InputDispatcher两个输入系统关键组件的运行容器。

·  EventHub,直接访问所有的设备节点。并且正如其名字所描述的,它通过一个名为getEvents()的函数将所有输入系统相关的待处理的底层事件返回给使用者。这些事件包括原始输入事件、设备节点的增删等。

·  InputReader,I是IMS中的关键组件之一。它运行于一个独立的线程中,负责管理输入设备的列表与配置,以及进行输入事件的加工处理。它通过其线程循环不断地通过getEvents()函数从EventHub中将事件取出并进行处理。对于设备节点的增删事件,它会更新输入设备列表于配置。对于原始输入事件,InputReader对其进行翻译、组装、封装为包含了更多信息、更具可读性的输入事件,然后交给InputDispatcher进行派发。

·  InputReaderPolicy,它为InputReader的事件加工处理提供一些策略配置,例如键盘布局信息等。

·  InputDispatcher,是IMS中的另一个关键组件。它也运行于一个独立的线程中。InputDispatcher中保管了来自WMS的所有窗口的信息,其收到来自InputReader的输入事件后,会在其保管的窗口中寻找合适的窗口,并将事件派发给此窗口。

·  InputDispatcherPolicy,它为InputDispatcher的派发过程提供策略控制。例如截取某些特定的输入事件用作特殊用途,或者阻止将某些事件派发给目标窗口。一个典型的例子就是HOME键被InputDispatcherPolicy截取到PhoneWindowManager中进行处理,并阻止窗口收到HOME键按下的事件。

·  WMS,虽说不是输入系统中的一员,但是它却对InputDispatcher的正常工作起到了至关重要的作用。当新建窗口时,WMS为新窗口和IMS创建了事件传递所用的通道。另外,WMS还将所有窗口的信息,包括窗口的可点击区域,焦点窗口等信息,实时地更新到IMS的InputDispatcher中,使得InputDispatcher可以正确地将事件派发到指定的窗口。

·  ViewRootImpl,对于某些窗口,如壁纸窗口、SurfaceView的窗口来说,窗口即是输入事件派发的终点。而对于其他的如Activity、对话框等使用了Android控件系统的窗口来说,输入事件的终点是控件(View)。ViewRootImpl将窗口所接收到的输入事件沿着控件树将事件派发给感兴趣的控件。

简单来说,内核将原始事件写入到设备节点中,InputReader不断地通过EventHub将原始事件取出来并翻译加工成Android输入事件,然后交给InputDispatcher。InputDispatcher根据WMS提供的窗口信息将事件交给合适的窗口。窗口的ViewRootImpl对象再沿着控件树将事件派发给感兴趣的控件。控件对其收到的事件作出响应,更新自己的画面、执行特定的动作。所有这些参与者以IMS为核心,构建了Android庞大而复杂的输入体系。

Linux内核对硬件中断的处理超出了本书的讨论范围,因此本章将以IMS为重点,详细讨论除Linux内核以外的其他参与者的工作原理。

二、 代码讲解

2.1 输入系统的初始化,启动流程

先从java层的InputManagerService的创建开始,它是在SystemServer中创建:


1. inputManager = new InputManagerService(context);  
2.   
3. Slog.i(TAG, "Window Manager");  
4. wm = WindowManagerService.main(context, inputManager,  
5.         mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,  
6.         !mFirstBoot, mOnlyCore);  
7. ServiceManager.addService(Context.WINDOW_SERVICE, wm);  
8. ServiceManager.addService(Context.INPUT_SERVICE, inputManager);  
9.   
10. mActivityManagerService.setWindowManager(wm);  
11.   
12. inputManager.setWindowManagerCallbacks(wm.getInputMonitor());  
13. inputManager.start();


创建后,将自己传给windowManagerService, 然后调用了start函数。再来看看InputManagerService的构造函数:



1. public InputManagerService(Context context) {  
2. this.mContext = context;  
3. this.mHandler = new InputManagerHandler(DisplayThread.get().getLooper());  
4.   
5.     mUseDevInputEventForAudioJack =  
6.             context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);  
7. "Initializing input manager, mUseDevInputEventForAudioJack="  
8.             + mUseDevInputEventForAudioJack);  
9. this, mContext, mHandler.getLooper().getQueue());//注意这个mPtr是NativeInputManager对象指针  
10.   
11. class, new LocalService());  
12. }


构造函数里面还是主要看下nativeInit这个JNI接口。这个接口在com_android_server_input_InputManagerService.cpp文件中:



1. static jlong nativeInit(JNIEnv* env, jclass clazz,  
2.         jobject serviceObj, jobject contextObj, jobject messageQueueObj) {  
3.     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);  
4. if (messageQueue == NULL) {  
5. "MessageQueue is not initialized.");  
6. return 0;  
7.     }  
8.   
9. new NativeInputManager(contextObj, serviceObj,//注意传下来的serviceObj对象  
10.             messageQueue->getLooper());  
11. 0);  
12. return reinterpret_cast<jlong>(im);  
13. }


nativeInit中主要是new了一个NativeInputManager对象,而NativeInputManager对象中的serviceObj是java层的InputManagerService对象。

而NativeInputManager对象的构造函数如下:



1. NativeInputManager::NativeInputManager(jobject contextObj,  
2. const sp<Looper>& looper) :  
3. true) {  
4.     JNIEnv* env = jniEnv();  
5.   
6.     mContextObj = env->NewGlobalRef(contextObj);  
7.     mServiceObj = env->NewGlobalRef(serviceObj);  
8.   
9.     {  
10.         AutoMutex _l(mLock);  
11.         mLocked.systemUiVisibility = ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;  
12.         mLocked.pointerSpeed = 0;  
13. true;  
14. false;  
15.     }  
16.   
17. new EventHub();  
18. new InputManager(eventHub, this, this);  
19. }


创建了一个InputManager对象,并把自己传给了它。再来看看InputManager对象的构造函数:



1. InputManager::InputManager(  
2. const sp<EventHubInterface>& eventHub,  
3. const sp<InputReaderPolicyInterface>& readerPolicy,  
4. const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {  
5. new InputDispatcher(dispatcherPolicy);//前面把NativeInputManager的对象传了进来,就是dispatcherPolicy和readerPolicy  
6. new InputReader(eventHub, readerPolicy, mDispatcher);  
7.     initialize();  
8. }

InputManager对象的构造函数中,创建了两个JNI层最重要的对象InputDispatcher,InputReader这两个对象有什么作用上面一节已经说过了。

initialize函数把reader和dispatch对象传进去了,建了两个线程。


1. void InputManager::initialize() {  
2. new InputReaderThread(mReader);  
3. new InputDispatcherThread(mDispatcher);  
4. }

2.2 InputReader InputDispatcher线程的run函数

初始化后就是start,java层的start比较简单。我们主要看下JNI的nativeStart


1. static void nativeStart(JNIEnv* env, jclass clazz, jlong ptr) {  
2. reinterpret_cast<NativeInputManager*>(ptr);  
3.   
4.     status_t result = im->getInputManager()->start();  
5. if (result) {  
6. "Input manager could not be started.");  
7.     }  
8. }

ptr就是java层InputManagerService保存的mPtr,这就到InputManager的start函数了。




1. status_t InputManager::start() {  
2. "InputDispatcher", PRIORITY_URGENT_DISPLAY);  
3. if (result) {  
4. "Could not start InputDispatcher thread due to error %d.", result);  
5. return result;  
6.     }  
7.   
8. "InputReader", PRIORITY_URGENT_DISPLAY);  
9. if (result) {  
10. "Could not start InputReader thread due to error %d.", result);  
11.   
12.         mDispatcherThread->requestExit();  
13. return result;  
14.     }  
15.   
16. return OK;  
17. }


InputManager的start函数没啥别的就是启动了两个线程。我们再来看看这两个线程:


1. bool InputReaderThread::threadLoop() {  
2.     mReader->loopOnce();  
3. return true;  
4. }

这种写法是ndk中的thread的写法,return true,就是继续循环。调用了InputReader的loopOnce函数:



1. void InputReader::loopOnce() {  
2. ............  
3.   
4. size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);  
5.   
6. // acquire lock  
7.         AutoMutex _l(mLock);  
8.         mReaderIsAliveCondition.broadcast();  
9.   
10. if (count) {  
11.             processEventsLocked(mEventBuffer, count);  
12.         }  
13.   
14. if (mNextTimeout != LLONG_MAX) {  
15.             nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);  
16. if (now >= mNextTimeout) {  
17.                 mNextTimeout = LLONG_MAX;  
18.                 timeoutExpiredLocked(now);  
19.             }  
20.         }  
21.   
22. if (oldGeneration != mGeneration) {  
23. true;  
24.             getInputDevicesLocked(inputDevices);  
25.         }  
26. // release lock  
27.   
28. // Send out a message that the describes the changed input devices.  
29. if (inputDevicesChanged) {  
30.         mPolicy->notifyInputDevicesChanged(inputDevices);  
31.     }  
32.   
33.     mQueuedListener->flush();  
34. }

这个函数挑重点的讲,第一个重要的函数getEvents是读取每个设备的数据形成RawEvent,放入buffer中,如果没有输入事件,就epoll_wait函数阻塞等待。

因此InputReaderThread大部分的时间在epoll_wait上,有输入设备事件到来。唤醒线程,读数据封装成RawEvent,放在mEventBuffer中然后调用processEventsLocked。具体的getEvents函数就不看了,也比较长。

看下processEventsLocked函数



1. void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {  
2. for (const RawEvent* rawEvent = rawEvents; count;) {  
3.         int32_t type = rawEvent->type;  
4. size_t batchSize = 1;  
5. if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {  
6.             int32_t deviceId = rawEvent->deviceId;  
7. while (batchSize < count) {  
8. if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT  
9.                         || rawEvent[batchSize].deviceId != deviceId) {  
10. break;  
11.                 }  
12.                 batchSize += 1;  
13.             }  
14. #if DEBUG_RAW_EVENTS  
15. "BatchSize: %d Count: %d", batchSize, count);  
16. #endif  
17.             processEventsForDeviceLocked(deviceId, rawEvent, batchSize);  
18. else {  
19. switch (rawEvent->type) {  
20. case EventHubInterface::DEVICE_ADDED://增加设备  
21.                 addDeviceLocked(rawEvent->when, rawEvent->deviceId);  
22. break;  
23. case EventHubInterface::DEVICE_REMOVED://移除设备  
24.                 removeDeviceLocked(rawEvent->when, rawEvent->deviceId);  
25. break;  
26. case EventHubInterface::FINISHED_DEVICE_SCAN://扫描设备结束  
27. //处理设备的配置文件  
28. break;  
29. default:  
30. false); // can't happen  
31. break;  
32.             }  
33.         }  
34.         count -= batchSize;  
35.         rawEvent += batchSize;  
36.     }  
37. }

这个函数处理RawEvent分成两类,一类是设备发生变化的Event,包括增加,移除,扫描设备结束;

另一类是设备自身产生的Event,比如按键的Event。这类Event,会从RawEvent的mEventBuffer中不断读取出来然后调用processEventsForDeviceLocked函数处理。




1. void InputReader::processEventsForDeviceLocked(int32_t deviceId,  
2. const RawEvent* rawEvents, size_t count) {  
3.     ssize_t deviceIndex = mDevices.indexOfKey(deviceId);  
4. if (deviceIndex < 0) {  
5. "Discarding event for unknown deviceId %d.", deviceId);  
6. return;  
7.     }  
8.   
9.     InputDevice* device = mDevices.valueAt(deviceIndex);  
10. if (device->isIgnored()) {  
11. //ALOGD("Discarding event for ignored deviceId %d.", deviceId);  
12. return;  
13.     }  
14.   
15.     device->process(rawEvents, count);  
16. }


processEventsForDeviceLocked函数根据deviceId得到InputDevice对象,然后调用其process函数



1. void InputDevice::process(const RawEvent* rawEvents, size_t count) {  
2. .........  
3. for (size_t i = 0; i < numMappers; i++) {  
4.                 InputMapper* mapper = mMappers[i];  
5.                 mapper->process(rawEvent);  
6.             }  
7.         }  
8. .........  
9. }


process函数处理RawEvent会对每个RawEvent调用它的所有的InputMaper对象的process函数,我们就看其中一种



1. void KeyboardInputMapper::process(const RawEvent* rawEvent) {  
2. switch (rawEvent->type) {  
3. case EV_KEY: {//按键事件  
4.         int32_t scanCode = rawEvent->code;  
5.         int32_t usageCode = mCurrentHidUsage;  
6.         mCurrentHidUsage = 0;  
7.   
8. if (isKeyboardOrGamepadKey(scanCode)) {  
9.             int32_t keyCode;  
10.             uint32_t flags;  
11. if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) {  
12.                 keyCode = AKEYCODE_UNKNOWN;  
13.                 flags = 0;  
14.             }  
15.             processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);  
16.         }  
17. break;  
18.     }  
19.     ........  
20. }


会调用processKey函数:最后会调用getListener()->notifyKey(&args);

这边的这个listener是QueuedInputListener,而processKey最后调用的notifyKey,就是把数据保存在mArgsQueue中。




1. void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {  
2. new NotifyKeyArgs(*args));  
3. }


回到前面的loopOnce函数,最后调用了mQueuedInputListener->flush();



1. void QueuedInputListener::flush() {  
2. size_t count = mArgsQueue.size();  
3. for (size_t i = 0; i < count; i++) {  
4.         NotifyArgs* args = mArgsQueue[i];  
5.         args->notify(mInnerListener);  
6. delete args;  
7.     }  
8.     mArgsQueue.clear();  
9. }


1. void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {  
2. this);  
3. }

最后还是调用了InputDispatcher的notifyKey函数




1. void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {  
2. ...........  
3.   
4.     KeyEvent event;  
5.     event.initialize(args->deviceId, args->source, args->action,  
6.             flags, keyCode, args->scanCode, metaState, 0,  
7.             args->downTime, args->eventTime);  
8.   
9. /*byref*/ policyFlags);//最后是调到phoneWindowManager中去对按键进行过滤  
10.       
11.   
12. bool needWake;  
13. // acquire lock  
14.         mLock.lock();  
15.   
16. if (shouldSendKeyToInputFilterLocked(args)) {  
17.             mLock.unlock();  
18.   
19.             policyFlags |= POLICY_FLAG_FILTERED;  
20. if (!mPolicy->filterInputEvent(&event, policyFlags)) {  
21. "kangchen filterInputEvent return");  
22. return; // event was consumed by the filter  
23.             }  
24.   
25.             mLock.lock();  
26.         }  
27.   
28.         int32_t repeatCount = 0;  
29. new KeyEntry(args->eventTime,  
30.                 args->deviceId, args->source, policyFlags,  
31.                 args->action, flags, keyCode, args->scanCode,  
32.                 metaState, repeatCount, args->downTime);  
33.   
34.         needWake = enqueueInboundEventLocked(newEntry);  
35.         mLock.unlock();  
36. // release lock  
37.   
38. if (needWake) {  
39. "kangchen needWake.");  
40.         mLooper->wake();  
41.     }  
42. }


这个函数我们也主要挑重点说,我们先看mPolicy->interceptKeyBeforeQueueing,这里的mPolicy就是nativeInputManager




1. void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,  
2.         uint32_t& policyFlags) {  
3. // Policy:  
4. // - Ignore untrusted events and pass them along.  
5. // - Ask the window manager what to do with normal events and trusted injected events.  
6. // - For normal events wake and brighten the screen if currently off or dim.  
7. if (mInteractive) {  
8.         policyFlags |= POLICY_FLAG_INTERACTIVE;  
9.     }  
10. if ((policyFlags & POLICY_FLAG_TRUSTED)) {  
11.         nsecs_t when = keyEvent->getEventTime();  
12.         JNIEnv* env = jniEnv();  
13.         jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);  
14.         jint wmActions;  
15. if (keyEventObj) {  
16. //直接是到phoneWindowManager中的interceptKeyBeforeQueueing函数  
17.                     gServiceClassInfo.interceptKeyBeforeQueueing,  
18.                     keyEventObj, policyFlags);  
19. if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {  
20.                 wmActions = 0;  
21.             }  
22.             android_view_KeyEvent_recycle(env, keyEventObj);  
23.             env->DeleteLocalRef(keyEventObj);  
24. else {  
25. "Failed to obtain key event object for interceptKeyBeforeQueueing.");  
26.             wmActions = 0;  
27.         }  
28.   
29. /*byref*/ policyFlags);  
30. else {  
31. if (mInteractive) {  
32.             policyFlags |= POLICY_FLAG_PASS_TO_USER;  
33.         }  
34.     }  
35. }

再来看看handleInterceptActions函数


1. void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,  
2.         uint32_t& policyFlags) {  
3. if (wmActions & WM_ACTION_PASS_TO_USER) {//这位是1  
4.         policyFlags |= POLICY_FLAG_PASS_TO_USER;  
5. else {//也就是说wmActions如果没有WM_ACTION_PASS_TO_USER这标志位就不会传到应用的线程去了。  
6. "kangchen handleInterceptActions: Not passing key to user.");  
7.     }  
8. }

再来看看phoneWindowManager中的interceptKeyBeforeQueueing函数中的一段,如果是power,result返回值就是~ACTION_PASS_TO_USER



1.       case KeyEvent.KEYCODE_POWER: {  
2.           result &= ~ACTION_PASS_TO_USER;  
3. false; // wake-up will be handled separately  
4. if (down) {  
5. Log.i(TAG, "PowerKey down, interactive = " + interactive);  
6.               interceptPowerKeyDown(event, interactive);  
7. else {  
8. Log.i(TAG, "PowerKey up.");  
9.               interceptPowerKeyUp(event, interactive, canceled);  
10.           }  
11. break;  
12.       }  
13.   
14. case KeyEvent.KEYCODE_SLEEP: {  
15.           result &= ~ACTION_PASS_TO_USER;  
16. if (!mPowerManager.isInteractive()) {  
17. false; // suppress feedback if already non-interactive  
18.           }  
19.           mPowerManager.goToSleep(event.getEventTime(),  
20.                   PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);  
21. false;  
22. break;  
23.       }  
24.   
25. case KeyEvent.KEYCODE_WAKEUP: {  
26.           result &= ~ACTION_PASS_TO_USER;  
27. true;  
28. break;  
29.       }


结合整个InputDispatcher的notifyKey函数会先调用到PhoneWindowManager,把返回值result的标志位~ACTION_PASS_TO_USER。后面如果是这个标志位应该就不会传给应用的线程了。(这段代码较多比较复杂就不分析了)。继续看InputDispatcher的notifyKey函数


1.       needWake = enqueueInboundEventLocked(newEntry);//enqueueInboundEventLocked函数把keyEntry放在mInboundQueue  
2.       mLock.unlock();  
3. // release lock  
4.   
5. if (needWake) {  
6. ALOGE("kangchen needWake.");  
7.       mLooper->wake();  
8.   }

最后再调用mLooper->wake()来唤醒线程。looper机制的话wake是往管道写数据,epoll_wait监听这个管道的read端。这样就把线程唤醒了。
这样InputReader就分析好了,下面再来看InputDispatcher

InputDispatcherThread线程开启后,一直调用mDispatcher->dispatchOnce

1. bool InputDispatcherThread::threadLoop() {  
2.     mDispatcher->dispatchOnce();  
3. return true;  
4. }

我们来看看dispatchOnce函数:




1. void InputDispatcher::dispatchOnce() {  
2.     nsecs_t nextWakeupTime = LONG_LONG_MAX;  
3. // acquire lock  
4.         AutoMutex _l(mLock);  
5.         mDispatcherIsAliveCondition.broadcast();  
6.   
7. // Run a dispatch loop if there are no pending commands.  
8. // The dispatch loop might enqueue commands to run afterwards.  
9. if (!haveCommandsLocked()) {  
10.             dispatchOnceInnerLocked(&nextWakeupTime);  
11.         }  
12.   
13. // Run all pending commands if there are any.  
14. // If any commands were run then force the next poll to wake up immediately.  
15. if (runCommandsLockedInterruptible()) {  
16.             nextWakeupTime = LONG_LONG_MIN;  
17.         }  
18. // release lock  
19.   
20. // Wait for callback or timeout or wake.  (make sure we round up, not down)  
21.     nsecs_t currentTime = now();  
22. int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);  
23. //线程阻塞了,具体看looper机制。后面会分析  
24. }


也就是InputReader线程有发送数据后调用mLooper的wake函数,唤醒InputDispatcher线程来发送给应用线程信息。其中dipatchOnceInnerLocked就是分发信息的。

调用dipatchOnceInnerLocked的流程较多,这里就列下调用关系:

dispatchOnce -> dispatchOnceInnerLocked -> dispatchKeyLocked -> dispatchEventLocked -> prepareDispatchCycleLocked -> enqueueDispatchEntriesLocked

最后再调到startDispatchCycleLocked函数,当然这其中肯定有把phoneWindowManager过滤的按键处理的过程,如果是被phoneWindowManager处理的按键就不会发送到应用线程那里了。



1. void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,  
2. const sp<Connection>& connection) {  
3. ..........        
4. switch (eventEntry->type) {  
5. case EventEntry::TYPE_KEY: {  
6. static_cast<KeyEntry*>(eventEntry);  
7.   
8. // Publish the key event.  
9.             status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,  
10.                     keyEntry->deviceId, keyEntry->source,  
11.                     dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,  
12.                     keyEntry->keyCode, keyEntry->scanCode,  
13.                     keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,  
14.                     keyEntry->eventTime);  
15. break;  
16.         }  
17.         ........  
18.         }  
19. }


然后又调用了connection->inputPublisher.publishKeyEvent。我们再来跟下:

2.3 InputChannel的JNI层

这个connection从InputManagerService的registerInputChannel函数跟起:


1. public void registerInputChannel(InputChannel inputChannel,  
2.         InputWindowHandle inputWindowHandle) {  
3. if (inputChannel == null) {  
4. throw new IllegalArgumentException("inputChannel must not be null.");  
5.     }  
6.   
7. false);  
8. }

在 nativeRegisterInputChannel函数中又调用了,NativeInputManager的registerInputChannel,然后又到InputDispatcher的registerInputChannel函数


1. status_t status = im->registerInputChannel(  
2.            env, inputChannel, inputWindowHandle, monitor);

所以还是直接看


1. status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,  
2. const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {  
3. ..........  
4. new Connection(inputChannel, inputWindowHandle, monitor);//创建了一个connection  
5.   
6. int fd = inputChannel->getFd();  
7.         mConnectionsByFd.add(fd, connection);  
8.   
9. if (monitor) {  
10.             mMonitoringChannels.push(inputChannel);  
11.         }  
12.   
13. this);  
14. // release lock  
15.   
16. // Wake the looper because some connections have changed.  
17.     mLooper->wake();  
18. return OK;  
19. }

registerInputChannel函数中创建了一个connection。然后加入了mConnectionsByFd列表中。也就是存在多个connection。而在dispatchKeyLocked的时候调用函数findFocusedWindowTargetsLocked得到拥有焦点窗口的inputChannel,然后调用getConnectionIndexLocked函数得到mConnectionsByFd列表中和inputChannel关联的Connection的index。


1. ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {  
2.     ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd());  
3. if (connectionIndex >= 0) {  
4.         sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);  
5. if (connection->inputChannel.get() == inputChannel.get()) {  
6. return connectionIndex;  
7.         }  
8.     }  
9.   
10. return -1;  
11. }


得到index也就得到了connection,在startDispatchCycleLocked中connection->inputPublisher.publishKeyEvent


1. status_t InputPublisher::publishKeyEvent(  
2.         uint32_t seq,  
3.         int32_t deviceId,  
4.         int32_t source,  
5.         int32_t action,  
6.         int32_t flags,  
7.         int32_t keyCode,  
8.         int32_t scanCode,  
9.         int32_t metaState,  
10.         int32_t repeatCount,  
11.         nsecs_t downTime,  
12.         nsecs_t eventTime) {  
13. ...............  
14.   
15.     InputMessage msg;  
16.     msg.header.type = InputMessage::TYPE_KEY;  
17.     msg.body.key.seq = seq;  
18.     msg.body.key.deviceId = deviceId;  
19.     msg.body.key.source = source;  
20.     msg.body.key.action = action;  
21.     msg.body.key.flags = flags;  
22.     msg.body.key.keyCode = keyCode;  
23.     msg.body.key.scanCode = scanCode;  
24.     msg.body.key.metaState = metaState;  
25.     msg.body.key.repeatCount = repeatCount;  
26.     msg.body.key.downTime = downTime;  
27.     msg.body.key.eventTime = eventTime;  
28. return mChannel->sendMessage(&msg);  
29. }


最后调用了mChannel->sendMessage,这个mChannel是穿件Connection对象时的参数。在nativeRegisterInputChannel函数中,创建Connection的时候传入的。而这个InputChannel在nativeRegisterInputChannel函数中创建,调用android_view_InputChannel_getInputChannel函数得到的inputChannel对象。



1. sp<InputChannel> android_view_InputChannel_getInputChannel(JNIEnv* env, jobject inputChannelObj) {  
2.     NativeInputChannel* nativeInputChannel =  
3.             android_view_InputChannel_getNativeInputChannel(env, inputChannelObj);  
4. return nativeInputChannel != NULL ? nativeInputChannel->getInputChannel() : NULL;  
5. }


android_view_InputChannel_getNativeInputChannel函数会JNI反调JAVA层InputManagerService中的mPtr,InputChannel的Java层对象就保存在mPtr中。


1. static NativeInputChannel* android_view_InputChannel_getNativeInputChannel(JNIEnv* env,  
2.         jobject inputChannelObj) {  
3.     jlong longPtr = env->GetLongField(inputChannelObj, gInputChannelClassInfo.mPtr);  
4. return reinterpret_cast<NativeInputChannel*>(longPtr);  
5. }


那最后是调用了java层的InputChannel对象的native层的NativeInputChannel来sendMessage。但是这个java层的InputChannel又是在哪创建的呢?看下面一节

2.4 InputChannel java层

我们先来看ViewRootImpl的setView方法:



1. public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {  
2. if ((mWindowAttributes.inputFeatures  
3. 0) {  
4. new InputChannel();//新建Channel  
5.                 }  
6. try {  
7.                     mOrigWindowType = mWindowAttributes.type;  
8. true;  
9.                     collectViewAttributes();  
10.                     res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,  
11.                             getHostVisibility(), mDisplay.getDisplayId(),  
12.                             mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel);  
13.                 }

setView方法中会新建一个InputChannel,然后通过mWindowSession.addToDisplay方法传到WindowManagerService中。最总会调用WMS的addWindow方法。



1. public int addWindow(Session session, IWindow client, int seq,  
2. int viewVisibility, int displayId,  
3.         Rect outContentInsets, Rect outStableInsets, InputChannel outInputChannel) {  
4. ..............            
5. if (outInputChannel != null && (attrs.inputFeatures  
6. 0) {  
7.                 String name = win.makeInputChannelName();  
8.                 InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);  
9. 0]);  
10. 1].transferTo(outInputChannel);  
11.   
12.                 mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);  
13.             }  
14. ................  
15. }


addWindow方法中先调用了InputChannel.openInputChannelPair方法返回一个InputChannel的数组,然后将inputChannel[0]设置到win对象中。接着将inputChannel[1]装换成和客户端传过来的outInputChannel对象。最后再调用InputManagerService中的registerInputChannel方法。所以最后JNI层用的InputChannel就是这个inputChannel[0]。

那我们接下来看下openInputChannel方法:



1. public static InputChannel[] openInputChannelPair(String name) {  
2. if (name == null) {  
3. throw new IllegalArgumentException("name must not be null");  
4.     }  
5.   
6. if (DEBUG) {  
7. "Opening input channel pair '" + name + "'");  
8.     }  
9. return nativeOpenInputChannelPair(name);  
10. }

看JNI层



1. static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv* env,  
2.         jclass clazz, jstring nameObj) {  
3. const char* nameChars = env->GetStringUTFChars(nameObj, NULL);  
4.     String8 name(nameChars);  
5.     env->ReleaseStringUTFChars(nameObj, nameChars);  
6.   
7.     sp<InputChannel> serverChannel;  
8.     sp<InputChannel> clientChannel;  
9.     status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);  
10.   
11. if (result) {  
12.         String8 message;  
13. "Could not open input channel pair.  status=%d", result);  
14.         jniThrowRuntimeException(env, message.string());  
15. return NULL;  
16.     }  
17.   
18.     jobjectArray channelPair = env->NewObjectArray(2, gInputChannelClassInfo.clazz, NULL);  
19. if (env->ExceptionCheck()) {  
20. return NULL;  
21.     }  
22.   
23.     jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,  
24. new NativeInputChannel(serverChannel));  
25. if (env->ExceptionCheck()) {  
26. return NULL;  
27.     }  
28.   
29.     jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,  
30. new NativeInputChannel(clientChannel));  
31. if (env->ExceptionCheck()) {  
32. return NULL;  
33.     }  
34.   
35.     env->SetObjectArrayElement(channelPair, 0, serverChannelObj);  
36.     env->SetObjectArrayElement(channelPair, 1, clientChannelObj);  
37. return channelPair;  
38. }


先来看看InputChannel::openInputChannelPair函数,这个方法调用了soketpair创建了一对sokcet。然后用这两个socket创建了两个InputChannel对象。一个serverChannel一个clientChannel。



1. status_t InputChannel::openInputChannelPair(const String8& name,  
2.         sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {  
3. int sockets[2];  
4. if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {  
5.         status_t result = -errno;  
6. "channel '%s' ~ Could not create socket pair.  errno=%d",  
7.                 name.string(), errno);  
8.         outServerChannel.clear();  
9.         outClientChannel.clear();  
10. return result;  
11.     }  
12.   
13. int bufferSize = SOCKET_BUFFER_SIZE;  
14. sizeof(bufferSize));  
15. sizeof(bufferSize));  
16. sizeof(bufferSize));  
17. sizeof(bufferSize));  
18.   
19.     String8 serverChannelName = name;  
20. " (server)");  
21. new InputChannel(serverChannelName, sockets[0]);  
22.   
23.     String8 clientChannelName = name;  
24. " (client)");  
25. new InputChannel(clientChannelName, sockets[1]);  
26. return OK;  
27. }


接下来继续拿这两个Channel各自新建了NativeInputChannel,然后传给android_view_InputChannel_createInputChannel方法:



1. static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,  
2.         NativeInputChannel* nativeInputChannel) {  
3.     jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,  
4.             gInputChannelClassInfo.ctor);  
5. if (inputChannelObj) {  
6.         android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);  
7.     }  
8. return inputChannelObj;  
9. }


这个方法新建了一个java层的InputChannel对象,就是最后返回到java层的inputChannels[0]和inputChannels[1],然后再来看看android_view_InputChannel_setNativeInputChannel方法。



1. static void android_view_InputChannel_setNativeInputChannel(JNIEnv* env, jobject inputChannelObj,  
2.         NativeInputChannel* nativeInputChannel) {  
3.     env->SetLongField(inputChannelObj, gInputChannelClassInfo.mPtr,  
4. reinterpret_cast<jlong>(nativeInputChannel));  
5. }


原来这个方法就是把NativeInputChannel传给java层InputChannel的mPtr成员变量中去。也就是最后用来sendMessage的对象就是java层传下来的InputChannel对象中的mPtr成员。

简单理解就是把sokcetpair中的一个socket注册到JNI层,另一个给应用。

再来看看如何把inputChannels[1]传给应用的:

1. public void transferTo(InputChannel outParameter) {  
2. if (outParameter == null) {  
3. throw new IllegalArgumentException("outParameter must not be null");  
4.     }  
5.       
6.     nativeTransferTo(outParameter);  
7. }

JNI层:


1. static void android_view_InputChannel_nativeTransferTo(JNIEnv* env, jobject obj,  
2.         jobject otherObj) {  
3. if (android_view_InputChannel_getNativeInputChannel(env, otherObj) != NULL) {  
4. "java/lang/IllegalStateException",  
5. "Other object already has a native input channel.");  
6. return;  
7.     }  
8.   
9.     NativeInputChannel* nativeInputChannel =  
10.             android_view_InputChannel_getNativeInputChannel(env, obj);  
11.     android_view_InputChannel_setNativeInputChannel(env, otherObj, nativeInputChannel);  
12.     android_view_InputChannel_setNativeInputChannel(env, obj, NULL);  
13. }

这个函数的功能就是把调用对象的mPtr中的值,放到参数对象的mPtr中,并把调用对象的mPtr置为NULL。

这样客户端调用完addToDisplay后,作为入参传递的outInputChannel将会被赋值。也就是另一个socket传到客户端了。

这样整个JNI层的两个thread,再到DispatchThread给应用发按键消息都通了。

JNI的两个Thread还是在SystemServer进程中的,而通过socketpair这种进程间的通信方式给客户端。


2.5 客户端的接收

前面JNI层最后调用了InputChannel的sendMessge,最后是通过socket发送的。那我们再来看看客户端的接收。

前面说客户端调用addToDisplay后得到InputChannel对象后,接着又创建了WindowInputEventReceiver对象。


1.    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {  
2. .......  
3. if (mInputChannel != null) {  
4. if (mInputQueueCallback != null) {  
5. new InputQueue();  
6.                        mInputQueueCallback.onInputQueueCreated(mInputQueue);  
7.                    }  
8. new WindowInputEventReceiver(mInputChannel,  
9.                            Looper.myLooper());  
10.                }  
11. .....


再来看看WindowInputEventReceiver父类的构造函数


1. public InputEventReceiver(InputChannel inputChannel, Looper looper) {  
2. if (inputChannel == null) {  
3. throw new IllegalArgumentException("inputChannel must not be null");  
4.     }  
5. if (looper == null) {  
6. throw new IllegalArgumentException("looper must not be null");  
7.     }  
8.   
9.     mInputChannel = inputChannel;  
10.     mMessageQueue = looper.getQueue();  
11. new WeakReference<InputEventReceiver>(this),  
12.             inputChannel, mMessageQueue);  
13.   
14. "dispose");  
15. }

看看nativeInit函数



1. static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,  
2.         jobject inputChannelObj, jobject messageQueueObj) {  
3.     sp<InputChannel> inputChannel = android_view_InputChannel_getInputChannel(env,  
4.             inputChannelObj);  
5. if (inputChannel == NULL) {  
6. "InputChannel is not initialized.");  
7. return 0;  
8.     }  
9.   
10.     sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);  
11. if (messageQueue == NULL) {  
12. "MessageQueue is not initialized.");  
13. return 0;  
14.     }  
15.   
16. new NativeInputEventReceiver(env,  
17.             receiverWeak, inputChannel, messageQueue);  
18.     status_t status = receiver->initialize();  
19. if (status) {  
20.         String8 message;  
21. "Failed to initialize input event receiver.  status=%d", status);  
22.         jniThrowRuntimeException(env, message.string());  
23. return 0;  
24.     }  
25.   
26. // retain a reference for the object  
27. return reinterpret_cast<jlong>(receiver.get());  
28. }

nativeInit函数取得了java层的InputChannel对象和MessageQueue在native层对象的指针,然后用它们创建了NativeInputEventReceiver对象,调用了NativeInputEventReceiver::initialize函数。



1. status_t NativeInputEventReceiver::initialize() {  
2.     setFdEvents(ALOOPER_EVENT_INPUT);  
3. return OK;  
4. }


再来看看setFdEvents函数,把InputChannel里的fd放到looper中去,也就是将客户端的socket放入looper的epoll机制中,如果JNI层发通过socket发信息过来。就会用epoll机制唤醒线程,并且处理其事件。


1. void NativeInputEventReceiver::setFdEvents(int events) {  
2. if (mFdEvents != events) {  
3.         mFdEvents = events;  
4. int fd = mInputConsumer.getChannel()->getFd();  
5. if (events) {  
6. this, NULL);  
7. else {  
8.             mMessageQueue->getLooper()->removeFd(fd);  
9.         }  
10.     }  
11. }


下面我们来温习下looper机制:



1. int Looper::addFd(int fd, int ident, int events, const sp<LooperCallback>& callback, void* data) {  
2. ............  
3.   
4. int epollEvents = 0;  
5. if (events & EVENT_INPUT) epollEvents |= EPOLLIN;  
6. if (events & EVENT_OUTPUT) epollEvents |= EPOLLOUT;  
7.   
8. // acquire lock  
9.         AutoMutex _l(mLock);  
10.   
11.         Request request;  
12.         request.fd = fd;  
13.         request.ident = ident;  
14.         request.callback = callback;  
15.         request.data = data;  
16.   
17. struct epoll_event eventItem;  
18. sizeof(epoll_event)); // zero out unused members of data field union  
19.         eventItem.events = epollEvents;  
20.         eventItem.data.fd = fd;  
21.   
22.         ssize_t requestIndex = mRequests.indexOfKey(fd);  
23. if (requestIndex < 0) {  
24. int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, & eventItem);  
25. if (epollResult < 0) {  
26. "Error adding epoll events for fd %d, errno=%d", fd, errno);  
27. return -1;  
28.             }  
29.             mRequests.add(fd, request);  
30. else {  
31. int epollResult = epoll_ctl(mEpollFd, EPOLL_CTL_MOD, fd, & eventItem);//将当前fd加入到epoll中  
32. if (epollResult < 0) {  
33. "Error modifying epoll events for fd %d, errno=%d", fd, errno);  
34. return -1;  
35.             }  
36.             mRequests.replaceValueAt(requestIndex, request);  
37.         }  
38. // release lock  
39. return 1;  
40. }


addFd函数将参数fd加入epoll,然后在mRequests列表中加入一个Request对象,这个对象的events成员带有EPOLLIN标记,然后它的callBack成员变量指向NativeInputEventReceiver。以前分析looper机制的时候知道,线程处理消息循环会调用looper的poolOnce函数,而这个函数又会调用pollInner函数:



1. int Looper::pollInner(int timeoutMillis) {  
2. ..........  
3. struct epoll_event eventItems[EPOLL_MAX_EVENTS];  
4. int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);//事件到来  
5. ..........  
6. for (int i = 0; i < eventCount; i++) {  
7. int fd = eventItems[i].data.fd;  
8.         uint32_t epollEvents = eventItems[i].events;  
9. if (fd == mWakeReadPipeFd) {//管道事件,就是调用wakeup函数的  
10. if (epollEvents & EPOLLIN) {  
11.                 awoken();  
12. else {  
13. "Ignoring unexpected epoll events 0x%x on wake read pipe.", epollEvents);  
14.             }  
15. else {//其它事件,就包括InputChannel的socket  
16. //获取request的index  
17. if (requestIndex >= 0) {  
18. int events = 0;  
19. if (epollEvents & EPOLLIN) events |= EVENT_INPUT;  
20. if (epollEvents & EPOLLOUT) events |= EVENT_OUTPUT;  
21. if (epollEvents & EPOLLERR) events |= EVENT_ERROR;  
22. if (epollEvents & EPOLLHUP) events |= EVENT_HANGUP;  
23. //加入mResponses列表  
24. else {  
25. "Ignoring unexpected epoll events 0x%x on fd %d that is "  
26. "no longer registered.", epollEvents, fd);  
27.             }  
28.         }  
29.     }  
30. ............  
31.   
32. // Invoke all response callbacks.处理所有的mResponses元素  
33. for (size_t i = 0; i < mResponses.size(); i++) {  
34.         Response& response = mResponses.editItemAt(i);  
35. if (response.request.ident == POLL_CALLBACK) {  
36. int fd = response.request.fd;  
37. int events = response.events;  
38. void* data = response.request.data;  
39. int callbackResult = response.request.callback->handleEvent(fd, events, data);//调用回调事件  
40. if (callbackResult == 0) {  
41.                 removeFd(fd);  
42.             }  
43. // Clear the callback reference in the response structure promptly because we  
44. // will not clear the response vector itself until the next poll.  
45.             response.request.callback.clear();  
46.             result = POLL_CALLBACK;  
47.         }  
48.     }  
49. return result;  
50. }


看上面代码的注释,把客户端socket的fd加入客户端线程消息机制中的epoll,当有事件过来,最总会调用回调。也就会调用NativeInputEventReceiver::handleEvent函数:




1. int NativeInputEventReceiver::handleEvent(int receiveFd, int events, void* data) {  
2. ..........  
3.   
4. if (events & ALOOPER_EVENT_INPUT) {  
5.         JNIEnv* env = AndroidRuntime::getJNIEnv();  
6. false /*consumeBatches*/, -1, NULL);  
7. "handleReceiveCallback");  
8. return status == OK || status == NO_MEMORY ? 1 : 0;  
9.     }  
10.     ..........  
11. }


consumeEvents函数如下,先读取socket的信息然后反调java层WindowInputEventReceiver的dispatchInputEvent方法


1. status_t NativeInputEventReceiver::consumeEvents(JNIEnv* env,  
2. bool consumeBatches, nsecs_t frameTime, bool* outConsumedBatch) {  
3. ......  
4. for (;;) {  
5.         uint32_t seq;  
6.         InputEvent* inputEvent;  
7. //读取InputChannel的socket信息  
8.                 consumeBatches, frameTime, &seq, &inputEvent);  
9.         ........  
10. if (inputEventObj) {//反调java层的WindowInputEventReceiver的dispatchInputEvent方法  
11.                 env->CallVoidMethod(receiverObj.get(),  
12.                         gInputEventReceiverClassInfo.dispatchInputEvent, seq, inputEventObj);  
13. .....  
14. }

这是父类的方法,然后再到子类WindowInputEventReceiver的onInputEvent方法



1. private void dispatchInputEvent(int seq, InputEvent event) {  
2.     mSeqMap.put(event.getSequenceNumber(), seq);  
3.     onInputEvent(event);  
4. }

WindowInputEventReceiver 类是在ViewRootImpl.java中是一个内部类:


1. final class WindowInputEventReceiver extends InputEventReceiver {  
2. public WindowInputEventReceiver(InputChannel inputChannel, Looper looper) {  
3. super(inputChannel, looper);  
4.     }  
5.   
6. @Override  
7. public void onInputEvent(InputEvent event) {  
8. this, 0, true);  
9.     }

enqueueInputEvent函数



1. void enqueueInputEvent(InputEvent event,  
2. int flags, boolean processImmediately) {  
3. "kangchen enqueueInputEvent");  
4.     QueuedInputEvent q = obtainQueuedInputEvent(event, receiver, flags);  
5.   
6. // Always enqueue the input event in order, regardless of its time stamp.  
7. // We do this because the application or the IME may inject key events  
8. // in response to touch events and we want to ensure that the injected keys  
9. // are processed in the order they were received and we cannot trust that  
10. // the time stamp of injected events are monotonic.  
11.     QueuedInputEvent last = mPendingInputEventTail;  
12. if (last == null) {  
13.         mPendingInputEventHead = q;  
14.         mPendingInputEventTail = q;  
15. else {  
16.         last.mNext = q;  
17.         mPendingInputEventTail = q;  
18.     }  
19. 1;  
20.     Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,  
21.             mPendingInputEventCount);  
22.   
23. if (processImmediately) {  
24.         doProcessInputEvents();  
25. else {  
26.         scheduleProcessInputEvents();  
27.     }  
28. }

这边都直接带过了,doProcessInputEvents函数中调用了deliverInputEvent函数



1. void doProcessInputEvents() {  
2. // Deliver all pending input events in the queue.  
3. while (mPendingInputEventHead != null) {  
4. "kangchen mPendingInputEventHead != null");  
5.         QueuedInputEvent q = mPendingInputEventHead;  
6.         mPendingInputEventHead = q.mNext;  
7. if (mPendingInputEventHead == null) {  
8. null;  
9.         }  
10. null;  
11.   
12. 1;  
13.         Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,  
14.                 mPendingInputEventCount);  
15.   
16.         deliverInputEvent(q);  
17.     }  
18.   
19. // We are done processing all input events that we can process right now  
20. // so we can clear the pending flag immediately.  
21. if (mProcessInputEventsScheduled) {  
22. false;  
23.         mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);  
24.


deliverInputEvent函数,进去上层InputState流程。



InputState流程就不多分析了,处理流程从NativeRreImeInputStage -> ViewPreImeStage -> ImeStage -> EarlyPostImeStage -> NativePostImeStage -> ViewPostImeInputStage -> SyntheticInputStage。

而我们分析下ViewPostImeInputStage:

InputStage的deliver函数会调用onProcess函数,我们就分析下ViewPostImeInputStage的onProcess函数

1. public final void deliver(QueuedInputEvent q) {  
2. if ((q.mFlags & QueuedInputEvent.FLAG_FINISHED) != 0) {  
3.         forward(q);  
4. else if (shouldDropInputEvent(q)) {  
5. false);  
6. else {  
7.         apply(q, onProcess(q));  
8.     }  
9. }



    1. final class ViewPostImeInputStage extends InputStage {  
    2. public ViewPostImeInputStage(InputStage next) {  
    3. super(next);  
    4.     }  
    5.   
    6. @Override  
    7. protected int onProcess(QueuedInputEvent q) {  
    8. if (q.mEvent instanceof KeyEvent) {  
    9. return processKeyEvent(q);//处理key事件  
    10. else {  
    11. // If delivering a new non-key event, make sure the window is  
    12. // now allowed to start updating.  
    13.             handleDispatchDoneAnimating();  
    14. final int source = q.mEvent.getSource();  
    15. if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {//触屏事件  
    16. return processPointerEvent(q);  
    17. else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {//轨迹球  
    18. return processTrackballEvent(q);  
    19. else {  
    20. return processGenericMotionEvent(q);  
    21.             }  
    22.         }  
    23.     }


    processKeyEvent函数


      1.         private int processKeyEvent(QueuedInputEvent q) {  
      2. final KeyEvent event = (KeyEvent)q.mEvent;  
      3.   
      4. if (event.getAction() != KeyEvent.ACTION_UP) {  
      5. // If delivering a new key event, make sure the window is  
      6. // now allowed to start updating.  
      7.                 handleDispatchDoneAnimating();  
      8.             }  
      9.   
      10. // Deliver the key to the view hierarchy.  
      11. if (mView.dispatchKeyEvent(event)) {  
      12. return FINISH_HANDLED;  
      13.             }  
      14. .....  
      15. }


      processKeyEvent函数会调用mView.dispatchKeyEvent函数,如果一个应用调的话,会优先调到应用自己实现的Activity中。

      下面随便举一个应用Activity的一个例子的一个dispatchKeyEvent函数:


      1. public boolean dispatchKeyEvent(KeyEvent event) {  
      2. int curpos = mTrackList.getSelectedItemPosition();  
      3. if (mPlaylist != null && !mPlaylist.equals("recentlyadded") && curpos >= 0 &&  
      4. 0 && event.getAction() == KeyEvent.ACTION_DOWN) {  
      5. switch (event.getKeyCode()) {//对KeyEvent的keycode处理  
      6. case KeyEvent.KEYCODE_DPAD_UP:  
      7. true);  
      8. return true;  
      9. case KeyEvent.KEYCODE_DPAD_DOWN:  
      10. false);  
      11. return true;  
      12. case KeyEvent.KEYCODE_DEL:  
      13.                 removeItem();  
      14. return true;  
      15.         }  
      16.     }  
      17.   
      18. return super.dispatchKeyEvent(event);//最后调用了父类的dispatchKeyEvent函数  
      19. }

      我们再来看看Acitivity的dispatchKeyEvent函数




      1. public boolean dispatchKeyEvent(KeyEvent event) {  
      2.     onUserInteraction();  
      3.   
      4. // Let action bars open menus in response to the menu key prioritized over  
      5. // the window handling it  
      6. if (event.getKeyCode() == KeyEvent.KEYCODE_MENU &&  
      7. null && mActionBar.onMenuKeyEvent(event)) {  
      8. return true;  
      9.     }  
      10.   
      11.     Window win = getWindow();  
      12. if (win.superDispatchKeyEvent(event)) {  
      13. return true;  
      14.     }  
      15.     View decor = mDecor;  
      16. if (decor == null) decor = win.getDecorView();  
      17. return event.dispatch(this, decor != null  
      18. null, this);  
      19. }


      再来看看KeyEvent的dispatch函数,这个receiver就只Activity本身,如果是应用调的话就是应用的Activity。


      1. public final boolean dispatch(Callback receiver) {  
      2. return dispatch(receiver, null, null);  
      3. }  
      4.   
      5. public final boolean dispatch(Callback receiver, DispatcherState state,  
      6.         Object target) {  
      7. switch (mAction) {  
      8. case ACTION_DOWN: {  
      9.             mFlags &= ~FLAG_START_TRACKING;  
      10. if (DEBUG) Log.v(TAG, "Key down to " + target + " in " + state  
      11. ": " + this);  
      12. boolean res = receiver.onKeyDown(mKeyCode, this);  
      13. if (state != null) {  
      14. if (res && mRepeatCount == 0 && (mFlags&FLAG_START_TRACKING) != 0) {  
      15. if (DEBUG) Log.v(TAG, "  Start tracking!");  
      16. this, target);  
      17. else if (isLongPress() && state.isTracking(this)) {  
      18. try {  
      19. if (receiver.onKeyLongPress(mKeyCode, this)) {  
      20. if (DEBUG) Log.v(TAG, "  Clear from long press!");  
      21. this);  
      22. true;  
      23.                         }  
      24. catch (AbstractMethodError e) {  
      25.                     }  
      26.                 }  
      27.             }  
      28. return res;  
      29.         }  
      30. case ACTION_UP:  
      31. if (DEBUG) Log.v(TAG, "Key up to " + target + " in " + state  
      32. ": " + this);  
      33. if (state != null) {  
      34. this);  
      35.             }  
      36. return receiver.onKeyUp(mKeyCode, this);  
      37. case ACTION_MULTIPLE:  
      38. final int count = mRepeatCount;  
      39. final int code = mKeyCode;  
      40. if (receiver.onKeyMultiple(code, count, this)) {  
      41. return true;  
      42.             }  
      43. if (code != KeyEvent.KEYCODE_UNKNOWN) {  
      44.                 mAction = ACTION_DOWN;  
      45. 0;  
      46. boolean handled = receiver.onKeyDown(code, this);  
      47. if (handled) {  
      48.                     mAction = ACTION_UP;  
      49. this);  
      50.                 }  
      51.                 mAction = ACTION_MULTIPLE;  
      52.                 mRepeatCount = count;  
      53. return handled;  
      54.             }  
      55. return false;  
      56.     }  
      57. return false;  
      58. }


      最总回到应用Activity的onKeyDown,onKeyUp中去。



      如此整个按键流程从InputManagerService到JNI到应用分析完了。