您的位置:首页 > 移动开发 > Android开发

[Android] 输入系统(一)

2015-08-22 03:00 309 查看
Android输入系统是人与机器交互最主要的手段。我们通过按键或者触碰屏幕,会先经由linux产生中断,进行统一的处理过后,转换成Android能识别的事件信息,然后Android的输入系统去获取事件,分发给上层用户程序进行处理。

下面在细分一下输入事件在Android系统中的流程:





从图上能看到,输入事件有四个处理的地方:

InputReaderThread

InputDispatcherThread

WindowInputEventReceiver

handleReceiverCallback

上面四个地方按功能来划分,其中:

InputReaderThread负责从输入设备中获取事件,事件加入inboundQueue队列。

InputDispatcherThread负责把inboundQueue中的事件信息取出,并且从系统中获取该事件所需要分发到的目标(窗口),把事件与目标分别整合成分发项,把分发项加入outboundQueue。另外,这里还是事件的分发端,负责把outboundQueue中的事件取出,通过InputChannel进行分发。分发完成后把该事件入waitQueue。

WindowInputEventReceiver是事件的接收端。事件会在这里被onTouch这类回调函数处理

handleReceiveCallback用于接收处理过后的反馈信息,事件在WindowInputEventReceiver端被处理成功或者失败,将会通过InputChannel返回Handled或者UNHandled消息。handleReceiveCallback接收到消息后将会对waitQueue中的事件进行出队列处理。

InputManager

InputManager用于启动InputReaderThread与InputDispatcherThread,会在system_server初始化的时候被创建并且调用InputManager的start方法启动这两个线程。

InputManager的构造函数如下:

InputManager::InputManager( constsp<EventHubInterface>&eventHub, constsp<InputReaderPolicyInterface>&readerPolicy, constsp<InputDispatcherPolicyInterface>&dispatcherPolicy){ mDispatcher=newInputDispatcher(dispatcherPolicy); mReader=newInputReader(eventHub,readerPolicy,mDispatcher); initialize(); }
可以看到构造了InputDispatcher与InputReader两个类,这两个类是功能类,分别为InputDispatcherThread与InputReaderThread提供功能。另外,在构建InputReader的时候,把mDispatcher传递了进去,用于构建QueueInputListener。在这里可以提前说明一下这个成员的作用:把输入事件添加到inboundQueue。

构造函数最后调用了initialize,构建InputReaderThread、InputDispatcherThread。

voidInputManager::initialize(){ mReaderThread=newInputReaderThread(mReader); mDispatcherThread=newInputDispatcherThread(mDispatcher); }
InputManager的start用于启动InputReaderThread与InputDispatcherThread这两个线程。

status_tInputManager::start(){ status_tresult=mDispatcherThread->run("InputDispatcher",PRIORITY_URGENT_DISPLAY); if(result){ ALOGE("CouldnotstartInputDispatcherthreadduetoerror%d.",result); returnresult; } result=mReaderThread->run("InputReader",PRIORITY_URGENT_DISPLAY); if(result){ ALOGE("CouldnotstartInputReaderthreadduetoerror%d.",result); mDispatcherThread->requestExit(); returnresult; } returnOK; }



InputReaderThread

InputReaderThread是用来从输入设备中读取输入事件的,首先看一下该线程的threadLoop函数

boolInputReaderThread::threadLoop(){ mReader->loopOnce(); returntrue; }

mReader即在构建InputReaderThread时传进来的InputReader,负责实现读取输入事件所需要的各种功能。InputReader::loopOnce用于读取一次输入事件。其中,读取一次包含三个主要动作:

获取输入事件

处理输入事件

输入数据flush

