Android应用程序键盘(Keyboard)消息处理机制分析(2)

  Step 6. InputManager.nativeInit

       这个函数定义在frameworks/base/services/jni$ vi com_android_server_InputManager.cpp文件中:

  1. static void android_server_InputManager_nativeInit(JNIEnv* env, jclass clazz,  
  2.         jobject callbacks) {  
  3.     if (gNativeInputManager == NULL) {  
  4.         gNativeInputManager = new NativeInputManager(callbacks);  
  5.     } else {  
  6.         LOGE("Input manager already initialized.");  
  7.         jniThrowRuntimeException(env, "Input manager already initialized.");  
  8.     }  
  9. }  

        这个函数的作用是创建一个NativeInputManager实例,并保存在gNativeInputManager变量中。由于是第一次调用到这里,因此,gNativeInputManager为NULL,于是就会new一个NativeInputManager对象出来,这样就会执行NativeInputManager类的构造函数来执其它的初始化操作。

 

       Step 7. NativeInputManager<init>

       NativeInputManager类的构造函数定义在frameworks/base/services/jni$ vi com_android_server_InputManager.cpp文件中:

  1. NativeInputManager::NativeInputManager(jobject callbacksObj) :  
  2.     mFilterTouchEvents(-1), mFilterJumpyTouchEvents(-1), mVirtualKeyQuietTime(-1),  
  3.     mMaxEventsPerSecond(-1),  
  4.     mDisplayWidth(-1), mDisplayHeight(-1), mDisplayOrientation(ROTATION_0) {  
  5.     JNIEnv* env = jniEnv();  
  6.   
  7.     mCallbacksObj = env->NewGlobalRef(callbacksObj);  
  8.   
  9.     sp<EventHub> eventHub = new EventHub();  
  10.     mInputManager = new InputManager(eventHub, thisthis);  
  11. }  

       这里只要是创建了一个EventHub实例,并且把这个EventHub作为参数来创建InputManager对象。注意,这里的InputManager类是定义在C++层的,和前面在Java层的InputManager不一样,不过它们是对应关系。EventHub类是真正执行监控键盘事件操作的地方,后面我们会进一步分析到,现在我们主要关心InputManager实例的创建过程,它会InputManager类的构造函数里面执行一些初始化操作。

 

        Step 8. InputManager<init>@C++

        C++层的InputManager类的构造函数定义在frameworks/base/libs/ui/InputManager.cpp 文件中:

  1. InputManager::InputManager(  
  2.         const sp<EventHubInterface>& eventHub,  
  3.         const sp<InputReaderPolicyInterface>& readerPolicy,  
  4.         const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {  
  5.     mDispatcher = new InputDispatcher(dispatcherPolicy);  
  6.     mReader = new InputReader(eventHub, readerPolicy, mDispatcher);  
  7.     initialize();  
  8. }  
        这里主要是创建了一个InputDispatcher对象和一个InputReader对象,并且分别保存在成员变量mDispatcher和mReader中。InputDispatcher类是负责把键盘消息分发给当前激活的Activity窗口的,而InputReader类则是通过EventHub类来实现读取键盘事件的,后面我们会进一步分析。创建了这两个对象后,还要调用initialize函数来执行其它的初始化操作。

 

        Step 9. InputManager.initialize

        这个函数定义在frameworks/base/libs/ui/InputManager.cpp 文件中:

  1. void InputManager::initialize() {  
  2.     mReaderThread = new InputReaderThread(mReader);  
  3.     mDispatcherThread = new InputDispatcherThread(mDispatcher);  
  4. }  
        这个函数创建了一个InputReaderThread线程实例和一个InputDispatcherThread线程实例,并且分别保存在成员变量mReaderThread和mDispatcherThread中。这里的InputReader实列mReader就是通过这里的InputReaderThread线程实列mReaderThread来读取键盘事件的,而InputDispatcher实例mDispatcher则是通过这里的InputDispatcherThread线程实例mDisptacherThread来分发键盘消息的。

 

        至此,InputManager的初始化工作就完成了,在回到Step 3中继续分析InputManager的进一步启动过程之前,我们先来作一个小结,看看这个初始化过程都做什么事情:

        A. 在Java层中的WindowManagerService中创建了一个InputManager对象,由它来负责管理Android应用程序框架层的键盘消息处理;

        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文件中:

  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$ vi com_android_server_InputManager.cpp文件中:

  1. static void android_server_InputManager_nativeStart(JNIEnv* env, jclass clazz) {  
  2.     if (checkInputManagerUnitialized(env)) {  
  3.         return;  
  4.     }  
  5.   
  6.     status_t result = gNativeInputManager->getInputManager()->start();  
  7.     if (result) {  
  8.         jniThrowRuntimeException(env, "Input manager could not be started.");  
  9.     }  
  10. }  

        这里的gNativeInputManager对象是在前面的Step 6中创建的,通过它的getInputManager函数可以返回C++层的InputManager对象,接着调用这个InputManager对象的start函数。

 

        Step 12. InputManager.start

        这个函数定义在frameworks/base/libs/ui/InputManager.cpp 文件中:

  1. status_t InputManager::start() {  
  2.     status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY);  
  3.     if (result) {  
  4.         LOGE("Could not start InputDispatcher thread due to error %d.", result);  
  5.         return result;  
  6.     }  
  7.   
  8.     result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY);  
  9.     if (result) {  
  10.         LOGE("Could not start InputReader thread due to error %d.", result);  
  11.   
  12.         mDispatcherThread->requestExit();  
  13.         return result;  
  14.     }  
  15.   
  16.     return OK;  
  17. }  
        这个函数主要就是分别启动一个InputDispatcherThread线程和一个InputReaderThread线程来读取和分发键盘消息的了。这里的InputDispatcherThread线程对象mDispatcherThread和InputReaderThread线程对象是在前面的Step 9中创建的,调用了它们的run函数后,就会进入到它们的threadLoop函数中去,只要threadLoop函数返回true,函数threadLoop就会一直被循环调用,于是这两个线程就起到了不断地读取和分发键盘消息的作用。

 

        我们先来分析InputDispatcherThread线程分发消息的过程,然后再回过头来分析InputReaderThread线程读取消息的过程。

        Step 13. InputDispatcherThread.threadLoop

        这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:

  1. bool InputDispatcherThread::threadLoop() {  
  2.     mDispatcher->dispatchOnce();  
  3.     return true;  
  4. }  
        这里的成员变量mDispatcher即为在前面Step 8中创建的InputDispatcher对象,调用它的dispatchOnce成员函数执行一次键盘消息分发的操作。

 Step 14. InputDispatcher.dispatchOnce

        这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:

  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)分析一文。

 





本文转自 Luoshengyang 51CTO博客,原文链接:http://blog.51cto.com/shyluo/966611,如需转载请自行联系原作者
上一篇:c#开源消息队列中间件EQueue 教程


下一篇:Android应用程序键盘(Keyboard)消息处理机制分析(4)