3.InputManager分发键盘消息给应用程序的过程分析
在分析InputManager分发键盘消息给应用程序的过程之前,我们先假设现在没有键盘事件发生,因此,InputManager中的InputReader正在睡眠等待键盘事件的发生,而InputManager中的InputDispatcher正在等待InputReader从睡眠中醒过来并且唤醒它,而应用程序也正在消息循环中等待InputDispatcher从睡眠中醒过来并且唤醒它。这时候,用户按下键盘中的一个键,于是,一系列唤醒的事件就依次发生了,一直到应用程序中正在显示的Activity得到通知,有键盘事件发生了。我们先来看这个过程的序列图,然后再详细分析每一个步骤:
Step 1. InputReader.pollOnce
Step 2. EventHub.getEvent
这两个函数分别定义在frameworks/base/libs/ui/InputReader.cpp和frameworks/base/libs/ui/EventHub.cpp文件中,前面我们在分析InputManager的启动过程的Step 17和Step 18时,已经看到过这两个函数了。InputReaderThread线程会不民地循环调用InputReader.pollOnce函数来读入键盘事件,而实际的键盘事件读入操作是由EventHub.getEvent函数来进行的。如果当前没有键盘事件发生,InputReaderThread线程就会睡眠在EventHub.getEvent函数上,而当键盘事件发生后,就会把这个事件封装成一个RawEvent对象,然后返回到pollOnce函数中,执行process函数进一步处理:
- voidInputReader::loopOnce(){
- RawEventrawEvent;
- mEventHub->getEvent(&rawEvent);
- ......
- process(&rawEvent);
- }
这个函数定义在frameworks/base/libs/ui/InputReader.cpp文件中:
- voidInputReader::process(constRawEvent*rawEvent){
- switch(rawEvent->type){
- caseEventHubInterface::DEVICE_ADDED:
- addDevice(rawEvent->deviceId);
- break;
- caseEventHubInterface::DEVICE_REMOVED:
- removeDevice(rawEvent->deviceId);
- break;
- caseEventHubInterface::FINISHED_DEVICE_SCAN:
- handleConfigurationChanged(rawEvent->when);
- break;
- default:
- consumeEvent(rawEvent);
- break;
- }
- }
当键盘事件发生时,rawEvent->type的值为EV_KEY,这是一个宏定义,具体可以参考bionic/libc/kernel/common/linux/input.h文件:
- #defineEV_KEY0x01
Step 4.InputReader.consumeEvent
这个函数定义在frameworks/base/libs/ui/InputReader.cpp文件中:
- voidInputReader::consumeEvent(constRawEvent*rawEvent){
- int32_tdeviceId=rawEvent->deviceId;
- {//acquiredeviceregistryreaderlock
- RWLock::AutoRLock_rl(mDeviceRegistryLock);
- ssize_tdeviceIndex=mDevices.indexOfKey(deviceId);
- if(deviceIndex<0){
- LOGW("DiscardingeventforunknowndeviceId%d.",deviceId);
- return;
- }
- InputDevice*device=mDevices.valueAt(deviceIndex);
- if(device->isIgnored()){
- //LOGD("DiscardingeventforignoreddeviceId%d.",deviceId);
- return;
- }
- device->process(rawEvent);
- }//releasedeviceregistryreaderlock
- }
Step 5. InputDevice.process
这个函数定义在frameworks/base/libs/ui/InputReader.cpp文件中:
- voidInputDevice::process(constRawEvent*rawEvent){
- size_tnumMappers=mMappers.size();
- for(size_ti=0;i<numMappers;i++){
- InputMapper*mapper=mMappers[i];
- mapper->process(rawEvent);
- }
- }
Step 6.KeyboardInputMapper.process
这个函数定义在frameworks/base/libs/ui/InputReader.cpp文件中:
- voidKeyboardInputMapper::process(constRawEvent*rawEvent){
- switch(rawEvent->type){
- caseEV_KEY:{
- int32_tscanCode=rawEvent->scanCode;
- if(isKeyboardOrGamepadKey(scanCode)){
- processKey(rawEvent->when,rawEvent->value!=0,rawEvent->keyCode,scanCode,
- rawEvent->flags);
- }
- break;
- }
- }
- }
Step 7.KeyboardInputMapper.processKey
这个函数定义在frameworks/base/libs/ui/InputReader.cpp文件中:
- voidKeyboardInputMapper::processKey(nsecs_twhen,booldown,int32_tkeyCode,
- int32_tscanCode,uint32_tpolicyFlags){
- int32_tnewMetaState;
- nsecs_tdownTime;
- boolmetaStateChanged=false;
- {//acquirelock
- AutoMutex_l(mLock);
- if(down){
- //Rotatekeycodesaccordingtoorientationifneeded.
- //Note:getDisplayInfoisnon-reentrantsowecancontinueholdingthelock.
- if(mAssociatedDisplayId>=0){
- int32_torientation;
- if(!getPolicy()->getDisplayInfo(mAssociatedDisplayId,NULL,NULL,&orientation)){
- return;
- }
- keyCode=rotateKeyCode(keyCode,orientation);
- }
- //Addkeydown.
- ssize_tkeyDownIndex=findKeyDownLocked(scanCode);
- if(keyDownIndex>=0){
- //keyrepeat,besuretousesamekeycodeasbeforeincaseofrotation
- keyCode=mLocked.keyDowns.itemAt(keyDownIndex).keyCode;
- }else{
- //keydown
- if((policyFlags&POLICY_FLAG_VIRTUAL)
- &&mContext->shouldDropVirtualKey(when,getDevice(),keyCode,scanCode)){
- return;
- }
- mLocked.keyDowns.push();
- KeyDown&keyDown=mLocked.keyDowns.editTop();
- keyDown.keyCode=keyCode;
- keyDown.scanCode=scanCode;
- }
- mLocked.downTime=when;
- }else{
- //Removekeydown.
- ssize_tkeyDownIndex=findKeyDownLocked(scanCode);
- if(keyDownIndex>=0){
- //keyup,besuretousesamekeycodeasbeforeincaseofrotation
- keyCode=mLocked.keyDowns.itemAt(keyDownIndex).keyCode;
- mLocked.keyDowns.removeAt(size_t(keyDownIndex));
- }else{
- //keywasnotactuallydown
- LOGI("Droppingkeyupfromdevice%sbecausethekeywasnotdown."
- "keyCode=%d,scanCode=%d",
- getDeviceName().string(),keyCode,scanCode);
- return;
- }
- }
- int32_toldMetaState=mLocked.metaState;
- newMetaState=updateMetaState(keyCode,down,oldMetaState);
- if(oldMetaState!=newMetaState){
- mLocked.metaState=newMetaState;
- metaStateChanged=true;
- }
- downTime=mLocked.downTime;
- }//releaselock
- if(metaStateChanged){
- getContext()->updateGlobalMetaState();
- }
- getDispatcher()->notifyKey(when,getDeviceId(),AINPUT_SOURCE_KEYBOARD,policyFlags,
- down?AKEY_EVENT_ACTION_DOWN:AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM,keyCode,scanCode,newMetaState,downTime);
- }
- //Rotatekeycodesaccordingtoorientationifneeded.
- //Note:getDisplayInfoisnon-reentrantsowecancontinueholdingthelock.
- if(mAssociatedDisplayId>=0){
- int32_torientation;
- if(!getPolicy()->getDisplayInfo(mAssociatedDisplayId,NULL,NULL,&orientation)){
- return;
- }
- keyCode=rotateKeyCode(keyCode,orientation);
- }
- //Addkeydown.
- ssize_tkeyDownIndex=findKeyDownLocked(scanCode);
- if(keyDownIndex>=0){
- //keyrepeat,besuretousesamekeycodeasbeforeincaseofrotation
- keyCode=mLocked.keyDowns.itemAt(keyDownIndex).keyCode;
- }else{
- //keydown
- if((policyFlags&POLICY_FLAG_VIRTUAL)
- &&mContext->shouldDropVirtualKey(when,getDevice(),keyCode,scanCode)){
- return;
- }
- mLocked.keyDowns.push();
- KeyDown&keyDown=mLocked.keyDowns.editTop();
- keyDown.keyCode=keyCode;
- keyDown.scanCode=scanCode;
- }
如果是松开键盘上的某个键,就把它从mLocked.keyDowns里面删除:
- //Removekeydown.
- ssize_tkeyDownIndex=findKeyDownLocked(scanCode);
- if(keyDownIndex>=0){
- //keyup,besuretousesamekeycodeasbeforeincaseofrotation
- keyCode=mLocked.keyDowns.itemAt(keyDownIndex).keyCode;
- mLocked.keyDowns.removeAt(size_t(keyDownIndex));
- }else{
- //keywasnotactuallydown
- LOGI("Droppingkeyupfromdevice%sbecausethekeywasnotdown."
- "keyCode=%d,scanCode=%d",
- getDeviceName().string(),keyCode,scanCode);
- return;
- }
最后,KeyboardInputMappger函数通知InputDispatcher,有键盘事件发生了:
- getDispatcher()->notifyKey(when,getDeviceId(),AINPUT_SOURCE_KEYBOARD,policyFlags,
- down?AKEY_EVENT_ACTION_DOWN:AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM,keyCode,scanCode,newMetaState,downTime);
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- voidInputDispatcher::notifyKey(nsecs_teventTime,int32_tdeviceId,int32_tsource,
- uint32_tpolicyFlags,int32_taction,int32_tflags,
- int32_tkeyCode,int32_tscanCode,int32_tmetaState,nsecs_tdownTime){
- ......
- if(!validateKeyEvent(action)){
- return;
- }
- /*Accordingtohttp://source.android.com/porting/keymaps_keyboard_input.html
- *Keydefinitions:KeydefinitionsfollowthesyntaxkeySCANCODEKEYCODE[FLAGS...],
- *whereSCANCODEisanumber,KEYCODEisdefinedinyourspecifickeylayoutfile
- *(android.keylayout.xxx),andpotentialFLAGSaredefinedasfollows:
- *SHIFT:Whilepressed,theshiftkeymodifierisset
- *ALT:Whilepressed,thealtkeymodifierisset
- *CAPS:Whilepressed,thecapslockkeymodifierisset
- *SinceKeyEvent.javadoesn'tcheckifCaplockisONandwedon'thavea
- *modiferstateforcaplock,wewillnotsupportit.
- */
- if(policyFlags&POLICY_FLAG_ALT){
- metaState|=AMETA_ALT_ON|AMETA_ALT_LEFT_ON;
- }
- if(policyFlags&POLICY_FLAG_ALT_GR){
- metaState|=AMETA_ALT_ON|AMETA_ALT_RIGHT_ON;
- }
- if(policyFlags&POLICY_FLAG_SHIFT){
- metaState|=AMETA_SHIFT_ON|AMETA_SHIFT_LEFT_ON;
- }
- policyFlags|=POLICY_FLAG_TRUSTED;
- mPolicy->interceptKeyBeforeQueueing(eventTime,deviceId,action,/*byref*/flags,
- keyCode,scanCode,/*byref*/policyFlags);
- boolneedWake;
- {//acquirelock
- AutoMutex_l(mLock);
- int32_trepeatCount=0;
- KeyEntry*newEntry=mAllocator.obtainKeyEntry(eventTime,
- deviceId,source,policyFlags,action,flags,keyCode,scanCode,
- metaState,repeatCount,downTime);
- needWake=enqueueInboundEventLocked(newEntry);
- }//releaselock
- if(needWake){
- mLooper->wake();
- }
- }
- staticboolisValidKeyAction(int32_taction){
- switch(action){
- caseAKEY_EVENT_ACTION_DOWN:
- caseAKEY_EVENT_ACTION_UP:
- returntrue;
- default:
- returnfalse;
- }
- }
- staticboolvalidateKeyEvent(int32_taction){
- if(!isValidKeyAction(action)){
- LOGE("Keyeventhasinvalidactioncode0x%x",action);
- returnfalse;
- }
- returntrue;
- }
参数action检查通过后,还通过policyFlags参数来检查一下同时是否有ALT和SHIFT键被按下:
- if(policyFlags&POLICY_FLAG_ALT){
- metaState|=AMETA_ALT_ON|AMETA_ALT_LEFT_ON;
- }
- if(policyFlags&POLICY_FLAG_ALT_GR){
- metaState|=AMETA_ALT_ON|AMETA_ALT_RIGHT_ON;
- }
- if(policyFlags&POLICY_FLAG_SHIFT){
- metaState|=AMETA_SHIFT_ON|AMETA_SHIFT_LEFT_ON;
- }
- boolInputDispatcher::enqueueInboundEventLocked(EventEntry*entry){
- boolneedWake=mInboundQueue.isEmpty();
- mInboundQueue.enqueueAtTail(entry);
- switch(entry->type){
- caseEventEntry::TYPE_KEY:{
- KeyEntry*keyEntry=static_cast<KeyEntry*>(entry);
- if(isAppSwitchKeyEventLocked(keyEntry)){
- if(keyEntry->action==AKEY_EVENT_ACTION_DOWN){
- mAppSwitchSawKeyDown=true;
- }elseif(keyEntry->action==AKEY_EVENT_ACTION_UP){
- if(mAppSwitchSawKeyDown){
- <spanstyle="white-space:pre"></span>......
- mAppSwitchDueTime=keyEntry->eventTime+APP_SWITCH_TIMEOUT;
- mAppSwitchSawKeyDown=false;
- needWake=true;
- }
- }
- }
- break;
- }
- }
- returnneedWake;
- }
回到前面的notifyKey函数中,根据enqueueInboundEventLocked函数的返回值来决定是否要唤醒InputDispatccherThread线程:
- if(needWake){
- mLooper->wake();
- }
Step 9. Looper.wake
这个函数定义在frameworks/base/libs/utils/Looper.cpp文件中,在前面一篇文章Android应用程序消息处理机制(Looper、Handler)分析中,我们已经分析过这个函数了,这里不再详述,简单来说,它的作用就是用来唤醒睡眠在Looper对象内部的管道读端的线程,在我们的这个场景中,睡眠在Looper对象内部的管道读端的线程就是InputDispatccherThread线程了。
从上面InputManager启动过程的Step 15中,我们知道,此时InputDispatccherThread线程正在InputDispatcher类的dispatchOnceb函数中通过调用mLooper->loopOnce函数进入睡眠状态。当它被唤醒以后,它就会从InputDispatcher类的dispatchOnceb函数返回到InputDispatcherThread类的threadLoop函数,而InputDispatcherThread类的threadLoop函数是循环执行的,于是,它又会再次进入到InputDispatcher类的dispatchOnce函数来处理当前发生的键盘事件。
Step 10.InputDispatcher.dispatchOnce
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- voidInputDispatcher::dispatchOnce(){
- nsecs_tkeyRepeatTimeout=mPolicy->getKeyRepeatTimeout();
- nsecs_tkeyRepeatDelay=mPolicy->getKeyRepeatDelay();
- nsecs_tnextWakeupTime=LONG_LONG_MAX;
- {//acquirelock
- AutoMutex_l(mLock);
- dispatchOnceInnerLocked(keyRepeatTimeout,keyRepeatDelay,&nextWakeupTime);
- ......
- }//releaselock
- ......
- }
Step 11.InputDispatcher.dispatchOnceInnerLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- voidInputDispatcher::dispatchOnceInnerLocked(nsecs_tkeyRepeatTimeout,
- nsecs_tkeyRepeatDelay,nsecs_t*nextWakeupTime){
- ......
- //Readytostartanewevent.
- //Ifwedon'talreadyhaveapendingevent,gograbone.
- if(!mPendingEvent){
- if(mInboundQueue.isEmpty()){
- ......
- }else{
- //Inboundqueuehasatleastoneentry.
- EventEntry*entry=mInboundQueue.headSentinel.next;
- ......
- mInboundQueue.dequeue(entry);
- mPendingEvent=entry;
- }
- ......
- }
- ......
- switch(mPendingEvent->type){
- ......
- caseEventEntry::TYPE_KEY:{
- KeyEntry*typedEntry=static_cast<KeyEntry*>(mPendingEvent);
- ......
- done=dispatchKeyLocked(currentTime,typedEntry,keyRepeatTimeout,
- &dropReason,nextWakeupTime);
- break;
- }
- ......
- }
- ......
- }
我们忽略了这个函数的次要逻辑,主要关注键盘事件的主要处理流程。首先,如果前面发生的键盘事件都已经处理完毕,那么这里的mPendingEvent就为NULL,又因为前面我们把刚刚发生的键盘事件加入了mInboundQueue队列,因此,这里mInboundQueue不为NULL,于是,这里就把mInboundQueue队列中的键盘事件取出来,放在mPendingEvent变量中:
- mInboundQueue.dequeue(entry);
- mPendingEvent=entry;
Step 12.InputDispatcher.dispatchKeyLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- boolInputDispatcher::dispatchKeyLocked(
- nsecs_tcurrentTime,KeyEntry*entry,nsecs_tkeyRepeatTimeout,
- DropReason*dropReason,nsecs_t*nextWakeupTime){
- ......
- //Identifytargets.
- if(!mCurrentInputTargetsValid){
- int32_tinjectionResult=findFocusedWindowTargetsLocked(currentTime,
- entry,nextWakeupTime);
- ......
- }
- //Dispatchthekey.
- dispatchEventToCurrentInputTargetsLocked(currentTime,entry,false);
- returntrue;
- }
我们先来看一InputDispatcher是如何找到当前激活的Activity窗口的,然后再分析它把键盘事件分发给当前激活Activity窗口的过程。
Step 13.InputDispatcher.findFocusedWindowTargetsLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- int32_tInputDispatcher::findFocusedWindowTargetsLocked(nsecs_tcurrentTime,
- constEventEntry*entry,nsecs_t*nextWakeupTime){
- mCurrentInputTargets.clear();
- int32_tinjectionResult;
- //Ifthereisnocurrentlyfocusedwindowandnofocusedapplication
- //thendroptheevent.
- if(!mFocusedWindow){
- if(mFocusedApplication){
- ......
- injectionResult=handleTargetsNotReadyLocked(currentTime,entry,
- mFocusedApplication,NULL,nextWakeupTime);
- gotoUnresponsive;
- }
- ......
- injectionResult=INPUT_EVENT_INJECTION_FAILED;
- gotoFailed;
- }
- //Checkpermissions.
- if(!checkInjectionPermission(mFocusedWindow,entry->injectionState)){
- injectionResult=INPUT_EVENT_INJECTION_PERMISSION_DENIED;
- gotoFailed;
- }
- //Ifthecurrentlyfocusedwindowispausedthenkeepwaiting.
- if(mFocusedWindow->paused){
- ......
- injectionResult=handleTargetsNotReadyLocked(currentTime,entry,
- mFocusedApplication,mFocusedWindow,nextWakeupTime);
- gotoUnresponsive;
- }
- //Ifthecurrentlyfocusedwindowisstillworkingonpreviouseventsthenkeepwaiting.
- if(!isWindowFinishedWithPreviousInputLocked(mFocusedWindow)){
- ......
- injectionResult=handleTargetsNotReadyLocked(currentTime,entry,
- mFocusedApplication,mFocusedWindow,nextWakeupTime);
- gotoUnresponsive;
- }
- //Success!Outputtargets.
- injectionResult=INPUT_EVENT_INJECTION_SUCCEEDED;
- addWindowTargetLocked(mFocusedWindow,InputTarget::FLAG_FOREGROUND,BitSet32(0));
- ......
- returninjectionResult;
- }
第二个if语句检查权限问题,原来,这个键盘事件除了是由硬件触发的外,也可以由其它进程注入进来的,如果这个键盘事件是由其它进程注入进来的,那么entry->injectState就不为NULL,它里面包含了事件注册者的进程ID和用户ID,于是,这里就会调用checkInjectionPermission来检查这个事件注入者的进程ID和用户ID,看看它是否具有这个权限。这里我们不考虑这种情况,因此,这里的entry->injectState为NULL,于是,这个if语句的检查也通过了。
第三个if语句检查当前激活的Activity窗口是否是处于paused状态,如果是的话,也不用进一步处理了。一般情况下,当前激活的Activity窗口都是处于resumed状态的,于是,这个if语句的检查也通过了。
第四个if语句检查当前激活的Activity窗口是否还正在处理前一个键盘事件,如果是的话,那就要等待它处理完前一个键盘事件后再来处理新的键盘事件了。这里我们也假设当前激活的Activity窗口不是正在处理前面的键盘事件,因此,这个if语句的检查也通过了。
最后,就调用addWindowTargetLocked函数把当前激活的Activity窗口添加到InputDispatcher类的mCurrentInputTargets成员变量中去。
Step 14.InputDispatcher.addWindowTargetLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- voidInputDispatcher::addWindowTargetLocked(constInputWindow*window,int32_ttargetFlags,
- BitSet32pointerIds){
- mCurrentInputTargets.push();
- InputTarget&target=mCurrentInputTargets.editTop();
- target.inputChannel=window->inputChannel;
- target.flags=targetFlags;
- target.xOffset=-window->frameLeft;
- target.yOffset=-window->frameTop;
- target.pointerIds=pointerIds;
- }
回到Step 12中的dispatchKeyLocked函数,它接下来就调用dispatchEventToCurrentInputTargetsLocked来进一步处理了。
Step 15.InputDispatcher.dispatchEventToCurrentInputTargetsLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- voidInputDispatcher::dispatchEventToCurrentInputTargetsLocked(nsecs_tcurrentTime,
- EventEntry*eventEntry,boolresumeWithAppendedMotionSample){
- ......
- for(size_ti=0;i<mCurrentInputTargets.size();i++){
- constInputTarget&inputTarget=mCurrentInputTargets.itemAt(i);
- ssize_tconnectionIndex=getConnectionIndexLocked(inputTarget.inputChannel);
- if(connectionIndex>=0){
- sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
- prepareDispatchCycleLocked(currentTime,connection,eventEntry,&inputTarget,
- resumeWithAppendedMotionSample);
- }else{
- ......
- }
- }
前面我们在分析应用程序注册键盘消息接收通道的过程时,在Step 18中(InputDispatcher.registerInputChannel),把Server端的InputChannel封装成了一个Connection,然后以这个InputChannel中的Receive Pipe Fd作为键值把这个Connection对象保存在mConnectionsByReceiveFd中。这里,既然我们已经通过mCurrentInputTargets得到了表示当前需要接收键盘事件的Activity窗口的InputTarget对象,而且这个InputTarget对象的inputChannel就表示当初在InputDispatcher中注册的Server端InputChannel,因此,这里就可以把这个Connection对象取出来,最后调用prepareDispatchCycleLocked函数来进一步处理。
Step 16.InputDispatcher.prepareDispatchCycleLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- voidInputDispatcher::prepareDispatchCycleLocked(nsecs_tcurrentTime,
- constsp<Connection>&connection,EventEntry*eventEntry,constInputTarget*inputTarget,
- boolresumeWithAppendedMotionSample){
- ......
- //Resumethedispatchcyclewithafreshlyappendedmotionsample.
- //Firstwecheckthatthelastdispatchentryintheoutboundqueueisforthesame
- //motioneventtowhichweappendedthemotionsample.Ifwefindsuchadispatch
- //entry,andifitiscurrentlyinprogressthenwetrytostreamthenewsample.
- boolwasEmpty=connection->outboundQueue.isEmpty();
- if(!wasEmpty&&resumeWithAppendedMotionSample){
- ......
- return;
- }
- //Thisisanewevent.
- //Enqueueanewdispatchentryontotheoutboundqueueforthisconnection.
- DispatchEntry*dispatchEntry=mAllocator.obtainDispatchEntry(eventEntry,//incrementsref
- inputTarget->flags,inputTarget->xOffset,inputTarget->yOffset);
- ......
- //Enqueuethedispatchentry.
- connection->outboundQueue.enqueueAtTail(dispatchEntry);
- //Iftheoutboundqueuewaspreviouslyempty,startthedispatchcyclegoing.
- if(wasEmpty){
- ......
- startDispatchCycleLocked(currentTime,connection);
- }
- }
在开始处理键盘事件之前,这个函数会检查一下传进来的参数connection中的outboundQueue事件队列是否为空,如果不为空,就要看看当前要处理的事件和outboundQueue队列中的最后一个事件是不是同一个motion事件,如果是的话,并且从上面传进来的resumeWithAppendedMotionSample参数为true,这时候就要以流水线的方式来处理这些motion事件了。在我们这个情景中,要处理的是键盘事件,因此在上面Step 12中传进来的resumeWithAppendedMotionSample参数为false,因此,我们略过这种情况。
接下来,就会把当前的键盘事件封装成一个DispatchEntry对象,然后添加到connection对象的outboundQueue队列中去,表示当前键盘事件是一个待处理的键盘事件。
当connection中的outboundQueue事件队列不为空,即wasEmpty为false时,说明当前这个Activity窗口正在处键盘事件了,因此,就不需要调用startDispatchCycleLocked来启动Activity窗口来处理这个事件了,因为一旦这个Activity窗口正在处键盘事件,它就会一直处理下去,直到它里的connection对象的outboundQueue为空为止。当connection中的outboundQueue事件队列为空时,就需要调用startDispatchCycleLocked来通知这个Activity窗口来执行键盘事件处理的流程了。
Step 17.InputDispatcher.startDispatchCycleLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- voidInputDispatcher::startDispatchCycleLocked(nsecs_tcurrentTime,
- constsp<Connection>&connection){
- ......
- DispatchEntry*dispatchEntry=connection->outboundQueue.headSentinel.next;
- //Markthedispatchentryasinprogress.
- dispatchEntry->inProgress=true;
- //Updatetheconnection'sinputstate.
- EventEntry*eventEntry=dispatchEntry->eventEntry;
- ......
- //Publishtheevent.
- status_tstatus;
- switch(eventEntry->type){
- caseEventEntry::TYPE_KEY:{
- KeyEntry*keyEntry=static_cast<KeyEntry*>(eventEntry);
- //Applytargetflags.
- int32_taction=keyEntry->action;
- int32_tflags=keyEntry->flags;
- //Publishthekeyevent.
- status=connection->inputPublisher.publishKeyEvent(keyEntry->deviceId,keyEntry->source,
- action,flags,keyEntry->keyCode,keyEntry->scanCode,
- keyEntry->metaState,keyEntry->repeatCount,keyEntry->downTime,
- keyEntry->eventTime);
- ......
- break;
- }
- ......
- }
- //Sendthedispatchsignal.
- status=connection->inputPublisher.sendDispatchSignal();
- ......
- }
Step 18. InputPublisher.publishKeyEvent
这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_tInputPublisher::publishKeyEvent(
- int32_tdeviceId,
- int32_tsource,
- int32_taction,
- int32_tflags,
- int32_tkeyCode,
- int32_tscanCode,
- int32_tmetaState,
- int32_trepeatCount,
- nsecs_tdownTime,
- nsecs_teventTime){
- ......
- status_tresult=publishInputEvent(AINPUT_EVENT_TYPE_KEY,deviceId,source);
- if(result<0){
- returnresult;
- }
- mSharedMessage->key.action=action;
- mSharedMessage->key.flags=flags;
- mSharedMessage->key.keyCode=keyCode;
- mSharedMessage->key.scanCode=scanCode;
- mSharedMessage->key.metaState=metaState;
- mSharedMessage->key.repeatCount=repeatCount;
- mSharedMessage->key.downTime=downTime;
- mSharedMessage->key.eventTime=eventTime;
- returnOK;
- }
这个匿名共享内存是什么时候创建的呢?前面我们在分析应用程序注册键盘消息接收通道的过程时,在Step 18中(InputDispatcher.registerInputChannel),在把Server端的InputChannel封装成一个 Connection对象时,会调用它的initialize成员函数来执行一些初始化工作,就是在这个时候创建这个匿名共享内存的了:
- sp<Connection>connection=newConnection(inputChannel);
- status_tstatus=connection->initialize();
- status_tInputPublisher::initialize(){
- ......
- intashmemFd=mChannel->getAshmemFd();
- intresult=ashmem_get_size_region(ashmemFd);
- ......
- mAshmemSize=(size_t)result;
- mSharedMessage=static_cast<InputMessage*>(mmap(NULL,mAshmemSize,
- PROT_READ|PROT_WRITE,MAP_SHARED,ashmemFd,0));
- ......
- mPinned=true;
- mSharedMessage->consumed=false;
- returnreset();
- }
这个匿名共享内存mSharedMessage的作用是什么呢?原来,在InputChannel中,前向管道和反向管道的作用只是用来在Server端和Client端之间相互通知有事件发生了,但是具体是什么样的事件,还需要去读取这个匿名共享内存的内容才知道。前面我们在分析应用程序注册键盘消息接收通道的过程时,在Step 14中(InputChannel.openInputChannelPair)创建Server端和Client端的InputChannel对时,创建一个匿名共享内存,这个匿名共享内存有两个文件描述符同时指向它,其中一个放在Server端的InputChannel中,另外一个放在Client端的InputChannel中。这样,当InputDispatcher通过Server端的InputChannel的前向管道来通知Client端有键盘事件发生时,Client端只要通过它的InputChannel中的匿名共享内存文件描述符去读取匿名共享内存中的内容,就可以知道发生了什么事情了。有关匿名共享内存的相关知识,请参考Android系统匿名共享内存Ashmem(Anonymous Shared Memory)简要介绍和学习计划一文。
回到Step 17中,接下来就是调用InputPublisher的成员函数sendDispatchSignal来通知Activity窗口处理键盘事件了。
Step 19.InputPublishe.sendDispatchSignal
这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_tInputPublisher::sendDispatchSignal(){
- ......
- mWasDispatched=true;
- returnmChannel->sendSignal(INPUT_SIGNAL_DISPATCH);
- }
Step 20. InputChannel.sendSignal
这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_tInputChannel::sendSignal(charsignal){
- ssize_tnWrite;
- do{
- nWrite=::write(mSendPipeFd,&signal,1);
- }while(nWrite==-1&&errno==EINTR);
- if(nWrite==1){
- ......
- returnOK;
- }
- return-errno;
- }
在前面分析应用程序注册键盘消息接收通道过程的Step 21中,我们也说过,当应用程序的主线程因为这个InputChannel中的前向管道的写端唤醒时,NativeInputQueue的成员函数handleReceiveCallback就会被回调,因此,接下来,应用程序的主线程就会被唤醒,然后执行NativeInputQueue的成员函数handleReceiveCallback。
Step 21.NativeInputQueue.handleReceiveCallback
这个函数定义在frameworks/base/core/jni/android_view_InputQueue.cpp文件中:
- intNativeInputQueue::handleReceiveCallback(intreceiveFd,intevents,void*data){
- NativeInputQueue*q=static_cast<NativeInputQueue*>(data);
- JNIEnv*env=AndroidRuntime::getJNIEnv();
- sp<Connection>connection;
- InputEvent*inputEvent;
- jobjectinputHandlerObjLocal;
- jlongfinishedToken;
- {//acquirelock
- AutoMutex_l(q->mLock);
- ssize_tconnectionIndex=q->mConnectionsByReceiveFd.indexOfKey(receiveFd);
- ......
- connection=q->mConnectionsByReceiveFd.valueAt(connectionIndex);
- ......
- status_tstatus=connection->inputConsumer.receiveDispatchSignal();
- if(status){
- ......
- return0;//removethecallback
- }
- ......
- status=connection->inputConsumer.consume(&connection->inputEventFactory,&inputEvent);
- ......
- finishedToken=generateFinishedToken(receiveFd,connection->id,connection->messageSeqNum);
- inputHandlerObjLocal=env->NewLocalRef(connection->inputHandlerObjGlobal);
- }//releaselock
- ......
- int32_tinputEventType=inputEvent->getType();
- jobjectinputEventObj;
- jmethodIDdispatchMethodId;
- switch(inputEventType){
- caseAINPUT_EVENT_TYPE_KEY:
- ......
- inputEventObj=android_view_KeyEvent_fromNative(env,
- static_cast<KeyEvent*>(inputEvent));
- dispatchMethodId=gInputQueueClassInfo.dispatchKeyEvent;
- break;
- }
- ......
- }
- ......
- env->CallStaticVoidMethod(gInputQueueClassInfo.clazz,
- dispatchMethodId,inputHandlerObjLocal,inputEventObj,
- jlong(finishedToken));
- ......
- return1;
- }
这个函数首先是通过参数data获得当初注册InputChannel的NativeInputQueue对象,具体可以参考前面介绍的应用程序注册键盘消息接收通道过程的Step 21。接下来再通过参数receiveFd获得保存在这个NativeInputQueue对象中的mConnectionsByReceiveFd成员变量中的Connection对象。有了这个Connection对象后,就可以获得它内部的InputConsumer对象,这个InputConsumer对象是和上面的Step 18中介绍的InputPublisher对象相应的。
在InputChannel内部中,分别有一个InputPublisher对象和一个InputConsumer对象,对于Server端的InputChannel来说,它使用的是InputPublisher对象,通过它进行键盘消息的分发,而对于Client端的InputChannel来说,它使用的是InputConsumer对象,通过它进行键盘消息的读取。
获得了这个InputConsumer对象后首先是调用它的receiveDispatchSignal来确认是否是接收到了键盘消息的通知,如果是的话,再调用它的consume函数来把键盘事件读取出来,最后,调用Java层的回调对象InputQueue的DispatchKeyEvent来处理这个键盘事件。下面,我们就依次来分析这些过程。
Step 22.InputConsumer.receiveDispatchSignal
这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_tInputConsumer::receiveDispatchSignal(){
- ......
- charsignal;
- status_tresult=mChannel->receiveSignal(&signal);
- if(result){
- returnresult;
- }
- if(signal!=INPUT_SIGNAL_DISPATCH){
- ......
- returnUNKNOWN_ERROR;
- }
- returnOK;
- }
InputChannel类的receiveSignal函数也是定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_tInputChannel::receiveSignal(char*outSignal){
- ssize_tnRead;
- do{
- nRead=::read(mReceivePipeFd,outSignal,1);
- }while(nRead==-1&&errno==EINTR);
- if(nRead==1){
- ......
- returnOK;
- }
- ......
- return-errno;
- }
这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_tInputConsumer::consume(InputEventFactoryInterface*factory,InputEvent**outEvent){
- ......
- *outEvent=NULL;
- intashmemFd=mChannel->getAshmemFd();
- intresult=ashmem_pin_region(ashmemFd,0,0);
- ......
- if(mSharedMessage->consumed){
- ......
- returnINVALID_OPERATION;
- }
- //Acquirebut*neverrelease*thesemaphore.Contentiononthesemaphoreisusedtosignal
- //tothepublisherthatthemessagehasbeenconsumed(orisintheprocessofbeing
- //consumed).Eventuallythepublisherwillreinitializethesemaphoreforthenextmessage.
- result=sem_wait(&mSharedMessage->semaphore);
- ......
- mSharedMessage->consumed=true;
- switch(mSharedMessage->type){
- caseAINPUT_EVENT_TYPE_KEY:{
- KeyEvent*keyEvent=factory->createKeyEvent();
- if(!keyEvent)returnNO_MEMORY;
- populateKeyEvent(keyEvent);
- *outEvent=keyEvent;
- break;
- }
- ......
- }
- returnOK;
- }
回到Step 21中的handleReceiveCallback函数中,从InputConsumer中获得了键盘事件的内容(保存在本地变量inputEvent中)后,就开始要通知Java层的应用程序了。在前面分析应用程序注册键盘消息接收通道的过程时,在Step 21中(NativeInputQueue.registerInputChannel),会把传进来的对象inputHandlerObj保存在Connection对象中:
- connection->inputHandlerObjGlobal=env->NewGlobalRef(inputHandlerObj);
- inputHandlerObjLocal=env->NewLocalRef(connection->inputHandlerObjGlobal);
- dispatchMethodId=gInputQueueClassInfo.dispatchKeyEvent;
- inputEventObj=android_view_KeyEvent_fromNative(env,
- static_cast<KeyEvent*>(inputEvent));
- env->CallStaticVoidMethod(gInputQueueClassInfo.clazz,
- dispatchMethodId,inputHandlerObjLocal,inputEventObj,
- jlong(finishedToken));
这个函数定义在frameworks/base/core/java/android/view/InputQueue.java文件中:
- publicfinalclassInputQueue{
- ......
- privatestaticvoiddispatchKeyEvent(InputHandlerinputHandler,
- KeyEventevent,longfinishedToken){
- RunnablefinishedCallback=FinishedCallback.obtain(finishedToken);
- inputHandler.handleKey(event,finishedCallback);
- }
- ......
- }
这里的inputHandler对象是在前面分析应用程序注册键盘消息接收通道的过程时,在Step 1(ViewRoot.setView)中传进来的:
- InputQueue.registerInputChannel(mInputChannel,mInputHandler,
- Looper.myQueue());
Step 25. InputHandler.handleKey
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- publicfinalclassViewRootextendsHandlerimplementsViewParent,
- View.AttachInfo.Callbacks{
- ......
- privatefinalInputHandlermInputHandler=newInputHandler(){
- publicvoidhandleKey(KeyEventevent,RunnablefinishedCallback){
- startInputEvent(finishedCallback);
- dispatchKey(event,true);
- }
- ......
- };
- ......
- }
- publicfinalclassViewRootextendsHandlerimplementsViewParent,
- View.AttachInfo.Callbacks{
- ......
- privatevoidstartInputEvent(RunnablefinishedCallback){
- ......
- mFinishedCallback=finishedCallback;
- }
- ......
- }
Step 26.ViewRoot.dispatchKey
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- publicfinalclassViewRootextendsHandlerimplementsViewParent,
- View.AttachInfo.Callbacks{
- ......
- privatevoiddispatchKey(KeyEventevent,booleansendDone){
- ......
- Messagemsg=obtainMessage(DISPATCH_KEY);
- msg.obj=event;
- msg.arg1=sendDone?1:0;
- ......
- sendMessageAtTime(msg,event.getEventTime());
- }
- ......
- }
Step 27.ViewRoot.deliverKeyEvent
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- publicfinalclassViewRootextendsHandlerimplementsViewParent,
- View.AttachInfo.Callbacks{
- ......
- privatevoiddeliverKeyEvent(KeyEventevent,booleansendDone){
- //IfmViewisnull,wejustconsumethekeyeventbecauseitdoesn't
- //makesensetodoanythingelsewithit.
- booleanhandled=mView!=null
- ?mView.dispatchKeyEventPreIme(event):true;
- ......
- //Ifitispossibleforthiswindowtointeractwiththeinput
- //methodwindow,thenwewanttofirstdispatchourkeyevents
- //totheinputmethod.
- if(mLastWasImTarget){
- InputMethodManagerimm=InputMethodManager.peekInstance();
- if(imm!=null&&mView!=null){
- ......
- imm.dispatchKeyEvent(mView.getContext(),seq,event,
- mInputMethodCallback);
- return;
- }
- }
- ......
- }
- ......
- }
Step 28. InputMethodManager.dispatchKeyEvent
这个函数定义在frameworks/base/core/java/android/view/inputmethod/InputMethodManager.java文件中。这是一个输入法相关的类,我们这里就不关注了,只要知道当输入法处理完成之后,它就会调用ViewRoot类的mInputMehtodCallback对象的finishedEvent成员函数。
Step 29. InputMethodCallack.finishedEvent
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- publicfinalclassViewRootextendsHandlerimplementsViewParent,
- View.AttachInfo.Callbacks{
- ......
- staticclassInputMethodCallbackextendsIInputMethodCallback.Stub{
- privateWeakReference<ViewRoot>mViewRoot;
- publicInputMethodCallback(ViewRootviewRoot){
- mViewRoot=newWeakReference<ViewRoot>(viewRoot);
- }
- publicvoidfinishedEvent(intseq,booleanhandled){
- finalViewRootviewRoot=mViewRoot.get();
- if(viewRoot!=null){
- viewRoot.dispatchFinishedEvent(seq,handled);
- }
- }
- ......
- }
- ......
- }
Step 30.ViewRoot.dispatchFinishedEvent
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- publicfinalclassViewRootextendsHandlerimplementsViewParent,
- View.AttachInfo.Callbacks{
- ......
- publicvoiddispatchFinishedEvent(intseq,booleanhandled){
- Messagemsg=obtainMessage(FINISHED_EVENT);
- msg.arg1=seq;
- msg.arg2=handled?1:0;
- sendMessage(msg);
- }
- ......
- }
Step 31.ViewRoot.handleFinishedEvent
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- publicfinalclassViewRootextendsHandlerimplementsViewParent,
- View.AttachInfo.Callbacks{
- ......
- voidhandleFinishedEvent(intseq,booleanhandled){
- finalKeyEventevent=(KeyEvent)retrievePendingEvent(seq);
- ......
- if(event!=null){
- finalbooleansendDone=seq>=0;
- if(!handled){
- deliverKeyEventToViewHierarchy(event,sendDone);
- return;
- }elseif(sendDone){
- ......
- }else{
- ......
- }
- }
- }
- ......
- }
Step 32.ViewRoot.deliverKeyEventToViewHierarchy
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- publicfinalclassViewRootextendsHandlerimplementsViewParent,
- View.AttachInfo.Callbacks{
- ......
- privatevoiddeliverKeyEventToViewHierarchy(KeyEventevent,booleansendDone){
- try{
- if(mView!=null&&mAdded){
- ......
- booleankeyHandled=mView.dispatchKeyEvent(event);
- }
- ......
- }finally{
- if(sendDone){
- finishInputEvent();
- }
- }
- }
- ......
- }
ViewRoot类的成员变量mView的类型为DecorView,它是由ActivityThread类第一次Resume当前的Activity窗口时创建的,具体可以参考ActivityThread类的handleResumeActivity成员函数,这里就不关注了。
Step 33. DecorView.dispatchKeyEvent
这个函数定义在frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java文件中,它是PhoneWindow类的一个内部类:
- publicclassPhoneWindowextendsWindowimplementsMenuBuilder.Callback{
- ......
- privatefinalclassDecorViewextendsFrameLayoutimplementsRootViewSurfaceTaker{
- ......
- @Override
- publicbooleandispatchKeyEvent(KeyEventevent){
- ......
- finalCallbackcb=getCallback();
- finalbooleanhandled=cb!=null&&mFeatureId<0?cb.dispatchKeyEvent(event)
- :super.dispatchKeyEvent(event);
- ......
- }
- ......
- }
- ......
- }
Step 34. Activity.dispatchKeyEvent
这个函数定义在frameworks/base/core/java/android/app/Activity.java文件中:
- publicclassActivityextendsContextThemeWrapper
- implementsLayoutInflater.Factory,
- Window.Callback,KeyEvent.Callback,
- OnCreateContextMenuListener,ComponentCallbacks{
- ......
- publicbooleandispatchKeyEvent(KeyEventevent){
- ......
- Viewdecor=mDecor;
- if(decor==null)decor=win.getDecorView();
- returnevent.dispatch(this,decor!=null
- ?decor.getKeyDispatcherState():null,this);
- }
- ......
- }
Step 35. KeyEvent.dispatch
这个函数定义在frameworks/base/core/java/android/view/KeyEvent.java文件中:
- publicclassKeyEventextendsInputEventimplementsParcelable{
- ......
- publicfinalbooleandispatch(Callbackreceiver,DispatcherStatestate,
- Objecttarget){
- switch(mAction){
- caseACTION_DOWN:{
- ......
- booleanres=receiver.onKeyDown(mKeyCode,this);
- ......
- returnres;
- }
- caseACTION_UP:
- ......
- returnreceiver.onKeyUp(mKeyCode,this);
- caseACTION_MULTIPLE:
- finalintcount=mRepeatCount;
- finalintcode=mKeyCode;
- if(receiver.onKeyMultiple(code,count,this)){
- returntrue;
- }
- ......
- returnfalse;
- }
- returnfalse;
- }
- ......
- }
Activity窗口处理完这个键盘事件后,层层返回,最后回到Step 32中,调用finishInputEvent事件来处理一些手尾工,下面我们将会看到这些手尾工是什么。
Step 36. ViewRoot.finishInputEvent
这个函数定义在frameworks/base/core/java/android/view/ViewRoot.java文件中:
- publicfinalclassViewRootextendsHandlerimplementsViewParent,
- View.AttachInfo.Callbacks{
- ......
- privatevoidfinishInputEvent(){
- ......
- if(mFinishedCallback!=null){
- mFinishedCallback.run();
- mFinishedCallback=null;
- }else{
- ......
- }
- }
- ......
- }
ViewRoot类里面的成员变量mFinishedCallback是在前面Step 25中由InputQueue设置的,它是一个Runnable对象,实际类型是定义在InputQueue的内部类FinishedCallback,因此,这里调用它的run方法时,接下来就会调用InputQueue的内部类FinishedCallback的run成员函数:
- publicfinalclassInputQueue{
- ......
- privatestaticclassFinishedCallbackimplementsRunnable{
- ......
- publicvoidrun(){
- synchronized(sLock){
- ......
- nativeFinished(mFinishedToken);
- ......
- }
- }
- ......
- }
- ......
- }
Step 37. InputQueue.nativeFinished
这个函数定义在frameworks/base/core/jni/android_view_InputQueue.cpp文件中:
- staticvoidandroid_view_InputQueue_nativeFinished(JNIEnv*env,jclassclazz,
- jlongfinishedToken){
- status_tstatus=gNativeInputQueue.finished(
- env,finishedToken,false/*ignoreSpuriousFinish*/);
- ......
- }
Step 38. NativeInputQueue.finished
这个函数定义在frameworks/base/core/jni/android_view_InputQueue.cpp文件中:
- status_tNativeInputQueue::finished(JNIEnv*env,jlongfinishedToken,boolignoreSpuriousFinish){
- int32_treceiveFd;
- uint16_tconnectionId;
- uint16_tmessageSeqNum;
- parseFinishedToken(finishedToken,&receiveFd,&connectionId,&messageSeqNum);
- {//acquirelock
- AutoMutex_l(mLock);
- ssize_tconnectionIndex=mConnectionsByReceiveFd.indexOfKey(receiveFd);
- ......
- sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
- ......
- connection->messageInProgress=false;
- status_tstatus=connection->inputConsumer.sendFinishedSignal();
- ......
- }//releaselock
- returnOK;
- }
- finishedToken=generateFinishedToken(receiveFd,connection->id,connection->messageSeqNum);
- jlongNativeInputQueue::generateFinishedToken(int32_treceiveFd,uint16_tconnectionId,
- uint16_tmessageSeqNum){
- return(jlong(receiveFd)<<32)|(jlong(connectionId)<<16)|jlong(messageSeqNum);
- }
因此,在上面的finished函数里面,首先就是要对参数值finishedToken进行解码,把receiveFd、connectionId和messageSeqNum三个值分别取回来:
- parseFinishedToken(finishedToken,&receiveFd,&connectionId,&messageSeqNum);
- voidNativeInputQueue::parseFinishedToken(jlongfinishedToken,
- int32_t*outReceiveFd,uint16_t*outConnectionId,uint16_t*outMessageIndex){
- *outReceiveFd=int32_t(finishedToken>>32);
- *outConnectionId=uint16_t(finishedToken>>16);
- *outMessageIndex=uint16_t(finishedToken);
- }
- ssize_tconnectionIndex=mConnectionsByReceiveFd.indexOfKey(receiveFd);
- ......
- sp<Connection>connection=mConnectionsByReceiveFd.valueAt(connectionIndex);
- status_tstatus=connection->inputConsumer.sendFinishedSignal();
Step 39. InputConsumer.sendFinishedSignal
这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_tInputConsumer::sendFinishedSignal(){
- ......
- returnmChannel->sendSignal(INPUT_SIGNAL_FINISHED);
- }
前面我们在分析应用程序注册键盘消息接收通道的过程时,在Step 18(InputDispatcher.registerInputChannel)中,说到InputDispatcher把一个反向管道的读端文件描述符添加到WindowManagerService所运行的线程中的Looper对象中去,然后就会在这个反向管道的读端上睡眠等待有这个管道有新的内容可读。现在,InputConsumer往这个反向管道写入新的内容了,于是,InputDispatcher就被唤醒过来了,唤醒过来后,它所调用的函数是InputDispatcher.handleReceiveCallback函数,这与前面的Step 21的逻辑是一样的。
Step 40. InputDispatcher.handleReceiveCallack
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- intInputDispatcher::handleReceiveCallback(intreceiveFd,intevents,void*data){
- InputDispatcher*d=static_cast<InputDispatcher*>(data);
- {//acquirelock
- AutoMutex_l(d->mLock);
- ssize_tconnectionIndex=d->mConnectionsByReceiveFd.indexOfKey(receiveFd);
- ......
- nsecs_tcurrentTime=now();
- sp<Connection>connection=d->mConnectionsByReceiveFd.valueAt(connectionIndex);
- ......
- status_tstatus=connection->inputPublisher.receiveFinishedSignal();
- if(status){
- ......
- return0;//removethecallback
- }
- d->finishDispatchCycleLocked(currentTime,connection);
- ......
- return1;
- }//releaselock
- }
- ssize_tconnectionIndex=d->mConnectionsByReceiveFd.indexOfKey(receiveFd);
- ......
- sp<Connection>connection=d->mConnectionsByReceiveFd.valueAt(connectionIndex);
Step 41. InputPublisher.receiverFinishedSignal
这个函数定义在frameworks/base/libs/ui/InputTransport.cpp文件中:
- status_tInputPublisher::receiveFinishedSignal(){
- ....
- charsignal;
- status_tresult=mChannel->receiveSignal(&signal);
- if(result){
- returnresult;
- }
- if(signal!=INPUT_SIGNAL_FINISHED){
- .......
- returnUNKNOWN_ERROR;
- }
- returnOK;
- }
回到前面的Step 40中,确认了是真的收到了键盘事件处理完成的信号后,就调用InputDispatcher的finishDispatchCycleLocked函数来执行一些善后工作了。
Step 42. InputDispatcher.finishDispatchCycleLocked
这个函数定义在frameworks/base/libs/ui/InputDispatcher.cpp文件中:
- voidInputDispatcher::finishDispatchCycleLocked(nsecs_tcurrentTime,
- constsp<Connection>&connection){
- ......
- //Notifyothersystemcomponents.
- onDispatchCycleFinishedLocked(currentTime,connection);
- //Resetthepublishersincetheeventhasbeenconsumed.
- //Wedothisnowsothatthepublishercanreleasesomeofitsinternalresources
- //whilewaitingforthenextdispatchcycletobegin.
- status_tstatus=connection->inputPublisher.reset();
- ......
- startNextDispatchCycleLocked(currentTime,connection);
- }
一是通知其它系统,InputDispatcher完成了一次键盘事件的处理:
- //Notifyothersystemcomponents.
- onDispatchCycleFinishedLocked(currentTime,connection);
- //Resetthepublishersincetheeventhasbeenconsumed.
- //Wedothisnowsothatthepublishercanreleasesomeofitsinternalresources
- //whilewaitingforthenextdispatchcycletobegin.
- status_tstatus=connection->inputPublisher.reset();
- startNextDispatchCycleLocked(currentTime,connection);
至此,InputManager分发键盘消息给应用程序的过程就分析完成了,这是一个比较复杂的过程,不过,只要我们抓住主要的线索,就不难理解了,现在我们就小结一下这个过程的四个主要线索:
A. 键盘事件发生,InputManager中的InputReader被唤醒,此前InputReader睡眠在/dev/input/event0这个设备文件上;
B.InputReader被唤醒后,它接着唤醒InputManager中的InputDispatcher,此前InputDispatcher睡眠在InputManager所运行的线程中的Looper对象里面的管道的读端上;
C. InputDispatcher被唤醒后,它接着唤醒应用程序的主线程来处理这个键盘事件,此前应用程序的主线程睡眠在Client端InputChannel中的前向管道的读端上;
D. 应用程序处理处理键盘事件之后,它接着唤醒InputDispatcher来执行善后工作,此前InputDispatcher睡眠在Server端InputChannel的反向管道的读端上,注意这里与第二个线索处的区别。
----
下接:Android应用程序键盘(Keyboard)消息处理机制分析(四)