inputmanager对按键事件的获取和向上派发

Android系统中,键盘按键事件是由WindowManagerService服务来管理的,然后再以消息的形式来分发给应用程序处理,不过和普通消息不一样,它是由硬件中断触发的;在上一篇文章《Android应用程序消息处理机制(LooperHandler)分析》中,我们分析了Android应用程序的消息处理机制,本文将结合这种消息处理机制来详细分析Android应用程序是如何获得键盘按键消息的。

       在系统启动的时候,SystemServer会启动窗口管理服务WindowManagerServiceWindowManagerService在启动的时候就会通过系统输入管理器InputManager来总负责监控键盘消息。这些键盘消息一般都是分发给当前激活的Activity窗口来处理的,因此,当前激活的Activity窗口在创建的时候,会到WindowManagerService中去注册一个接收键盘消息的通道,表明它要处理键盘消息,而当InputManager监控到有键盘消息时,就会分给给它处理。当当前激活的Activity窗口不再处于激活状态时,它也会到WindowManagerService中去反注册之前的键盘消息接收通道,这样,InputManager就不会再把键盘消息分发给它来处理。

       由于本文的内容比较多,在接下面的章节中,我们将分为五个部分来详细描述Android应用程序获得键盘按键消息的过程,每一个部分都是具体描述键盘消息处理过程中的一个过程。结合上面的键盘消息处理框架,这四个过程分别是InputManager的启动过程、应用程序注册键盘消息接收通道的过程、InputManager分发键盘消息给应用程序的过程以及应用程序注销键盘消息接收通道的过程。为了更好地理解Android应用程序获得键盘按键消息的整个过程,建议读者首先阅读Android应用程序消息处理机制(LooperHandler)分析一文,理解了Android应用程序的消息处理机制后,就能很好的把握本文的内容。

 

      1. InputManager的启动过程分析 

       前面说过,Android系统的键盘事件是由InputManager来监控的,而InputManager是由窗口管理服务WindowManagerService来启动的。

       从前面一篇文章Android系统进程Zygote启动过程的源代码分析中,我们知道在Android系统中,Zygote进程负责启动系统服务进程SystemServer,而系统服务进程SystemServer负责启动系统中的各种关键服务,例如我们在前面两篇文章Android应用程序安装过程源代码分析Android系统默认Home应用程序(Launcher)的启动过程源代码分析中提到的Package管理服务PackageManagerServiceActivity管理服务ActivityManagerService。这里我们所讨论的窗口管理服务WindowManagerService也是由SystemServer来启动的,具体的启动过程这里就不再详述了,具体可以参考PackageManagerServiceActivityManagerService的启动过程。

      了解了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实例thrstart成员函数时,会进入到WMThread实例thrrun函数中去。

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变量中。由于是第一次调用到这里,因此,gNativeInputManagerNULL,于是就会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对象,并且分别保存在成员变量mDispatchermReader中。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线程实例,并且分别保存在成员变量mReaderThreadmDispatcherThread中。这里的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线程对象mDispatcherThreadInputReaderThread线程对象是在前面的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应用程序消息处理机制(LooperHandler)分析一文。

       Step 15. Looper.pollOnce

       这个函数定义在frameworks/native/services/inputflinger/InputDispatcher.cpp文件中,具体可以参考前面Android应用程序消息处理机制(LooperHandler)分析一文,这里就不再详述了。总的来说,就是在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来负责键盘消息的读取工作,如果当前有键盘事件发生或者有键盘事件等待处理,通过mEventHubgetEvent函数就可以得到这个事件,然后交给process函数进行处理,这个函数主要就是唤醒前面的InputDispatcherThread线程,通知它有新的键盘事件发生了,它需要进行一次键盘消息的分发操作了,这个函数我们后面再进一步详细分析;如果没有键盘事件发生或者没有键盘事件等待处理,那么调用mEventHubgetEvent函数时就会进入等待状态。

       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中,一般有三个设备文件存在,分别是event0micemouse0设备文件,其中,键盘事件就包含在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结构体,主要就是把结构体deviceclasses成员变量的INPUT_DEVICE_CLASS_KEYBOARD位置为1了,以表明这是一个键盘。
        
如果是键盘设备,初始化工作还未完成,还要继续设置键盘的布局等信息:

布局文件的加载

status_tEventHub::loadKeyMapLocked(Device* device) {

    returndevice->keyMap.load(device->identifier, device->configuration);

}

 

keyMap.load又调用了Keyboard.cppKeyMap::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 的启动过程就分析完了,下面我们再分析应用程序注册键盘消息接收通道的过程。
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值