voidInputReader::loopOnce(){ size_tcount=mEventHub->getEvents(timeoutMillis,mEventBuffer,EVENT_BUFFER_SIZE); {//acquirelock processEventsLocked(mEventBuffer,count); } mQueuedListener->flush(); }

1.获取输入事件getEvents

几乎所有与输入有关的事件都会从这里获得。其中包含:

EPOLL_ID_INORIFY.输入设备打开或者删除的事件

EPOLL_ID_WAKE.管道发送过来的模拟事件

EPOLL_IN.按键,触摸这类实际操作事件

EPOLL_ID_INOTIFY,用于监控某个目录(子目录)下是否有新增或者删除文件,在这里用于监视/dev/input,这个是输入设备文件所在的目录,如果有新增设备,则会在该目录内创建新文件;如果删除设备,则该目录的相应文件会被删除。

if(eventItem.data.u32==EPOLL_ID_INOTIFY){ if(eventItem.events&EPOLLIN){ mPendingINotify=true; }else{ ALOGW("Receivedunexpectedepollevent0x%08xforINotify.",eventItem.events); } continue; } ...... if(mPendingINotify&&mPendingEventIndex>=mPendingEventCount){ mPendingINotify=false; readNotifyLocked(); deviceChanged=true; } status_tEventHub::readNotifyLocked(){ if(event->mask&IN_CREATE){ openDeviceLocked(devname); }else{ ALOGI("Removingdevice'%s'duetoinotifyevent\n",devname); closeDeviceByPathLocked(devname); } }

EPOLL_ID_WAKE,EventHub有维护一个pipe,当pipe的写入端按照适当格式写入时间后,getEvents可以通过pipe的读取端获取这个虚拟事件

if(eventItem.data.u32==EPOLL_ID_WAKE){ if(eventItem.events&EPOLLIN){ ALOGV("awokenafterwake()"); awoken=true; charbuffer[16]; ssize_tnRead; do{ nRead=read(mWakeReadPipeFd,buffer,sizeof(buffer)); }while((nRead==-1&&errno==EINTR)||nRead==sizeof(buffer)); }else{ ALOGW("Receivedunexpectedepollevent0x%08xforwakereadpipe.", eventItem.events); } continue; }

EPOLL_IN,用于监控设备文件的输入状态,当我们按键或者触摸设备时,我们就能获得EPOLL_IN状态,从而到该设备读取输入事件

if(eventItem.events&EPOLLIN){ int32_treadSize=read(device->fd,readBuffer, sizeof(structinput_event)*capacity); event->when=now; event->deviceId=deviceId; event->type=iev.type; event->code=iev.code; event->value=iev.value; event+=1; capacity-=1; }

监听事件用的是epoll_wait,由于epoll_wait一次能获取的事件可能会有多个,所以一次的getEvents需要对所获得的每个事件都进行上述代码的打包操作,最后返回事件数组。

intpollResult=epoll_wait(mEpollFd,mPendingEventItems,EPOLL_MAX_EVENTS,timeoutMillis);



2.处理输入事件processEventsLocked

由getEvents获得的事件数组会在这个函数内进行处理,其中事件数组中的事件大致可以分为两类,在这个函数将他们分开处理

按键、触摸事件

设备增加、删除事件

voidInputReader::processEventsLocked(constRawEvent*rawEvents,size_tcount){ for(constRawEvent*rawEvent=rawEvents;count;){ int32_ttype=rawEvent->type; size_tbatchSize=1; if(type<EventHubInterface::FIRST_SYNTHETIC_EVENT){ int32_tdeviceId=rawEvent->deviceId; while(batchSize<count){ if(rawEvent[batchSize].type>=EventHubInterface::FIRST_SYNTHETIC_EVENT ||rawEvent[batchSize].deviceId!=deviceId){ break; } batchSize+=1; } #ifDEBUG_RAW_EVENTS ALOGD("BatchSize:%dCount:%d",batchSize,count); #endif processEventsForDeviceLocked(deviceId,rawEvent,batchSize); }else{ switch(rawEvent->type){ caseEventHubInterface::DEVICE_ADDED: addDeviceLocked(rawEvent->when,rawEvent->deviceId); break; caseEventHubInterface::DEVICE_REMOVED: removeDeviceLocked(rawEvent->when,rawEvent->deviceId); break; caseEventHubInterface::FINISHED_DEVICE_SCAN: handleConfigurationChangedLocked(rawEvent->when); break; default: ALOG_ASSERT(false);//can'thappen break; } } count-=batchSize; rawEvent+=batchSize; } }

在处理按键、触摸事件时,会根据他们设备的类型调用不同的process函数进行处理。对于触摸事件,基本上只是进行赋值,而按键事件则需要通过映射,把从设备文件读取进来的值转换成Android上层能统一处理的按键事件。

voidInputReader::processEventsForDeviceLocked(int32_tdeviceId, constRawEvent*rawEvents,size_tcount){ InputDevice*device=mDevices.valueAt(deviceIndex); device->process(rawEvents,count); } voidKeyboardInputMapper::process(constRawEvent*rawEvent){ switch(rawEvent->type){ caseEV_KEY:{ if(getEventHub()->mapKey(getDeviceId(),scanCode,usageCode,&keyCode,&flags)){ keyCode=AKEYCODE_UNKNOWN; flags=0; } processKey(rawEvent->when,rawEvent->value!=0,keyCode,scanCode,flags); } break; } }

上面的mapKey对按键进行了映射处理,processKey用于区分按键的按下或者松开。在processKey的最后,会把事件打包成NotifyKeyArgs,然后通过QueueInputListener把事件push进mArgQueue。由于这里是一个事件数组,所以mArgQueue是必须的。

voidKeyboardInputMapper::processKey(nsecs_twhen,booldown,int32_tkeyCode, int32_tscanCode,uint32_tpolicyFlags){ if(down){ ... }else{ ... } NotifyKeyArgsargs(when,getDeviceId(),mSource,policyFlags, down?AKEY_EVENT_ACTION_DOWN:AKEY_EVENT_ACTION_UP, AKEY_EVENT_FLAG_FROM_SYSTEM,keyCode,scanCode,newMetaState,downTime); getListener()->notifyKey(&args); } voidQueuedInputListener::notifyKey(constNotifyKeyArgs*args){ mArgsQueue.push(newNotifyKeyArgs(*args)); }



3.输入数据flush

在事件数组都push进mArgQueue之后,就需要把mArgQueue队列给推送出去进行下一步的操作,mQueuedListener->flush();就是负责进行队列的推送。还记得我们最开始说的”在构建InputReader的时候,把mDispatcher传递了进去,用于构建QueueInputListener”,我们这里的flush最终就是调用了InputDispatcher的notifyKey

voidQueuedInputListener::flush(){ size_tcount=mArgsQueue.size(); for(size_ti=0;i<count;i++){ NotifyArgs*args=mArgsQueue[i]; args->notify(mInnerListener); deleteargs; } mArgsQueue.clear(); } voidNotifyKeyArgs::notify(constsp<InputListenerInterface>&listener)const{ listener->notifyKey(this); }



以notifyKey为例,其目的实际上是把事件队列加入mInboundQueue,但是在入mInboundQueue队列之前,调用了interceptKeyBeforeQueueing,该函数通过jni,调用到PhoneWindowManager的interceptKeyBeforeQueueing。而在入了mInboundQueue队列后,就会调用wake函数去唤醒InputDispatcherThread。下一步就是InputDispatcherThread的工作了。

voidInputDispatcher::notifyKey(constNotifyKeyArgs*args){ mPolicy->interceptKeyBeforeQueueing(&event,/*byref*/policyFlags); needWake=enqueueInboundEventLocked(newEntry); if(needWake){ mLooper->wake(); } }

InputDispatcherThread

InputDispatcherThread是用来进行事件分发的线程。内部也是调用InputDispatcher来实现所需要的功能。

boolInputDispatcherThread::threadLoop(){ mDispatcher->dispatchOnce(); returntrue; }

每次分发,调用的都是dispatchOnce,其内部调用dispatchOnceInnerLocked进行分发后,线程会调用pollOnce进入睡眠,等待下次InputReaderThread的wake操作

voidInputDispatcher::dispatchOnce(){ dispatchOnceInnerLocked(&nextWakeupTime); mLooper->pollOnce(timeoutMillis); }

分发的过程可以大概分成以下几个步骤:

从mInboundQueue的队列头取出事件

特殊事件的处理,如POLICY_FLAG_PASS_TO_USER这类事件能直接发送到用户,类似于电量不足的这类事件:当电量低于20%时,直接往上层发送事件,而不用知道当前是在哪个Activity

一般事件的处理,进行分发

voidInputDispatcher::dispatchOnceInnerLocked(nsecs_t*nextWakeupTime){ mPendingEvent=mInboundQueue.dequeueAtHead(); //Pokeuseractivityforthisevent. if(mPendingEvent->policyFlags&POLICY_FLAG_PASS_TO_USER){ pokeUserActivityLocked(mPendingEvent); } switch(mPendingEvent->type){ caseEventEntry::TYPE_KEY:{ done=dispatchKeyLocked(currentTime,typedEntry,&dropReason,nextWakeupTime); break; } } }

分发事件,肯定需要知道事件要分发到哪里,即分发的目标窗口,不过目标窗口可能不止一个。

boolInputDispatcher::dispatchKeyLocked(nsecs_tcurrentTime,KeyEntry*entry, DropReason*dropReason,nsecs_t*nextWakeupTime){ int32_tinjectionResult=findFocusedWindowTargetsLocked(currentTime, entry,inputTargets,nextWakeupTime); //Dispatchthekey. dispatchEventLocked(currentTime,entry,inputTargets); returntrue; }

由于可能存在多个目标窗口,所以需要对每个目标窗口都进行事件分发

voidInputDispatcher::dispatchEventLocked(nsecs_tcurrentTime, EventEntry*eventEntry,constVector<InputTarget>&inputTargets){ for(size_ti=0;i<inputTargets.size();i++){ prepareDispatchCycleLocked(currentTime,connection,eventEntry,&inputTarget); } }

在分发前的准备,就是把事件入outboundQueue队列,不过请注意,这里的队列不同于inboundQueue,因为outboundQueue是窗口相关的,窗口跟InputDispatcherThread间建立起一个连接(connection),该outboundQueue就是connection的成员。

voidInputDispatcher::prepareDispatchCycleLocked(nsecs_tcurrentTime, constsp<Connection>&connection,EventEntry*eventEntry,constInputTarget*inputTarget){ //Notsplitting.Enqueuedispatchentriesfortheeventasis. enqueueDispatchEntriesLocked(currentTime,connection,eventEntry,inputTarget); } voidInputDispatcher::enqueueDispatchEntriesLocked(nsecs_tcurrentTime, constsp<Connection>&connection,EventEntry*eventEntry,constInputTarget*inputTarget){ boolwasEmpty=connection->outboundQueue.isEmpty(); //Enqueuedispatchentriesfortherequestedmodes. enqueueDispatchEntryLocked(connection,eventEntry,inputTarget, InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); enqueueDispatchEntryLocked(connection,eventEntry,inputTarget, InputTarget::FLAG_DISPATCH_AS_OUTSIDE); enqueueDispatchEntryLocked(connection,eventEntry,inputTarget, InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); enqueueDispatchEntryLocked(connection,eventEntry,inputTarget, InputTarget::FLAG_DISPATCH_AS_IS); enqueueDispatchEntryLocked(connection,eventEntry,inputTarget, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); enqueueDispatchEntryLocked(connection,eventEntry,inputTarget, InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); //Iftheoutboundqueuewaspreviouslyempty,startthedispatchcyclegoing. if(wasEmpty&&!connection->outboundQueue.isEmpty()){ startDispatchCycleLocked(currentTime,connection); } } voidInputDispatcher::enqueueDispatchEntryLocked( constsp<Connection>&connection,EventEntry*eventEntry,constInputTarget*inputTarget, int32_tdispatchMode){ //Enqueuethedispatchentry. connection->outboundQueue.enqueueAtTail(dispatchEntry); }

在准备完成后就会调用startDispatchCycleLocked进行事件分发,startDispatchCycleLocked这个函数的主体是一个while循环,在循环体内会执行下面三个主要步骤:

调用connection的inputPublisher来发出事件

把事件从outboundQueue队列中移除

把事件加入waitQueue队列,当事件在处理完成后返回,就会从waitQueue中删除该事件

voidInputDispatcher::startDispatchCycleLocked(nsecs_tcurrentTime, constsp<Connection>&connection){ while(connection->status==Connection::STATUS_NORMAL &&!connection->outboundQueue.isEmpty()){ DispatchEntry*dispatchEntry=connection->outboundQueue.head; switch(eventEntry->type){ caseEventEntry::TYPE_KEY:{ KeyEntry*keyEntry=static_cast<KeyEntry*>(eventEntry); //Publishthekeyevent. status=connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId,keyEntry->source, dispatchEntry->resolvedAction,dispatchEntry->resolvedFlags, keyEntry->keyCode,keyEntry->scanCode, keyEntry->metaState,keyEntry->repeatCount,keyEntry->downTime, keyEntry->eventTime); } } //Re-enqueuetheeventonthewaitqueue. connection->outboundQueue.dequeue(dispatchEntry); traceOutboundQueueLengthLocked(connection); connection->waitQueue.enqueueAtTail(dispatchEntry); traceWaitQueueLengthLocked(connection); } }

我们来看一下inputPublisher的publishKeyEvent的实现,最后也是调用socket的send接口来实现。

status_tInputPublisher::publishKeyEvent( uint32_tseq, int32_tdeviceId, int32_tsource, int32_taction, int32_tflags, int32_tkeyCode, int32_tscanCode, int32_tmetaState, int32_trepeatCount, nsecs_tdownTime, nsecs_teventTime){ InputMessagemsg; msg.header.type=InputMessage::TYPE_KEY; msg.body.key.seq=seq; msg.body.key.deviceId=deviceId; msg.body.key.source=source; msg.body.key.action=action; msg.body.key.flags=flags; msg.body.key.keyCode=keyCode; msg.body.key.scanCode=scanCode; msg.body.key.metaState=metaState; msg.body.key.repeatCount=repeatCount; msg.body.key.downTime=downTime; msg.body.key.eventTime=eventTime; returnmChannel->sendMessage(&msg); } status_tInputChannel::sendMessage(constInputMessage*msg){ do{ nWrite=::send(mFd,msg,msgLength,MSG_DONTWAIT|MSG_NOSIGNAL); }while(nWrite==-1&&errno==EINTR); }




总体的流程如下



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: