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

上接:Android应用程序键盘(Keyboard)消息处理机制分析(三)

----

4.应用程序注销键盘消息接收通道的过程分析
当Activity窗口创建时,它会向InputManager注册键盘消息接收通道,而当Activity窗口销毁时,它就会向InputManager注销前面注册的键盘消息接收通道了,本节内容就来看看应用程序注销键盘消息接收通道的过程。

当我们按下键盘上的Back键时,当前**的Activity窗口就会被失去焦点,但是这时候它还没有被销毁,它的状态被设置为Stopped;当新的Activity窗口即将要显示时,它会通知WindowManagerService,这时候WindowManagerService就会处理当前处理Stopped状态的Activity窗口了,要执行的操作就是销毁它们了,在销毁的时候,就会注销它们之前所注册的键盘消息接收通道。

新的Activity窗口通知WindowManagerService它即将要显示的过程比较复杂,但是它与我们本节要介绍的内容不是很相关,因此,这里就略过大部过程了,我们从ActvitiyRecord的windowsVisible函数开始分析。注意,这里的ActivityRecord是新的Activity窗口在ActivityManangerService的代表,而那些处于Stopped状态的Activity窗口

会放在ActivityStack类的一个等待可见的mWaitingVisibleActivities列表里面,事实于,对于那些Stopped状态的Activity窗口来说,它们是等待销毁,而不是等待可见。

像前面一样,我们先来看一张应用程序注销键盘消息接收通道的过程的序列图,然后根据这个序列图来详细分析互一个步骤:

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

点击查看大图

Step 1. ActivityRecord.windowsVisible

这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityRecord.java文件中:

  1. classActivityRecordextendsIApplicationToken.Stub{
  2. ......
  3. booleannowVisible;//isthisactivity'swindowvisible?
  4. booleanidle;//hastheactivitygoneidle?
  5. ......
  6. publicvoidwindowsVisible(){
  7. synchronized(service){
  8. ......
  9. if(!nowVisible){
  10. nowVisible=true;
  11. if(!idle){
  12. .......
  13. }else{
  14. //Ifthisactivitywasalreadyidle,thenwenowneedto
  15. //makesureweperformthefullstopofanyactivities
  16. //thatarewaitingtodoso.Thisisbecausewewon't
  17. //dothatwhiletheyarestillwaitingforthisoneto
  18. //becomevisible.
  19. finalintN=stack.mWaitingVisibleActivities.size();
  20. if(N>0){
  21. for(inti=0;i<N;i++){
  22. ActivityRecordr=(ActivityRecord)
  23. stack.mWaitingVisibleActivities.get(i);
  24. r.waitingVisible=false;
  25. ......
  26. }
  27. stack.mWaitingVisibleActivities.clear();
  28. Messagemsg=Message.obtain();
  29. msg.what=ActivityStack.IDLE_NOW_MSG;
  30. stack.mHandler.sendMessage(msg);
  31. }
  32. }
  33. ......
  34. }
  35. }
  36. }
  37. ......
  38. }
应用程序中的每一个Activity在ActivityManagerService都有一个代表ActivityRecord,它们以堆栈的形式组织在ActivityManaerService中的ActivityStack中。一个即将要显示,但是还没有显示的Activity,它在ActivityManagerService中的ActivityRecord的成员变量nowVisible为false,而成员变量idle为ture,表示这个即将要显示的Activity窗口处于空闲状态。因此,在上面的这个函数中,会执行下面的语句:

  1. finalintN=stack.mWaitingVisibleActivities.size();
  2. if(N>0){
  3. for(inti=0;i<N;i++){
  4. ActivityRecordr=(ActivityRecord)
  5. stack.mWaitingVisibleActivities.get(i);
  6. r.waitingVisible=false;
  7. ......
  8. }
  9. stack.mWaitingVisibleActivities.clear();
  10. Messagemsg=Message.obtain();
  11. msg.what=ActivityStack.IDLE_NOW_MSG;
  12. stack.mHandler.sendMessage(msg);
  13. }
前面我们说过,当用户按下键盘上的Back键时,当前**的Activity记录就被放在ActivityStack对象stack的成员变量mWaitingVisibleActivities中了,这时候就要对它进行处理了。首先是将它们的Activity记录的waitingVisible设置为false,然后就把它们从ActivityStack对象stack的成员变量mWaitingVisibleActivities清空,最后向ActivityStack对象stack发送一个ActivityStack.IDLE_NOW_MSG消息。这个消息最终是由ActivityStack类的activityIdleInternal函数来处理的。

Step 2. ActivityStack.activityIdleInternal

这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

  1. publicclassActivityStack{
  2. ......
  3. finalvoidactivityIdleInternal(IBindertoken,booleanfromTimeout,
  4. Configurationconfig){
  5. ......
  6. ArrayList<ActivityRecord>stops=null;
  7. ......
  8. intNS=0;
  9. ......
  10. synchronized(mService){
  11. ......
  12. //Atomicallyretrievealloftheotherthingstodo.
  13. stops=processStoppingActivitiesLocked(true);
  14. NS=stops!=null?stops.size():0;
  15. ......
  16. }
  17. inti;
  18. ......
  19. //Stopanyactivitiesthatarescheduledtodosobuthavebeen
  20. //waitingforthenextonetostart.
  21. for(i=0;i<NS;i++){
  22. ActivityRecordr=(ActivityRecord)stops.get(i);
  23. synchronized(mService){
  24. if(r.finishing){
  25. finishCurrentActivityLocked(r,FINISH_IMMEDIATELY);
  26. }else{
  27. ......
  28. }
  29. }
  30. }
  31. ......
  32. }
  33. ......
  34. }
这个函数首先会调用processStoppingActivitiesLocked函数把所有处于Stopped状态的Activity取回来,然后逐个分析它们,如果它们的ActivityRecord中的finishing成员变量为true,就说明这个Activity需要销毁了,于是,就调用finishCurrentActivityLocked函数来销毁它们。

Step 3.ActivityStack.finishCurrentActivityLocked

这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

  1. publicclassActivityStack{
  2. ......
  3. privatefinalActivityRecordfinishCurrentActivityLocked(ActivityRecordr,
  4. intmode){
  5. ......
  6. returnfinishCurrentActivityLocked(r,index,mode);
  7. }
  8. privatefinalActivityRecordfinishCurrentActivityLocked(ActivityRecordr,
  9. intindex,intmode){
  10. ......
  11. //makesuretherecordiscleanedoutofotherplaces.
  12. mStoppingActivities.remove(r);
  13. mWaitingVisibleActivities.remove(r);
  14. ......
  15. finalActivityStateprevState=r.state;
  16. r.state=ActivityState.FINISHING;
  17. if(mode==FINISH_IMMEDIATELY
  18. ||prevState==ActivityState.STOPPED
  19. ||prevState==ActivityState.INITIALIZING){
  20. //Ifthisactivityisalreadystopped,wecanjustfinish
  21. //itrightnow.
  22. returndestroyActivityLocked(r,true)?null:r;
  23. }else{
  24. ......
  25. }
  26. returnr;
  27. }
  28. ......
  29. }
从上面的Step 2中传进来的参数mode为FINISH_IMMEDIATELY,并且这个即将要被销毁的Activity的状态为Stopped,因此,接下来就会调用destroyActivityLocked函数来销毁它。

Step 4.ActivityStack.destroyActivityLocked

这个函数定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

  1. publicclassActivityStack{
  2. ......
  3. finalbooleandestroyActivityLocked(ActivityRecordr,
  4. booleanremoveFromApp){
  5. ......
  6. booleanremovedFromHistory=false;
  7. ......
  8. finalbooleanhadApp=r.app!=null;
  9. if(hadApp){
  10. ......
  11. try{
  12. ......
  13. r.app.thread.scheduleDestroyActivity(r,r.finishing,
  14. r.configChangeFlags);
  15. }catch(Exceptione){
  16. ......
  17. }
  18. ......
  19. }else{
  20. ......
  21. }
  22. ......
  23. returnremovedFromHistory;
  24. }
  25. ......
  26. }
在前面一篇文章Android应用程序启动过程源代码分析中,我们说到,每一个应用程序进程在ActivityManagerService中,都ProcessRecord记录与之对应,而每一个Activity,都是运行在一个进程上下文中,因此,在ActivityManagerService中,每一个ActivityRecord的app成员变量都应该指向一个ProcessRecord记录,于是,这里得到的hadApp为true。在ProcessRecord类中,有一个成员变量thread,它的类型为IApplicationThread。在文章Android应用程序启动过程源代码分析中,我们也曾经说过,每一个应用程序在启动的时候,它都会在内部创建一个ActivityThread对象,而在这个ActivityThread对象中,有一个成员变量mAppThread,它的类型为ApplicationThread,这是一个Binder对象,专门用来负责在应用程序和ActivityManagerService之间执行进程间通信工作的。应用程序在启动的时候,就会将这个Binder对象传递给ActivityManagerService,而ActivityManagerService就会把它保存在相应的ProcessRecord记录的thread成员变量中。因此,ProcessRecord记录的thread成员变量其实就是ApplicationThread对象的远程接口,于是,执行下面这个语句的时候:

  1. r.app.thread.scheduleDestroyActivity(r,r.finishing,
  2. r.configChangeFlags);
就会进入到ApplicationThread类中的scheduleDestroyActivity函数来。

Step 5.ApplicationThread.scheduleDestroyActivity

这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

  1. publicfinalclassActivityThread{
  2. ......
  3. privatefinalclassApplicationThreadextendsApplicationThreadNative{
  4. ......
  5. publicfinalvoidscheduleDestroyActivity(IBindertoken,booleanfinishing,
  6. intconfigChanges){
  7. queueOrSendMessage(H.DESTROY_ACTIVITY,token,finishing?1:0,
  8. configChanges);
  9. }
  10. ......
  11. }
  12. ......
  13. }
这个函数调用外部类ActivityThread的queueOrSendMessage函数来往应用程序的消息队列中发送一个H.DESTROY_ACTIVITY消息,这个消息最终由ActivityThread类的handleDestroyActivity函数来处理。

Step 6.ActivityThread.handleDestroyActivity

这个函数定义在frameworks/base/core/java/android/app/ActivityThread.java文件中:

  1. publicfinalclassActivityThread{
  2. ......
  3. privatefinalvoidhandleDestroyActivity(IBindertoken,booleanfinishing,
  4. intconfigChanges,booleangetNonConfigInstance){
  5. ......
  6. ActivityClientRecordr=performDestroyActivity(token,finishing,
  7. configChanges,getNonConfigInstance);
  8. if(r!=null){
  9. WindowManagerwm=r.activity.getWindowManager();
  10. Viewv=r.activity.mDecor;
  11. if(v!=null){
  12. ......
  13. if(r.activity.mWindowAdded){
  14. wm.removeViewImmediate(v);
  15. }
  16. ......
  17. }
  18. ......
  19. }
  20. ......
  21. }
  22. ......
  23. }
这里首先调用performDestroyActivity来执行一些销毁Activity的操作,期间就会调用Activity的onDestroy函数让Activity本身有机会执行一些销毁前的工作了。这里通过r.activity.getWindowManager函数返回的是一个LocalWindowManager对象,而通过r.activity.mDecor得到的是一个DecorView对象,这些都是在Activity启动的时候设置好的。函数最后调用LocalWindowManager对象wm的removeViewImmediate函员来从LocalWindowManager移除这个DecorView对象。

Step 7.LocalWindowManager.removeViewImmediate

这个函数定义在frameworks/base/core/java/android/view/Window.java文件中:

  1. publicabstractclassWindow{
  2. ......
  3. privateclassLocalWindowManagerimplementsWindowManager{
  4. ......
  5. publicfinalvoidremoveViewImmediate(Viewview){
  6. mWindowManager.removeViewImmediate(view);
  7. }
  8. ......
  9. privatefinalWindowManagermWindowManager;
  10. }
  11. ......
  12. }
LocalWindowManager类的成员变量mWindowManager是一个WndowManagerImpl对象,这个函数只是简单地调用WndowManagerImpl类的removeViewImmediate来进一步处理。

Step 8.WndowManagerImpl.removeViewImmediate

这个函数定义在frameworks/base/core/java/android/view/WindowManagerImpl.java文件中:

  1. publicclassWindowManagerImplimplementsWindowManager{
  2. ......
  3. publicvoidremoveViewImmediate(Viewview){
  4. synchronized(this){
  5. intindex=findViewLocked(view,true);
  6. ViewRootroot=mRoots[index];
  7. ......
  8. root.die(true);
  9. ......
  10. }
  11. }
  12. ......
  13. }
这个函数首先是找到这个view所属的ViewRoot对象root,然后调用这个root对象的die函数来销毁它。

Step 9. ViewRoot.die

这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:

  1. publicfinalclassViewRootextendsHandlerimplementsViewParent,
  2. View.AttachInfo.Callbacks{
  3. ......
  4. publicvoiddie(booleanimmediate){
  5. if(immediate){
  6. doDie();
  7. }else{
  8. ......
  9. }
  10. }
  11. ......
  12. }
上面Step 8传进来的immediate参数为true,因此,这里直接调用doDie函数来进一步处理。

Step 10.ViewRoot.doDie

这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:

  1. publicfinalclassViewRootextendsHandlerimplementsViewParent,
  2. View.AttachInfo.Callbacks{
  3. ......
  4. voiddoDie(){
  5. ......
  6. synchronized(this){
  7. ......
  8. if(mAdded){
  9. mAdded=false;
  10. dispatchDetachedFromWindow();
  11. }
  12. }
  13. }
  14. ......
  15. }
当我们把Activity窗口中的View添加到一个ViewRoot对象时,就会把它的成员变量mAdded设置为true,这样就表示这个ViewRoot中有View存在,于是,这里就会调用dispatchDetachedFromWindow函数来进一步处理。

Step 11.ViewRoot.ispatchDetachedFromWindow

这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:

  1. publicfinalclassViewRootextendsHandlerimplementsViewParent,
  2. View.AttachInfo.Callbacks{
  3. ......
  4. voiddispatchDetachedFromWindow(){
  5. ......
  6. if(mInputChannel!=null){
  7. if(mInputQueueCallback!=null){
  8. ......
  9. }else{
  10. InputQueue.unregisterInputChannel(mInputChannel);
  11. }
  12. }
  13. try{
  14. sWindowSession.remove(mWindow);
  15. }catch(RemoteExceptione){
  16. }
  17. ......
  18. }
  19. ......
  20. }
前面在介绍应用程序注册键盘消息接收通道的过程时,在Step 18,我们说到,ViewRoot类中的mInputQueueCallback为null,表示由这个ViewRoot自己来管理键盘输入事件,因此,这里首先会调用InputQueue的unregisterInputChannel函数来注销注册在应用程序这一侧的Client端InputChannel,然后再调用sWindowSession的remove函数来注销注册在InputManager这一侧的Server端InputChannel,这个逻辑是和前面介绍应用程序注册键盘消息接收通道的逻辑相对应的,前面分别注册了这两个InputChannel,现在Activity要销毁了,当然就要把它们注销了。

我们先来看注销注册在应用程序这一侧的Client端InputChannel,然后再回过头来分析注销注册在InputManager这一侧的Server端InputChannel。

Step 12.InputQueue.unregisterInputChannel

这个函数定义在frameworks/base/core/java/android/view/InputQueue.java文件中:

  1. publicfinalclassInputQueue{
  2. ......
  3. publicstaticvoidunregisterInputChannel(InputChannelinputChannel){
  4. ......
  5. synchronized(sLock){
  6. ......
  7. nativeUnregisterInputChannel(inputChannel);
  8. }
  9. }
  10. ......
  11. }
这个函数只是简单地调用本地方法nativeUnregisterInputChannel来执行具体的操作。

Step 13.InputQueue.nativeUnregisterInputChannel
这个函数定义在frameworks/base/core/jni/android_view_InputQueue.cpp文件中:

  1. staticvoidandroid_view_InputQueue_nativeUnregisterInputChannel(JNIEnv*env,jclassclazz,
  2. jobjectinputChannelObj){
  3. status_tstatus=gNativeInputQueue.unregisterInputChannel(env,inputChannelObj);
  4. ......
  5. }
这里调用NativeInputQueue的成员函数unregisterInputChannel来进一步处理。

Step 14.NativeInputQueue.unregisterInputChannel
这个函数定义在frameworks/base/core/jni/android_view_InputQueue.cpp文件中:

  1. status_tNativeInputQueue::unregisterInputChannel(JNIEnv*env,jobjectinputChannelObj){
  2. sp<InputChannel>inputChannel=android_view_InputChannel_getInputChannel(env,
  3. inputChannelObj);
  4. ......
  5. {//acquirelock
  6. AutoMutex_l(mLock);
  7. ssize_tconnectionIndex=getConnectionIndex(inputChannel);
  8. ......
  9. sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
  10. mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
  11. connection->status=Connection::STATUS_ZOMBIE;
  12. connection->looper->removeFd(inputChannel->getReceivePipeFd());
  13. env->DeleteGlobalRef(connection->inputHandlerObjGlobal);
  14. connection->inputHandlerObjGlobal=NULL;
  15. ......
  16. }//releaselock
  17. ......
  18. returnOK;
  19. }
