Step 6. InputManager.nativeInit

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

  1. staticvoidandroid_server_InputManager_nativeInit(JNIEnv*env,jclassclazz,
  2. jobjectcallbacks){
  3. if(gNativeInputManager==NULL){
  4. gNativeInputManager=newNativeInputManager(callbacks);
  5. }else{
  6. LOGE("Inputmanageralreadyinitialized.");
  7. jniThrowRuntimeException(env,"Inputmanageralreadyinitialized.");
  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(jobjectcallbacksObj):
  2. mFilterTouchEvents(-1),mFilterJumpyTouchEvents(-1),mVirtualKeyQuietTime(-1),
  3. mMaxEventsPerSecond(-1),
  4. mDisplayWidth(-1),mDisplayHeight(-1),mDisplayOrientation(ROTATION_0){
  5. JNIEnv*env=jniEnv();
  6. mCallbacksObj=env->NewGlobalRef(callbacksObj);
  7. sp<EventHub>eventHub=newEventHub();
  8. mInputManager=newInputManager(eventHub,this,this);
  9. }

这里只要是创建了一个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. constsp<EventHubInterface>&eventHub,
  3. constsp<InputReaderPolicyInterface>&readerPolicy,
  4. constsp<InputDispatcherPolicyInterface>&dispatcherPolicy){
  5. mDispatcher=newInputDispatcher(dispatcherPolicy);
  6. mReader=newInputReader(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. voidInputManager::initialize(){
  2. mReaderThread=newInputReaderThread(mReader);
  3. mDispatcherThread=newInputDispatcherThread(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. publicclassInputManager{
  2. ......
  3. publicvoidstart(){
  4. Slog.i(TAG,"Startinginputmanager");
  5. nativeStart();
  6. }
  7. ......
  8. }
这个函数通过调用本地方法nativeStart来执行进一步的启动操作。

Step 11. InputManager.nativeStart

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

  1. staticvoidandroid_server_InputManager_nativeStart(JNIEnv*env,jclassclazz){
  2. if(checkInputManagerUnitialized(env)){
  3. return;
  4. }
  5. status_tresult=gNativeInputManager->getInputManager()->start();
  6. if(result){
  7. jniThrowRuntimeException(env,"Inputmanagercouldnotbestarted.");
  8. }
  9. }

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

Step 12. InputManager.start

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

  1. status_tInputManager::start(){
  2. status_tresult=mDispatcherThread->run("InputDispatcher",PRIORITY_URGENT_DISPLAY);
  3. if(result){
  4. LOGE("CouldnotstartInputDispatcherthreadduetoerror%d.",result);
  5. returnresult;
  6. }
  7. result=mReaderThread->run("InputReader",PRIORITY_URGENT_DISPLAY);
  8. if(result){
  9. LOGE("CouldnotstartInputReaderthreadduetoerror%d.",result);
  10. mDispatcherThread->requestExit();
  11. returnresult;
  12. }
  13. returnOK;
  14. }
这个函数主要就是分别启动一个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. boolInputDispatcherThread::threadLoop(){
  2. mDispatcher->dispatchOnce();
  3. returntrue;
  4. }
这里的成员变量mDispatcher即为在前面Step 8中创建的InputDispatcher对象,调用它的dispatchOnce成员函数执行一次键盘消息分发的操作。

Step 14. InputDispatcher.dispatchOnce

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

  1. voidInputDispatcher::dispatchOnce(){
  2. nsecs_tkeyRepeatTimeout=mPolicy->getKeyRepeatTimeout();
  3. nsecs_tkeyRepeatDelay=mPolicy->getKeyRepeatDelay();
  4. nsecs_tnextWakeupTime=LONG_LONG_MAX;
  5. {//acquirelock
  6. AutoMutex_l(mLock);
  7. dispatchOnceInnerLocked(keyRepeatTimeout,keyRepeatDelay,&nextWakeupTime);
  8. if(runCommandsLockedInterruptible()){
  9. nextWakeupTime=LONG_LONG_MIN;//forcenextpolltowakeupimmediately
  10. }
  11. }//releaselock
  12. //Waitforcallbackortimeoutorwake.(makesureweroundup,notdown)
  13. nsecs_tcurrentTime=now();
  14. int32_ttimeoutMillis;
  15. if(nextWakeupTime>currentTime){
  16. uint64_ttimeout=uint64_t(nextWakeupTime-currentTime);
  17. timeout=(timeout+999999LL)/1000000LL;
  18. timeoutMillis=timeout>INT_MAX?-1:int32_t(timeout);
  19. }else{
  20. timeoutMillis=0;
  21. }
  22. mLooper->pollOnce(timeoutMillis);
  23. }

这个函数很简单,把键盘消息交给dispatchOnceInnerLocked函数来处理,这个过程我们在后面再详细分析,然后调用mLooper->pollOnce函数等待下一次键盘事件的发生。这里的成员变量mLooper的类型为Looper,它定义在C++层中,具体可以参考前面Android应用程序消息处理机制(Looper、Handler)分析一文。

更多相关文章

  1. Android Audio代码分析21 - 创建AudioEffect对象
  2. Android Training精要(六)如何防止Bitmap对象出现OOM
  3. android listview 与 一般多线程配合产生的错误,资料汇总
  4. Android Audio代码分析2 - 函数getMinBufferSize
  5. android关于fragment的构造函数用法建议
  6. 文件多线程下载实现
  7. Android Audio代码分析18 - setSampleRate函数
  8. android使用多线程处理

随机推荐

  1. Android中的Zip解压缩
  2. Android(安卓)三个按钮对话框
  3. 智能手机软件平台 Android(安卓)VS iPhon
  4. Android(安卓)HttpClient设置User_agent
  5. Android中如何判断Intent是否存在?
  6. Learning about Android(安卓)Graphics S
  7. Android(安卓)清除缓存(工具类)
  8. Android之自定义对话框AlertDialog.Build
  9. android键盘事件
  10. Android适配器之-----SimpleCursorTreeAd