在Android系统中,键盘按键事件是由WindowManagerService服务来管理的,然后再以消息的形式来分发给应用程序处理,不过和普通消息不一样,它是由硬件中断触发的;在上一篇文章《Android应用程序消息处理机制(Looper、Handler)分析》中,我们分析了Android应用程序的消息处理机制,本文将结合这种消息处理机制来详细分析Android应用程序是如何获得键盘按键消息的。
在系统启动的时候,SystemServer会启动窗口管理服务WindowManagerService,WindowManagerService在启动的时候就会通过系统输入管理器InputManager来总负责监控键盘消息。这些键盘消息一般都是分发给当前激活的Activity窗口来处理的,因此,当前激活的Activity窗口在创建的时候,会到WindowManagerService中去注册一个接收键盘消息的通道,表明它要处理键盘消息,而当InputManager监控到有键盘消息时,就会分给给它处理。当当前激活的Activity窗口不再处于激活状态时,它也会到WindowManagerService中去反注册之前的键盘消息接收通道,这样,InputManager就不会再把键盘消息分发给它来处理。
由于本文的内容比较多,在接下面的章节中,我们将分为五个部分来详细描述Android应用程序获得键盘按键消息的过程,每一个部分都是具体描述键盘消息处理过程中的一个过程。结合上面的键盘消息处理框架,这四个过程分别是InputManager的启动过程、应用程序注册键盘消息接收通道的过程、InputManager分发键盘消息给应用程序的过程以及应用程序注销键盘消息接收通道的过程。为了更好地理解Android应用程序获得键盘按键消息的整个过程,建议读者首先阅读Android应用程序消息处理机制(Looper、Handler)分析一文,理解了Android应用程序的消息处理机制后,就能很好的把握本文的内容。
1. InputManager的启动过程分析
前面说过,Android系统的键盘事件是由InputManager来监控的,而InputManager是由窗口管理服务WindowManagerService来启动的。
从前面一篇文章Android系统进程Zygote启动过程的源代码分析中,我们知道在Android系统中,Zygote进程负责启动系统服务进程SystemServer,而系统服务进程SystemServer负责启动系统中的各种关键服务,例如我们在前面两篇文章Android应用程序安装过程源代码分析和Android系统默认Home应用程序(Launcher)的启动过程源代码分析中提到的Package管理服务PackageManagerService和Activity管理服务ActivityManagerService。这里我们所讨论的窗口管理服务WindowManagerService也是由SystemServer来启动的,具体的启动过程这里就不再详述了,具体可以参考PackageManagerService和ActivityManagerService的启动过程。
了解了WindowManagerService的启动过程之后,我们就可以继续分析InputManager的启动过程了。
Step 1. WindowManagerService.main
这个函数定义在frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java件中:
[java] view plain copy
1. public class WindowManagerService extends IWindowManager.Stub
2. implements Watchdog.Monitor {
3. ......
4.
5. public static WindowManagerServicemain(final Context context,
6. final InputManagerService im,
7. final boolean haveInputMethods,final boolean showBootMsgs,
8. final boolean onlyCore) {
9. final WindowManagerService[] holder =new WindowManagerService[1];
10. DisplayThread.getHandler().runWithScissors(newRunnable() {
11. @Override
12. public void run() {
13. holder[0] = newWindowManagerService(context, im,
14. haveInputMethods,showBootMsgs, onlyCore);
15. }
16. }, 0);
17. return holder[0];
18. }
19. ......
20. }
// 它通过一个线程WMThread实例来执行全局唯一的WindowManagerService实例的启动操作。这里调用//WMThread实例thr的start成员函数时,会进入到WMThread实例thr的run函数中去。
6.0的直接调用DisplayThread.getHandler().runWithScissors(new Runnable()的run来执行WindowManagerService实例的启动操作
Step 2. DisplayThread.getHandler().runWithScissors(newRunnable()的run被重写。
这个函数定义在frameworks/文base/services/core/java/com/android/server/wm/WindowManagerService.java文件中:
[java] view plain copy
1. @Override
2. public void run() {
3. holder[0] = newWindowManagerService(context, im,
4. haveInputMethods,showBootMsgs, onlyCore);
5. }
这里执行的主要操作就是创建一个WindowManagerService实例.
Step 3. InputManager的创建过程在SystemServer.java中进行。先进行实例化,然后再作为参数传给WindowManagerService.main,这点与作者2.3中的逻辑是不一样的。而且现在是InputManagerService替代了以前的InputManager 。
frameworks//base/services/java/com/android/server/SystemServer.java文件中:
[java] view plain copy
1. private void startOtherServices() {
2. ......
3. InputManagerService inputManager = null;
4. ......
5. Slog.i(TAG, "InputManager");
6. inputManager = new InputManagerService(context);
7.
8. Slog.i(TAG, "WindowManager");
9. wm =WindowManagerService.main(context, inputManager,
10. mFactoryTestMode !=FactoryTest.FACTORY_TEST_LOW_LEVEL,
11. !mFirstBoot, mOnlyCore);
12. ServiceManager.addService(Context.WINDOW_SERVICE,wm);
13. ServiceManager.addService(Context.INPUT_SERVICE,inputManager);
14. ......
Step 4. InputManagerservice<init>@java
Java层的InputManagerservice类的构造函数定义在frameworks//base/services/core/java/com/android/server/input/InputManagerService.java文件中:
[java] view plain copy
1. public InputManagerService(Context context) {
2. this.mContext = context;
3. this.mHandler = newInputManagerHandler(DisplayThread.get().getLooper());
4.
5. mUseDevInputEventForAudioJack =
6. context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
7. Slog.i(TAG, "Initializing inputmanager, mUseDevInputEventForAudioJack="
8. +mUseDevInputEventForAudioJack);
9. mPtr = nativeInit(this, mContext,mHandler.getLooper().getQueue());
10.
11. LocalServices.addService(InputManagerInternal.class,new LocalService());
12. }
这里只是简单地初始化InputManagerservice类的一些成员变量,然后调用init函数进一步执行初始化操作。
Step 5. InputManager.init
这个函数定义在frameworks//base/services/core/java/com/android/server/input/InputManagerService.java文件中:
[java] view plain copy
1. public InputManagerService(Context context) {
2. this.mContext = context;
3. this.mHandler = newInputManagerHandler(DisplayThread.get().getLooper());
4.
5. mUseDevInputEventForAudioJack =
6. context.getResources().getBoolean(R.bool.config_useDevInputEventForAudioJack);
7. Slog.i(TAG, "Initializing inputmanager, mUseDevInputEventForAudioJack="
8. +mUseDevInputEventForAudioJack);
9. mPtr = nativeInit(this, mContext,mHandler.getLooper().getQueue());
10.
11. LocalServices.addService(InputManagerInternal.class,new LocalService());
函数init通过调用本地方法nativeInit来执行C++层的相关初始化操作。
Step 6. InputManager.nativeInit
这个函数定义在frameworks/ base/services/core/jni/com_android_server_input_InputManagerService.cpp文件中:
[cpp] view plain copy
staticjlong 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);
return reinterpret_cast<jlong>(im);
}
这个函数的作用是创建一个NativeInputManager实例,并保存在gNativeInputManager变量中。由于是第一次调用到这里,因此,gNativeInputManager为NULL,于是就会new一个NativeInputManager对象出来,这样就会执行NativeInputManager类的构造函数来执其它的初始化操作。
Step 7. NativeInputManager<init>
NativeInputManager类的构造函数定义在frameworks/ base/services/core/jni/com_android_server_input_InputManagerService.cpp文件中:
[cpp] view plain copy
NativeInputManager::NativeInputManager(jobjectcontextObj,
jobject serviceObj, constsp<Looper>& looper) :
mLooper(looper), mInteractive(true) {
JNIEnv* env = jniEnv();
mContextObj =env->NewGlobalRef(contextObj);
mServiceObj =env->NewGlobalRef(serviceObj);
{
AutoMutex _l(mLock);
mLocked.systemUiVisibility =ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE;
mLocked.pointerSpeed = 0;
mLocked.pointerGesturesEnabled = true;
mLocked.showTouches = false;
}
mInteractive = true;
sp<EventHub> eventHub = new EventHub();
mInputManager = new InputManager(eventHub, this, this);
}
这里只要是创建了一个EventHub实例,并且把这个EventHub作为参数来创建InputManager对象。注意,这里的InputManager类是定义在C++层的,和前面在Java层的InputManager不一样,不过它们是对应关系。EventHub类是真正执行监控键盘事件操作的地方,后面我们会进一步分析到,现在我们主要关心InputManager实例的创建过程,它会InputManager类的构造函数里面执行一些初始化操作。
Step 8. InputManager<init>@C++
C++层的InputManager类的构造函数定义在frameworks/native/services/inputflinger/InputManager.cpp 文件中:
[cpp] view plain copy
InputManager::InputManager(
const sp<EventHubInterface>& eventHub,
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
mDispatcher = new InputDispatcher(dispatcherPolicy);
mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
initialize();
}
这里主要是创建了一个InputDispatcher对象和一个InputReader对象,并且分别保存在成员变量mDispatcher和mReader中。InputDispatcher类是负责把键盘消息分发给当前激活的Activity窗口的,而InputReader类则是通过EventHub类来实现读取键盘事件的,后面我们会进一步分析。创建了这两个对象后,还要调用initialize函数来执行其它的初始化操作。
Step 9. InputManager.initialize
这个函数定义在frameworks/native/services/inputflinger/InputManager.cpp 文件中:
[cpp] view plain copy
1.
2. void InputManager::initialize() {
3. mReaderThread = newInputReaderThread(mReader);
4. mDispatcherThread = newInputDispatcherThread(mDispatcher);
5. }
这个函数创建了一个InputReaderThread线程实例和一个InputDispatcherThread线程实例,并且分别保存在成员变量mReaderThread和mDispatcherThread中。这里的InputReader实列mReader就是通过这里的InputReaderThread线程实列mReaderThread来读取键盘事件的,而InputDispatcher实例mDispatcher则是通过这里的InputDispatcherThread线程实例mDisptacherThread来分发键盘消息的。
至此,InputManager的初始化工作就完成了,在回到Step 3中继续分析InputManager的进一步启动过程之前,我们先来作一个小结,看看这个初始化过程都做什么事情:
A. 在Java层中的WindowManagerService中创建了一个InputManager对象,由它来负责管理Android应用程序框架层的键盘消息处理;
//这点6.0的有调整,InputManager的对象是直接在SystemServier.java中创建起来的。还有一点是对象的名字修改为了InputManagerService,以便于本地层的InputManger区分开来。
B. 在C++层也相应地创建一个InputManager本地对象来负责监控键盘事件;
C. 在C++层中的InputManager对象中,分别创建了一个InputReader对象和一个InputDispatcher对象,前者负责读取系统中的键盘消息,后者负责把键盘消息分发出去;
D. InputReader对象和一个InputDispatcher对象分别是通过InputReaderThread线程实例和InputDispatcherThread线程实例来实键盘消息的读取和分发的。
有了这些对象之后,万事就俱备了,回到Step 3中,调用InputManager类的start函数来执行真正的启动操作。
Step 10. InputManager.start
这个函数定义在frameworks/base/services/java/com/android/server/InputManager.java文件中:
[cpp] view plain copy
1. public class InputManager {
2. ......
3.
4. public void start() {
5. Slog.i(TAG, "Starting input manager");
6. nativeStart();
7. }
8.
9. ......
10. }
这个函数通过调用本地方法nativeStart来执行进一步的启动操作。
Step 11. InputManager.nativeStart
这个函数定义在frameworks/base/services/jni$ vicom_android_server_InputManager.cpp文件中:
[cpp] view plain copy
1.
2. static void nativeStart(JNIEnv* env, jclass/* clazz */, jlong ptr) {
3. NativeInputManager* im =reinterpret_cast<NativeInputManager*>(ptr);
4.
5. status_t result =im->getInputManager()->start();
6. if (result) {
7. jniThrowRuntimeException(env,"Input manager could not be started.");
8. }
9. }
这里的im对象是在前面的Step 6中创建的,通过它的getInputManager函数可以返回C++层的InputManager对象,接着调用这个InputManager对象的start函数。
Step 12. InputManager.start
这个函数定义在frameworks/ native/services/inputflinger/InputManager.cpp 文件中:
[cpp] view plain copy
1.
2. status_t InputManager::start() {
3. status_t result = mDispatcherThread->run("InputDispatcher",PRIORITY_URGENT_DISPLAY);
4. if(result) {
5. ALOGE("Could not startInputDispatcher thread due to error %d.", result);
6. return result;
7. }
8.
9. result = mReaderThread->run("InputReader",PRIORITY_URGENT_DISPLAY);
10. if(result) {
11. ALOGE("Could not start InputReaderthread due to error %d.", result);
12.
13. mDispatcherThread->requestExit();
14. return result;
15. }
16.
17. return OK;
18. }
这个函数主要就是分别启动一个InputDispatcherThread线程和一个InputReaderThread线程来读取和分发键盘消息的了。这里的InputDispatcherThread线程对象mDispatcherThread和InputReaderThread线程对象是在前面的Step 9中创建的,调用了它们的run函数后,就会进入到它们的threadLoop函数中去,只要threadLoop函数返回true,函数threadLoop就会一直被循环调用,于是这两个线程就起到了不断地读取和分发键盘消息的作用。
我们先来分析InputDispatcherThread线程分发消息的过程,然后再回过头来分析InputReaderThread线程读取消息的过程。
Step 13. InputDispatcherThread.threadLoop
这个函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp文件中:
[cpp] view plain copy
1.
2. bool InputDispatcherThread::threadLoop() {
3. mDispatcher->dispatchOnce();
4. return true;
5. }
6.
这里的成员变量mDispatcher即为在前面Step 8中创建的InputDispatcher对象,调用它的dispatchOnce成员函数执行一次键盘消息分发的操作。
Step 14. InputDispatcher.dispatchOnce
这个函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp文件中:
[cpp] view plain copy
1. void InputDispatcher::dispatchOnce() {
2. nsecs_t keyRepeatTimeout = mPolicy->getKeyRepeatTimeout();
3. nsecs_t keyRepeatDelay = mPolicy->getKeyRepeatDelay();
4.
5. nsecs_t nextWakeupTime = LONG_LONG_MAX;
6. { // acquire lock
7. AutoMutex _l(mLock);
8. dispatchOnceInnerLocked(keyRepeatTimeout, keyRepeatDelay, & nextWakeupTime);
9.
10. if (runCommandsLockedInterruptible()) {
11. nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
12. }
13. } // release lock
14.
15. // Wait for callback or timeout or wake. (make sure we round up, not down)
16. nsecs_t currentTime = now();
17. int32_t timeoutMillis;
18. if (nextWakeupTime > currentTime) {
19. uint64_t timeout = uint64_t(nextWakeupTime - currentTime);
20. timeout = (timeout + 999999LL) / 1000000LL;
21. timeoutMillis = timeout > INT_MAX ? -1 : int32_t(timeout);
22. } else {
23. timeoutMillis = 0;
24. }
25.
26. mLooper->pollOnce(timeoutMillis);
27. }
这个函数很简单,把键盘消息交给dispatchOnceInnerLocked函数来处理,这个过程我们在后面再详细分析,然后调用mLooper->pollOnce函数等待下一次键盘事件的发生。这里的成员变量mLooper的类型为Looper,它定义在C++层中,具体可以参考前面Android应用程序消息处理机制(Looper、Handler)分析一文。
Step 15. Looper.pollOnce
这个函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp文件中,具体可以参考前面Android应用程序消息处理机制(Looper、Handler)分析一文,这里就不再详述了。总的来说,就是在Looper类中,会创建一个管道,当调用Looper类的pollOnce函数时,如果管道中没有内容可读,那么当前线程就会进入到空闲等待状态;当有键盘事件发生时,InputReader就会往这个管道中写入新的内容,这样就会唤醒前面正在等待键盘事件发生的线程。
InputDispatcher类分发消息的过程就暂时分析到这里,后面会有更进一步的分析,现在,我们回到Step 12中,接着分析InputReader类读取键盘事件的过程。在调用了InputReaderThread线程类的run就函数后,同样会进入到InputReaderThread线程类的threadLoop函数中去。
Step 16. InputReaderThread.threadLoop
这个函数定义在frameworks/native/services/inputflinger/InputReader.cpp文件中:
[cpp] view plain copy
1. bool InputReaderThread::threadLoop() {
2. mReader->loopOnce();
3. return true;
4. }
这里的成员变量mReader即为在前面Step 8中创建的InputReader对象,调用它的loopOnce成员函数执行一次键盘事件的读取操作。
Step 17. InputReader.loopOnce
这个函数定义在frameworks/ native/services/inputflinger/InputReader.cpp文件中:
[cpp] view plain copy
1.
2. void InputReader::loopOnce() {
3. int32_t oldGeneration;
4. int32_t timeoutMillis;
5. bool inputDevicesChanged = false;
6. Vector<InputDeviceInfo> inputDevices;
7. {// acquire lock
8. AutoMutex _l(mLock);
9.
10. oldGeneration = mGeneration;
11. timeoutMillis = -1;
12.
13. uint32_t changes =mConfigurationChangesToRefresh;
14. if (changes) {
15. mConfigurationChangesToRefresh = 0;
16. timeoutMillis = 0;
17. refreshConfigurationLocked(changes);
18. } else if (mNextTimeout != LLONG_MAX) {
19. nsecs_t now =systemTime(SYSTEM_TIME_MONOTONIC);
20. timeoutMillis =toMillisecondTimeoutDelay(now, mNextTimeout);
21. }
22. } // release lock
23.
24. size_t count = mEventHub->getEvents(timeoutMillis,mEventBuffer, EVENT_BUFFER_SIZE);
25.
26. { // acquire lock
27. AutoMutex _l(mLock);
28. mReaderIsAliveCondition.broadcast();
29.
30. if (count) {
31. processEventsLocked(mEventBuffer,count);
32. }
33.
34. if (mNextTimeout != LLONG_MAX) {
35. nsecs_t now =systemTime(SYSTEM_TIME_MONOTONIC);
36. if (now >= mNextTimeout) {
37. #ifDEBUG_RAW_EVENTS
38. ALOGD("Timeout expired,latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
39. #endif
40. mNextTimeout = LLONG_MAX;
41. timeoutExpiredLocked(now);
42. }
43. }
44.
45. if (oldGeneration != mGeneration) {
46. inputDevicesChanged = true;
47. getInputDevicesLocked(inputDevices);
48. }
49. } // release lock
50.
51. // Send out a message that the describesthe changed input devices.
52. if (inputDevicesChanged) {
53. mPolicy->notifyInputDevicesChanged(inputDevices);
54. }
55.
56. // Flush queued events out to the listener.
57. // This must happen outside of the lockbecause the listener could potentially call
58. // back into the InputReader's methods,such as getScanCodeState, or become blocked
59. // on another thread similarly waiting toacquire the InputReader lock thereby
60. // resulting in a deadlock. This situation is actually quite plausiblebecause the
61. // listener is actually the inputdispatcher, which calls into the window manager,
62. // which occasionally calls into the inputreader.
63. mQueuedListener->flush();
64. }
这里通过成员函数mEventHub来负责键盘消息的读取工作,如果当前有键盘事件发生或者有键盘事件等待处理,通过mEventHub的getEvent函数就可以得到这个事件,然后交给process函数进行处理,这个函数主要就是唤醒前面的InputDispatcherThread线程,通知它有新的键盘事件发生了,它需要进行一次键盘消息的分发操作了,这个函数我们后面再进一步详细分析;如果没有键盘事件发生或者没有键盘事件等待处理,那么调用mEventHub的getEvent函数时就会进入等待状态。
Step 18. EventHub.getEvent
这个函数定义在frameworks/native/services/inputflinger/EventHub.cpp文件中:
[cpp] view plain copy
1. size_t EventHub::getEvents(int timeoutMillis,RawEvent* buffer, size_t bufferSize) {
2. ALOG_ASSERT(bufferSize >= 1);
3.
4. AutoMutex _l(mLock);
5.
6. struct input_event readBuffer[bufferSize];
7.
8. RawEvent* event = buffer;
9. size_t capacity = bufferSize;
10. bool awoken = false;
11. for(;;) {
12. nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
13.
14. // Reopen input devices if needed.
15. if (mNeedToReopenDevices) {
16. mNeedToReopenDevices = false;
17.
18. ALOGI("Reopening all inputdevices due to a configuration change.");
19.
20. closeAllDevicesLocked();
21. mNeedToScanDevices = true;
22. break; // return to the callerbefore we actually rescan
23. }
24.
25. // Report any devices that had lastbeen added/removed.
26. while (mClosingDevices) {
27. Device* device = mClosingDevices;
28. ALOGV("Reporting deviceclosed: id=%d, name=%s\n",
29. device->id,device->path.string());
30. mClosingDevices = device->next;
31. event->when = now;
32. event->deviceId = device->id== mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id;
33. event->type = DEVICE_REMOVED;
34. event += 1;
35. delete device;
36. mNeedToSendFinishedDeviceScan =true;
37. if (--capacity == 0) {
38. break;
39. }
40. }
41.
42. if (mNeedToScanDevices) {
43. mNeedToScanDevices = false;
44. scanDevicesLocked();
45. mNeedToSendFinishedDeviceScan =true;
46. }
47.
48. while (mOpeningDevices != NULL) {
49. Device* device = mOpeningDevices;
50. ALOGV("Reporting deviceopened: id=%d, name=%s\n",
51. device->id,device->path.string());
52. mOpeningDevices = device->next;
53. event->when = now;
54. event->deviceId = device->id== mBuiltInKeyboardId ? 0 : device->id;
55. event->type = DEVICE_ADDED;
56. event += 1;
57. mNeedToSendFinishedDeviceScan =true;
58. if (--capacity == 0) {
59. break;
60. }
61. }
62.
63. if (mNeedToSendFinishedDeviceScan) {
64. mNeedToSendFinishedDeviceScan =false;
65. event->when = now;
66. event->type =FINISHED_DEVICE_SCAN;
67. event += 1;
68. if (--capacity == 0) {
69. break;
70. }
71. }
72.
73. // Grab the next input event.
74. bool deviceChanged = false;
75. while (mPendingEventIndex <mPendingEventCount) {
76. const struct epoll_event&eventItem = mPendingEventItems[mPendingEventIndex++];
77. if (eventItem.data.u32 ==EPOLL_ID_INOTIFY) {
78. if (eventItem.events &EPOLLIN) {
79. mPendingINotify = true;
80. } else {
81. ALOGW("Receivedunexpected epoll event 0x%08x for INotify.", eventItem.events);
82. }
83. continue;
84. }
85.
86. if (eventItem.data.u32 ==EPOLL_ID_WAKE) {
87. if (eventItem.events &EPOLLIN) {
88. ALOGV("awoken after wake()");
89. awoken = true;
90. char buffer[16];
91. ssize_t nRead;
92. do {
93. nRead =read(mWakeReadPipeFd, buffer, sizeof(buffer));
94. } while ((nRead == -1 && errno== EINTR) || nRead == sizeof(buffer));
95. } else {
96. ALOGW("Receivedunexpected epoll event 0x%08x for wake read pipe.",
97. eventItem.events);
98. }
99. continue;
100. }
101.
102. ssize_t deviceIndex =mDevices.indexOfKey(eventItem.data.u32);
103. if (deviceIndex < 0) {
104. ALOGW("Received unexpectedepoll event 0x%08x for unknown device id %d.",
105. eventItem.events,eventItem.data.u32);
106. continue;
107. }
108.
109. Device* device =mDevices.valueAt(deviceIndex);
110. if (eventItem.events & EPOLLIN){
111. int32_t readSize = read(device->fd,readBuffer,
112. sizeof(structinput_event) * capacity);
113. if (readSize == 0 || (readSize< 0 && errno == ENODEV)) {
114. // Device was removedbefore INotify noticed.
115. ALOGW("could not getevent, removed? (fd: %d size: %" PRId32
116. " bufferSize:%zu capacity: %zu errno: %d)\n",
117. device->fd,readSize, bufferSize, capacity, errno);
118. deviceChanged = true;
119. closeDeviceLocked(device);
120. } else if (readSize < 0) {
121. if (errno != EAGAIN&& errno != EINTR) {
122. ALOGW("could notget event (errno=%d)", errno);
123. }
124. } else if ((readSize %sizeof(struct input_event)) != 0) {
125. ALOGE("could not getevent (wrong size: %d)", readSize);
126. } else {
127. int32_t deviceId =device->id == mBuiltInKeyboardId ? 0 : device->id;
128.
129. size_t count =size_t(readSize) / sizeof(struct input_event);
130. for (size_t i = 0; i <count; i++) {
131. struct input_event&iev = readBuffer[i];
132. ALOGV("%s got:time=%d.%06d, type=%d, code=%d, value=%d",
133. device->path.string(),
134. (int)iev.time.tv_sec, (int) iev.time.tv_usec,
135. iev.type,iev.code, iev.value);
136.
137. // Some input devicesmay have a better concept of the time
138. // when an input eventwas actually generated than the kernel
139. // which simplytimestamps all events on entry to evdev.
140. // This is a customAndroid extension of the input protocol
141. // mainly intended foruse with uinput based device drivers.
142. if (iev.type == EV_MSC){
143. if (iev.code == MSC_ANDROID_TIME_SEC) {
144. device->timestampOverrideSec= iev.value;
145. continue;
146. } else if (iev.code== MSC_ANDROID_TIME_USEC) {
147. device->timestampOverrideUsec =iev.value;
148. continue;
149. }
150. }
151. if(device->timestampOverrideSec || device->timestampOverrideUsec) {
152. iev.time.tv_sec =device->timestampOverrideSec;
153. iev.time.tv_usec =device->timestampOverrideUsec;
154. if (iev.type ==EV_SYN && iev.code == SYN_REPORT) {
155. device->timestampOverrideSec = 0;
156. device->timestampOverrideUsec= 0;
157. }
158. ALOGV("appliedoverride time %d.%06d",
159. int(iev.time.tv_sec),int(iev.time.tv_usec));
160. }
161.
162. // Use the timespecified in the event instead of the current time
163. // so that downstreamcode can get more accurate estimates of
164. // event dispatch latency from the timethe event is enqueued onto
165. // the evdev clientbuffer.
166. //
167. // The event'stimestamp fortuitously uses the same monotonic clock
168. // time base as the rest ofAndroid. The kernel event device driver
169. //(drivers/input/evdev.c) obtains timestamps using ktime_get_ts().
170. // ThesystemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere
171. // callsclock_gettime(CLOCK_MONOTONIC) which is implemented as a
172. // system call thatalso queries ktime_get_ts().
173. event->when =nsecs_t(iev.time.tv_sec) * 1000000000LL
174. +nsecs_t(iev.time.tv_usec) * 1000LL;
175. ALOGV("event time%" PRId64 ", now %" PRId64, event->when, now);
176.
177. // Bug 7291243: Add aguard in case the kernel generates timestamps
178. // that appear to befar into the future because they were generated
179. // using the wrongclock source.
180. //
181. // This can happenbecause when the input device is initially opened
182. // it has a defaultclock source of CLOCK_REALTIME. Anyinput events
183. // enqueued right afterthe device is opened will have timestamps
184. // generated usingCLOCK_REALTIME. We later set the clocksource
185. // to CLOCK_MONOTONICbut it is already too late.
186. //
187. // Invalid input eventtimestamps can result in ANRs, crashes and
188. // and other issuesthat are hard to track down. We must notlet them
189. // propagate throughthe system.
190. //
191. // Log a warning sothat we notice the problem and recover gracefully.
192. if (event->when>= now + 10 * 1000000000LL) {
193. //Double-check. Time may have moved on.
194. nsecs_t time =systemTime(SYSTEM_TIME_MONOTONIC);
195. if (event->when> time) {
196. ALOGW("Aninput event from %s has a timestamp that appears to "
197. "havebeen generated using the wrong clock source "
198. "(expectedCLOCK_MONOTONIC): "
199. "eventtime %" PRId64 ", current time %" PRId64
200. ",call time %" PRId64 ". "
201. "Usingcurrent time instead.",
202. device->path.string(),event->when, time, now);
203. event->when= time;
204. } else {
205. ALOGV("Eventtime is ok but failed the fast path and required "
206. "anextra call to systemTime: "
207. "eventtime %" PRId64 ", current time %" PRId64
208. ",call time %" PRId64 ".",
209. event->when,time, now);
210. }
211. }
212. event->deviceId =deviceId;
213. event->type =iev.type;
214. event->code =iev.code;
215. #ifndefMTK_EMULATOR_SUPPORT
216. if(gTouchFilterEnable)
217. {
218. if(gTouchFilterDefault){
219. intvelocity[3];
220. float velocity_para[12];
221. charbuf[PROPERTY_VALUE_MAX] = {0};
222. property_get("persist.sys.input.Touchfval",buf, "true");
223. if (strcmp(buf,"true")) {
224. sscanf(buf,"%d %d %d %f %f %f %f %f %f %f %f %f %f %f %f", &velocity[0],&velocity[1], &velocity[2],
225. &velocity_para[0],&velocity_para[1], &velocity_para[2], &velocity_para[3],
226. &velocity_para[4],&velocity_para[5], &velocity_para[6], &velocity_para[7],
227. &velocity_para[8],&velocity_para[9], &velocity_para[10], &velocity_para[11]);
228. ALOGD("Touchfilter: %d %d %d %f %f %f %f %f %f %f %f %f %f %f %f", velocity[0],velocity[1], velocity[2],
229. velocity_para[0],velocity_para[1], velocity_para[2], velocity_para[3],
230. velocity_para[4],velocity_para[5], velocity_para[6], velocity_para[7],
231. velocity_para[8],velocity_para[9], velocity_para[10], velocity_para[11]);
232. setTouchFilterPara(&velocity[0],&velocity_para[0], 3, 4);
233. }
234. gTouchFilterDefault= false;
235. }
236. touch_driver_event_filter(&iev);
237. }
238. #endif
239. event->value =iev.value;
240. event += 1;
241. capacity -= 1;
242. }
243. if (capacity == 0) {
244. // The result buffer is full. Reset the pending event index
245. // so we will try toread the device again on the next iteration.
246. mPendingEventIndex -=1;
247. break;
248. }
249. }
250. } else if (eventItem.events &EPOLLHUP) {
251. ALOGI("Removing device %sdue to epoll hang-up event.",
252. device->identifier.name.string());
253. deviceChanged = true;
254. closeDeviceLocked(device);
255. } else {
256. ALOGW("Received unexpectedepoll event 0x%08x for device %s.",
257. eventItem.events,device->identifier.name.string());
258. }
259. }
260.
261. // readNotify() will modify the list ofdevices so this must be done after
262. // processing all other events toensure that we read all remaining events
263. // before closing the devices.
264. if (mPendingINotify &&mPendingEventIndex >= mPendingEventCount) {
265. mPendingINotify = false;
266. readNotifyLocked();
267. deviceChanged = true;
268. }
269.
270. // Report added or removed devicesimmediately.
271. if (deviceChanged) {
272. continue;
273. }
274.
275. // Return now if we have collected anyevents or if we were explicitly awoken.
276. if (event != buffer || awoken) {
277. break;
278. }
279.
280. // Poll for events. Mind the wake lock dance!
281. // We hold a wake lock at all timesexcept during epoll_wait(). This worksdue to some
282. // subtle choreography. When a device driver has pending (unread)events, it acquires
283. // a kernel wake lock. However, once the last pending event has beenread, the device
284. // driver will release the kernel wakelock. To prevent the system from goingto sleep
285. // when this happens, the EventHubholds onto its own user wake lock while the client
286. // is processing events. Thus the system can only sleep if there areno events
287. // pending or currently beingprocessed.
288. //
289. // The timeout is advisory only. If the device is asleep, it will not wakejust to
290. // service the timeout.
291. mPendingEventIndex = 0;
292.
293. mLock.unlock(); // release lock beforepoll, must be before release_wake_lock
294. release_wake_lock(WAKE_LOCK_ID);
295.
296. int pollResult = epoll_wait(mEpollFd,mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis);
297.
298. acquire_wake_lock(PARTIAL_WAKE_LOCK,WAKE_LOCK_ID);
299. mLock.lock(); // reacquire lock afterpoll, must be after acquire_wake_lock
300.
301. if (pollResult == 0) {
302. // Timed out.
303. mPendingEventCount = 0;
304. break;
305. }
306.
307. if (pollResult < 0) {
308. // An error occurred.
309. mPendingEventCount = 0;
310.
311. // Sleep after errors to avoidlocking up the system.
312. // Hopefully the error istransient.
313. if (errno != EINTR) {
314. ALOGW("poll failed(errno=%d)\n", errno);
315. usleep(100000);
316. }
317. } else {
318. // Some events occurred.
319. mPendingEventCount =size_t(pollResult);
320. }
321. }
322.
323. //All done, return the number of events we read.
324. return event - buffer;
325. }
这个函数比较长,我们一步一步来分析。
首先,如果是第一次进入到这个函数中时,成员变量mOpened的值为false,于是就会调用openPlatformInput函数来打开系统输入设备,在本文中,我们主要讨论的输入设备就是键盘了。打开了这些输入设备文件后,就可以对这些输入设备进行是监控了。如果不是第一次进入到这个函数,那么就会分析当前有没有输入事件发生,如果有,就返回这个事件,否则就会进入等待状态,等待下一次输入事件的发生。在我们这个场景中,就是等待下一次键盘事件的发生了。
我们先分析openPlatformInput函数的实现,然后回过头来分析这个getEvent函数的具体的实现。
Step 19. EventHub.openPlatformInput
//6.0没有该接口。
这个函数定义在frameworks/ native/services/inputflinger/EventHub.cpp文件中:
[cpp] view plain copy
1. bool EventHub::openPlatformInput(void)
2. {
3. ......
4.
5. res = scanDir(device_path);
6. if(res < 0) {
7. LOGE("scan dir failed for %s\n", device_path);
8. }
9.
10. return true;
11. }
这个函数主要是扫描device_path目录下的设备文件,然后打开它们,这里的变量device_path定义在frameworks/ native/services/inputflinger/EventHub.cpp文件开始的地方:
[cpp] view plain copy
1. static const char *device_path = "/dev/input";
在设备目录/dev/input中,一般有三个设备文件存在,分别是event0、mice和mouse0设备文件,其中,键盘事件就包含在event0设备文件中了。
Step 20. EventHub.scanDir
这个函数定义在frameworks/ native/services/inputflinger/EventHub.cpp文件中:
[cpp] view plain copy
1.
2. status_t EventHub::scanDirLocked(constchar *dirname)
3. {
4. char devname[PATH_MAX];
5. char *filename;
6. DIR *dir;
7. struct dirent *de;
8. dir = opendir(dirname);
9. if(dir == NULL)
10. return -1;
11. strcpy(devname, dirname);
12. filename = devname + strlen(devname);
13. *filename++ = '/';
14. while((de = readdir(dir))) {
15. if(de->d_name[0] == '.' &&
16. (de->d_name[1] == '\0' ||
17. (de->d_name[1] == '.' &&de->d_name[2] == '\0')))
18. continue;
19. strcpy(filename, de->d_name);
20. openDeviceLocked(devname);
21. }
22. closedir(dir);
23. return 0;
24. }
25.
26. voidEventHub::requestReopenDevices() {
27. ALOGV("requestReopenDevices()called");
28.
29. AutoMutex _l(mLock);
30. mNeedToReopenDevices = true;
31. }
根据上面一步的分析,这个函数主要就是调用openDevice函数来分别打开/dev/input/event0、/dev/input/mice和/dev/input/mouse0三个设备文件了。
Step 21. EventHub.openDevice
这个函数定义在frameworks/ native/services/inputflinger/EventHub.cpp文件中:
[cpp] view plain copy
1. status_t EventHub::openDeviceLocked(constchar *devicePath) {
2. char buffer[80];
3. ......
4. //Configure virtual keys.
5. if((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
6. // Load the virtual keys for the touchscreen, if any.
7. // We do this now so that we can makesure to load the keymap if necessary.
8. status_t status =loadVirtualKeyMapLocked(device);
9. if (!status) {
10. device->classes |=INPUT_DEVICE_CLASS_KEYBOARD;
11. }
12. }
13.
14. //Load the key map.
15. //We need to do this for joysticks too because the key layout may specify axes.
16. status_t keyMapStatus = NAME_NOT_FOUND;
17. if(device->classes & (INPUT_DEVICE_CLASS_KEYBOARD |INPUT_DEVICE_CLASS_JOYSTICK)) {
18. // Load the keymap for the device.
19. keyMapStatus = loadKeyMapLocked(device);
20. }
21.
22. //Configure the keyboard, gamepad or virtual keyboard.
23. if(device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
24. // Register the keyboard as a built-inkeyboard if it is eligible.
25. if (!keyMapStatus
26. && mBuiltInKeyboardId ==NO_BUILT_IN_KEYBOARD
27. &&isEligibleBuiltInKeyboard(device->identifier,
28. device->configuration,&device->keyMap)) {
29. mBuiltInKeyboardId = device->id;
30. }
31. ......
32. //Register with epoll.
33. struct epoll_event eventItem;
34. memset(&eventItem, 0,sizeof(eventItem));
35. eventItem.events = EPOLLIN;
36. if(mUsingEpollWakeup) {
37. eventItem.events |= EPOLLWAKEUP;
38. }
39. eventItem.data.u32 = deviceId;
40. if(epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) {
41. ALOGE("Could not add device fd toepoll instance. errno=%d", errno);
42. delete device;
43. return -1;
44. }
45. ......
46. addDeviceLocked(device);
47. return 0;
48. }
判断是否为键盘,如果是的话,还要继续进一步初始化前面为这个设备文件所创建的device_t结构体,主要就是把结构体device的classes成员变量的INPUT_DEVICE_CLASS_KEYBOARD位置为1了,以表明这是一个键盘。
如果是键盘设备,初始化工作还未完成,还要继续设置键盘的布局等信息:
布局文件的加载
status_tEventHub::loadKeyMapLocked(Device* device) {
returndevice->keyMap.load(device->identifier, device->configuration);
}
keyMap.load又调用了Keyboard.cpp的KeyMap::load()方法
frameworks/native/libs/input/Keyboard.cpp
[cpp] view plain copy
1.
status_tKeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
const PropertyMap* deviceConfiguration){
// Use the configured key layout ifavailable.
if (deviceConfiguration) {
String8 keyLayoutName;
if(deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
keyLayoutName)) {
status_t status =loadKeyLayout(deviceIdenfifier, keyLayoutName);
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration forkeyboard device '%s' requested keyboard layout '%s' but "
"it was not found.",
deviceIdenfifier.name.string(), keyLayoutName.string());
}
}
String8 keyCharacterMapName;
if(deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
keyCharacterMapName)) {
status_t status =loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration forkeyboard device '%s' requested keyboard character "
"map '%s' but itwas not found.",
deviceIdenfifier.name.string(), keyLayoutName.string());
}
}
if (isComplete()) {
return OK;
}
}
// Try searching by device identifier.
if (probeKeyMap(deviceIdenfifier,String8::empty())) {
return OK;
}
// Fall back on the Generic key map.
// TODO Apply some additional heuristicshere to figure out what kind of
// generic key map to use (US English, etc.) for typical externalkeyboards.
if (probeKeyMap(deviceIdenfifier,String8("Generic"))) {
return OK;
}
// Try the Virtual key map as a lastresort.
if (probeKeyMap(deviceIdenfifier,String8("Virtual"))) {
return OK;
}
// Give up!
ALOGE("Could not determine key map fordevice '%s' and no default key maps were found!",
deviceIdenfifier.name.string());
return NAME_NOT_FOUND;
}
到这里,系统中的输入设备文件就打开了。
回到Step 18中,我们继续分析EventHub.getEvent函数的实现。
在中间的for循环里面,首先会检查当前是否有输入设备被关闭,如果有,就返回一个设备移除的事件给调用方:
[cpp] view plain copy
1. // Report any devices that had last been added/removed.
2. if (mClosingDevices != NULL) {
3. device_t* device = mClosingDevices;
4. LOGV("Reporting device closed: id=0x%x, name=%s\n",
5. device->id, device->path.string());
6. mClosingDevices = device->next;
7. if (device->id == mFirstKeyboardId) {
8. outEvent->deviceId = 0;
9. } else {
10. outEvent->deviceId = device->id;
11. }
12. outEvent->type = DEVICE_REMOVED;
13. outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
14. delete device;
15. mNeedToSendFinishedDeviceScan = true;
16. return true;
17. }
接着,检查当前是否有新的输入设备加入进来:
[cpp] view plain copy
1. if (mOpeningDevices != NULL) {
2. device_t* device = mOpeningDevices;
3. LOGV("Reporting device opened: id=0x%x, name=%s\n",
4. device->id, device->path.string());
5. mOpeningDevices = device->next;
6. if (device->id == mFirstKeyboardId) {
7. outEvent->deviceId = 0;
8. } else {
9. outEvent->deviceId = device->id;
10. }
11. outEvent->type = DEVICE_ADDED;
12. outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
13. mNeedToSendFinishedDeviceScan = true;
14. return true;
15. }
接着,再检查是否需要结束监控输入事件:
[cpp] view plain copy
1. if (mNeedToSendFinishedDeviceScan) {
2. mNeedToSendFinishedDeviceScan = false;
3. outEvent->type = FINISHED_DEVICE_SCAN;
4. outEvent->when = systemTime(SYSTEM_TIME_MONOTONIC);
5. return true;
6. }
最后,就是要检查当前是否有还未处理的输入设备事件发生了:
[cpp] view plain copy
1. // Grab the next input event.
2. bool deviceChanged = false;
3. while (mPendingEventIndex <mPendingEventCount) {
4. const struct epoll_event& eventItem= mPendingEventItems[mPendingEventIndex++];
5. if (eventItem.data.u32 ==EPOLL_ID_INOTIFY) {
6. if (eventItem.events &EPOLLIN) {
7. mPendingINotify = true;
8. } else {
9. ALOGW("Receivedunexpected epoll event 0x%08x for INotify.", eventItem.events);
10. }
11. continue;
12. }
13.
14. if (eventItem.data.u32 ==EPOLL_ID_WAKE) {
15. if (eventItem.events & EPOLLIN){
16. ALOGV("awoken afterwake()");
17. awoken = true;
18. char buffer[16];
19. ssize_t nRead;
20. do {
21. nRead =read(mWakeReadPipeFd, buffer, sizeof(buffer));
22. } while ((nRead == -1&& errno == EINTR) || nRead == sizeof(buffer));
23. } else {
24. ALOGW("Receivedunexpected epoll event 0x%08x for wake read pipe.",
25. eventItem.events);
26. }
27. continue;
28. }
29.
30. ssize_t deviceIndex =mDevices.indexOfKey(eventItem.data.u32);
31. if (deviceIndex < 0) {
32. ALOGW("Received unexpectedepoll event 0x%08x for unknown device id %d.",
33. eventItem.events,eventItem.data.u32);
34. continue;
35. }
36.
37. Device* device =mDevices.valueAt(deviceIndex);
38. if (eventItem.events & EPOLLIN) {
39. int32_t readSize =read(device->fd, readBuffer,
40. sizeof(structinput_event) * capacity);
41. if (readSize == 0 || (readSize< 0 && errno == ENODEV)) {
42. // Device was removed before INotifynoticed.
43. ALOGW("could not getevent, removed? (fd: %d size: %" PRId32
44. " bufferSize:%zu capacity: %zu errno: %d)\n",
45. device->fd, readSize,bufferSize, capacity, errno);
46. deviceChanged = true;
47. closeDeviceLocked(device);
48. } else if (readSize < 0) {
49. if (errno != EAGAIN&& errno != EINTR) {
50. ALOGW("could notget event (errno=%d)", errno);
51. }
52. } else if ((readSize %sizeof(struct input_event)) != 0) {
53. ALOGE("could not getevent (wrong size: %d)", readSize);
54. } else {
55. int32_t deviceId =device->id == mBuiltInKeyboardId ? 0 : device->id;
56.
57. size_t count =size_t(readSize) / sizeof(struct input_event);
58. for (size_t i = 0; i <count; i++) {
59. struct input_event&iev = readBuffer[i];
60. ALOGV("%s got:time=%d.%06d, type=%d, code=%d, value=%d",
61. device->path.string(),
62. (int)iev.time.tv_sec, (int) iev.time.tv_usec,
63. iev.type,iev.code, iev.value);
64.
65. // Some input devicesmay have a better concept of the time
66. // when an input eventwas actually generated than the kernel
67. // which simply timestamps all events onentry to evdev.
68. // This is a customAndroid extension of the input protocol
69. // mainly intended foruse with uinput based device drivers.
70. if (iev.type == EV_MSC){
71. if (iev.code ==MSC_ANDROID_TIME_SEC) {
72. device->timestampOverrideSec= iev.value;
73. continue;
74. } else if (iev.code== MSC_ANDROID_TIME_USEC) {
75. device->timestampOverrideUsec= iev.value;
76. continue;
77. }
78. }
79. if(device->timestampOverrideSec || device->timestampOverrideUsec) {
80. iev.time.tv_sec =device->timestampOverrideSec;
81. iev.time.tv_usec =device->timestampOverrideUsec;
82. if (iev.type ==EV_SYN && iev.code == SYN_REPORT) {
83. device->timestampOverrideSec= 0;
84. device->timestampOverrideUsec= 0;
85. }
86. ALOGV("appliedoverride time %d.%06d",
87. int(iev.time.tv_sec),int(iev.time.tv_usec));
88. }
89.
90. // Use the timespecified in the event instead of the current time
91. // so that downstreamcode can get more accurate estimates of
92. // event dispatchlatency from the time the event is enqueued onto
93. // the evdev clientbuffer.
94. //
95. // The event'stimestamp fortuitously uses the same monotonic clock
96. // time base as therest of Android. The kernel event devicedriver
97. //(drivers/input/evdev.c) obtains timestamps using ktime_get_ts().
98. // The systemTime(SYSTEM_TIME_MONOTONIC)function we use everywhere
99. // callsclock_gettime(CLOCK_MONOTONIC) which is implemented as a
100. // system call thatalso queries ktime_get_ts().
101. event->when =nsecs_t(iev.time.tv_sec) * 1000000000LL
102. +nsecs_t(iev.time.tv_usec) * 1000LL;
103. ALOGV("event time%" PRId64 ", now %" PRId64, event->when, now);
104.
105. // Bug 7291243: Add aguard in case the kernel generates timestamps
106. // that appear to befar into the future because they were generated
107. // using the wrongclock source.
108. //
109. // This can happenbecause when the input device is initially opened
110. // it has a defaultclock source of CLOCK_REALTIME. Anyinput events
111. // enqueued right afterthe device is opened will have timestamps
112. // generated usingCLOCK_REALTIME. We later set the clocksource
113. // to CLOCK_MONOTONICbut it is already too late.
114. //
115. // Invalid input eventtimestamps can result in ANRs, crashes and
116. // and other issuesthat are hard to track down. We must notlet them
117. // propagate throughthe system.
118. //
119. // Log a warning so that we notice theproblem and recover gracefully.
120. if (event->when>= now + 10 * 1000000000LL) {
121. //Double-check. Time may have moved on.
122. nsecs_t time =systemTime(SYSTEM_TIME_MONOTONIC);
123. if (event->when> time) {
124. ALOGW("Aninput event from %s has a timestamp that appears to "
125. "havebeen generated using the wrong clock source "
126. "(expectedCLOCK_MONOTONIC): "
127. "eventtime %" PRId64 ", current time %" PRId64
128. ",call time %" PRId64 ". "
129. "Usingcurrent time instead.",
130. device->path.string(),event->when, time, now);
131. event->when= time;
132. } else {
133. ALOGV("Eventtime is ok but failed the fast path and required "
134. "anextra call to systemTime: "
135. "eventtime %" PRId64 ", current time %" PRId64
136. ",call time %" PRId64 ".",
137. event->when,time, now);
138. }
139. }
140. event->deviceId =deviceId;
141. event->type = iev.type;
142. event->code =iev.code;
143. #ifndefMTK_EMULATOR_SUPPORT
144. if(gTouchFilterEnable)
145. {
146. if(gTouchFilterDefault){
147. intvelocity[3];
148. floatvelocity_para[12];
149. charbuf[PROPERTY_VALUE_MAX] = {0};
150. property_get("persist.sys.input.Touchfval",buf, "true");
151. if (strcmp(buf,"true")) {
152. sscanf(buf,"%d %d %d %f %f %f %f %f %f %f %f %f %f %f %f", &velocity[0],&velocity[1], &velocity[2],
153. &velocity_para[0],&velocity_para[1], &velocity_para[2], &velocity_para[3],
154. &velocity_para[4],&velocity_para[5], &velocity_para[6], &velocity_para[7],
155. &velocity_para[8],&velocity_para[9], &velocity_para[10], &velocity_para[11]);
156. ALOGD("Touchfilter: %d %d %d %f %f %f %f %f %f %f %f %f %f %f %f", velocity[0],velocity[1], velocity[2],
157. velocity_para[0],velocity_para[1], velocity_para[2], velocity_para[3],
158. velocity_para[4],velocity_para[5], velocity_para[6], velocity_para[7],
159. velocity_para[8],velocity_para[9], velocity_para[10], velocity_para[11]);
160. setTouchFilterPara(&velocity[0],&velocity_para[0], 3, 4);
161. }
162. gTouchFilterDefault= false;
163. }
164. touch_driver_event_filter(&iev);
165. }
166. #endif
167. event->value =iev.value;
168. event += 1;
169. capacity -= 1;
170. }
171. if (capacity == 0) {
172. // The result buffer isfull. Reset the pending event index
173. // so we will try toread the device again on the next iteration.
174. mPendingEventIndex -=1;
175. break;
176. }
177. }
178. } else if (eventItem.events &EPOLLHUP) {
179. ALOGI("Removing device %sdue to epoll hang-up event.",
180. device->identifier.name.string());
181. deviceChanged = true;
182. closeDeviceLocked(device);
183. } else {
184. ALOGW("Received unexpectedepoll event 0x%08x for device %s.",
185. eventItem.events,device->identifier.name.string());
186. }
187. }
未处理的输入事件保存在成员变量event中,如果有的话,就可以直接返回了,否则的话,就要通过系统调用poll来等待输入设备上发生新的事件了,在我们这个场景中,就是等待键盘有按键被按下或者松开了。
[cpp] view plain copy
int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS,timeoutMillis);
Step 22. poll
这是一个Linux系统的文件操作系统调用,它用来查询指定的文件列表是否有有可读写的,如果有,就马上返回,否则的话,就阻塞线程,并等待驱动程序唤醒,重新调用poll函数,或超时返回。在我们的这个场景中,就是要查询是否有键盘事件发生,如果有的话,就返回,否则的话,当前线程就睡眠等待键盘事件的发生了。
这样, InputManager 的启动过程就分析完了,下面我们再分析应用程序注册键盘消息接收通道的过程。