真正的注销工作就是这里实现的了,读者可以对照前面介绍应用程序注册键盘消息接收通道过程中的Step 21(NativeInputQueue.registerInputChannel)来分析,它首先是将在之前创建的Connection对象从NativeInputQueue中的mConnectionByReceiveFd向量中删除:

  1. ssize_tconnectionIndex=getConnectionIndex(inputChannel);
  2. ......
  3. sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
  4. mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
然后再把这个Client端InputChannel的前向管道的读端文件描述符从应用程序主线程中的Looper对象中删除:

  1. connection->looper->removeFd(inputChannel->getReceivePipeFd());
这样,这个Activity窗口以后就不会接收到键盘事件了。

最后将Connection对象中的回调对象inputHandlerOjbGlobal对象删除:

  1. env->DeleteGlobalRef(connection->inputHandlerObjGlobal);
  2. connection->inputHandlerObjGlobal=NULL;
回忆一下前面我们在分析InputManager分发键盘消息给应用程序处理时,曾经说到,每当有键盘事件发生时,InputManager首先就会调用NativeInputQueue类的handleReceiveCallback函数。在这个handleReceiveCallback函数里面,NativeInputQueue会找到相应的Connection对象,然后把它里面的内部对象inputHandlerOjbGlobal作为参数来调用Java层的InputQueue类的dispatchKeyEvent函数来通知应用程序,有键盘事件发生了。在InputQueue类的dispatchKeyEvent函数里面,就是通过这个inputHandlerOjbGlobal对象来直正通知到当前**的Activity窗口来处理这个键盘事件的。

注册在应用程序这一侧的Client端InputChannel被注销以后,回到前面的Step 11中,我们继续分析注销注册在InputManager这一侧的Server端InputChannel。

Step 15. WindowManagerService.Session.remove

这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:

  1. publicclassWindowManagerServiceextendsIWindowManager.Stub
  2. implementsWatchdog.Monitor{
  3. ......
  4. privatefinalclassSessionextendsIWindowSession.Stub
  5. implementsIBinder.DeathRecipient{
  6. ......
  7. publicvoidremove(IWindowwindow){
  8. removeWindow(this,window);
  9. }
  10. ......
  11. }
  12. ......
  13. }

这个函数只是简单地调用其外部类WindowManagerService的removeWindow函数来进一步执行操作。

Step 16.WindowManagerService.removeWindow
这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:

  1. publicclassWindowManagerServiceextendsIWindowManager.Stub
  2. implementsWatchdog.Monitor{
  3. ......
  4. publicvoidremoveWindow(Sessionsession,IWindowclient){
  5. synchronized(mWindowMap){
  6. WindowStatewin=windowForClientLocked(session,client,false);
  7. if(win==null){
  8. return;
  9. }
  10. removeWindowLocked(session,win);
  11. }
  12. }
  13. ......
  14. }

回忆一下前面我们在分析应用程序注册键盘消息管道的过程时,在Step 11(WindowManagerService.addWindow)中,WindowManagerService为这个即将要**的Activity窗口创建了一个WindowState对象win,创建的时候,使用了从ViewRoot中传过来的两个参数,分别是一个Session对象session和一个IWindow对象client。

在这个函数中,ViewRoot传过来的两个参数session和client和上面说的两个参数是一致的,因此,这个函数首先通过参数session和client得到一个WindowState对象win,然后调用removeWindowLocked来把它从WindowManagerService删除。

Step 17.WindowManagerService.removeWindowLocked
这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:

  1. publicclassWindowManagerServiceextendsIWindowManager.Stub
  2. implementsWatchdog.Monitor{
  3. ......
  4. publicvoidremoveWindowLocked(Sessionsession,WindowStatewin){
  5. ......
  6. win.disposeInputChannel();
  7. ......
  8. }
  9. ......
  10. }
我们忽略了这个函数的其它逻辑,只关注注销之前注册的Server端InputChannel的逻辑,这里,注销的操作就是调用win的disposeInputChannel进行的了。

Step 18. WindowState.disposeInputChannel

这个函数定义在frameworks/base/services/java/com/android/server/WindowManagerService.java文件中:

  1. publicclassWindowManagerServiceextendsIWindowManager.Stub
  2. implementsWatchdog.Monitor{
  3. ......
  4. privatefinalclassWindowStateimplementsWindowManagerPolicy.WindowState{
  5. ......
  6. voiddisposeInputChannel(){
  7. if(mInputChannel!=null){
  8. mInputManager.unregisterInputChannel(mInputChannel);
  9. mInputChannel.dispose();
  10. mInputChannel=null;
  11. }
  12. }
  13. ......
  14. }
  15. ......
  16. }
上面说到,在前面分析应用程序注册键盘消息管道的过程时,在Step 11(WindowManagerService.addWindow)中,为当前这个Activity窗口创建了一个WindowState对象,接着创建了一个输入管道后,把Server端的InputChannel保存了在这个WindowState对象的成员变量mInputChannel中,因此,这里,就可以把它取回来,然后调用mInputManager对象的unregisterInputChannel函数来把它注销掉了。

Step 19. InputManager.unregisterInputChannel

这个函数定义在frameworks/base/services/java/com/android/server/InputManager.java文件中:

  1. publicclassInputManager{
  2. ......
  3. publicvoidunregisterInputChannel(InputChannelinputChannel){
  4. ......
  5. nativeUnregisterInputChannel(inputChannel);
  6. }
  7. ......
  8. }
这个函数很简单,它调用本地方法nativeUnregisterInputChannel来进一步处理。

Step 20.InputManager.nativeUnregisterInputChannel

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

  1. staticvoidandroid_server_InputManager_nativeUnregisterInputChannel(JNIEnv*env,jclassclazz,
  2. jobjectinputChannelObj){
  3. ......
  4. sp<InputChannel>inputChannel=android_view_InputChannel_getInputChannel(env,
  5. inputChannelObj);
  6. ......
  7. status_tstatus=gNativeInputManager->unregisterInputChannel(env,inputChannel);
  8. ......
  9. }
这个函数首先调用android_view_InputChannel_getInputChannel函数根据Java层的InputChannel对象找到C++层的InputChannel对象,然后调用NativeInputManager的unregisterInputChannel函数来执行注销的操作。

Step 21.NativeInputManager.unregisterInputChannel
这个函数定义在frameworks/base/services/jni/com_android_server_InputManager.cpp文件中:

  1. status_tNativeInputManager::unregisterInputChannel(JNIEnv*env,
  2. constsp<InputChannel>&inputChannel){
  3. ......
  4. returnmInputManager->getDispatcher()->unregisterInputChannel(inputChannel);
  5. }
这个函数与前面分析应用程序注册键盘消息通道的Step 17(NativeInputManager.registerInputChannel)相对应,主要是调用InputDispatcher对象的unregisterInputChannel函数来执行真正注销的操作。

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

  1. status_tInputDispatcher::unregisterInputChannel(constsp<InputChannel>&inputChannel){
  2. ......
  3. {//acquirelock
  4. AutoMutex_l(mLock);
  5. ssize_tconnectionIndex=getConnectionIndexLocked(inputChannel);
  6. ......
  7. sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
  8. mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
  9. ......
  10. mLooper->removeFd(inputChannel->getReceivePipeFd());
  11. .....
  12. }//releaselock
  13. ......
  14. returnOK;
  15. }
这一步与前面的Step 14注销应用程序一侧的Client端InputChannel是差不多的,只不过这里是从InputDispatcher中把Server端的InputChannel注销掉。首先是根据传进来的参数inputChannel找到它在InputDispatcher中对应的Connection对象在mConnectionsByReceiveFd中的索引,然后把它从mConnectionsByReceiveFd中删除:

  1. ssize_tconnectionIndex=getConnectionIndexLocked(inputChannel);
  2. ......
  3. sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
  4. mConnectionsByReceiveFd.removeItemsAt(connectionIndex);
最后,还需要把这个InputChannel中的反向管道读端文件描述符从InputDispatcher的内部对象mLooper中删除,因为这个文件描述符是在前面注册Server端的InputChannel时加入到mLooper对象去的,具体可以参考上面分析应用程序注册键盘消息接收通道的过程中的Step 18(InputDispatcher.registerInputChannel)。

这样,应用程序注销键盘消息接收通道的过程就分析完成了,整个应用程序键盘消息处理机制也分析完成了,这是一个比较复杂的过程,要完全理解它还需要花费一些努力和时间,不过,理解了这个过程之后,对Android应用程序框架层的理解就更进一步了。

转自:老罗的Android应用程序键盘(Keyboard)消息处理机制分析