该小节我们讲解,Dispatcher线程是如何分发事件的,在这之前,我们先回顾一下之前的学习,下面是一个框图: 在前面已经分析过,Dispatcher线程会对数据进行一些处理之后,再分发出去。他首先会把输入事件分为类(如:Global,System,user等等,对于Global,System处理完之后会直接抛弃,user类会加入队列,然后分发给应用程序。分发过程一般如下:1.查找目标APP,得到connection。2,把输入事件放入对应connection的mOutBoundQueue队列,然后进行分发。
在上小节的视频中,我们可以知道Dispatcher线程线程中,存在mConnectionsByFd,里面存在多个connection,每个connection中包括了 inputChannel, inputChannel中又包括了fd1,并且在对应的APP中,存在相应的fd2,这两个fd来源于 SocketPair,下面是他的主要步骤: 1.查找目标:向WindowManagerService查询当前窗口,获得对应的connection。 2.把输入事件放入connection中的mOutBoundQueue队列。 3.从队列中取出事件逐个写入到文件句柄中。(这样,另外一边的APP就能从对应的fd中读取事件) 下面我们就根据上述的几个步骤分析源代码
源码分析在前面的讲解中,都是依照按键的流程进行分析,已经分析到了InputDispatcher.cpp中的dispatchKeyLocked函数,该函数对输入事件进行稍微的处理之后,就会进行分发:
InputDispatcher::dispatchKeyLocked()
injectionResult = findFocusedWindowTargetsLocked(currentTime,entry, inputTargets, nextWakeupTime);//查找目标窗口
if (mFocusedWindowHandle == NULL) {//该变量表示最外面的窗口运行程序,该处不去分析其内部是如何设置
...............................//获取最外面的窗口
if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {//权限检查
/*使用mFocusedWindowHandle构建一个InputTarget*/
addWindowTargetLocked(mFocusedWindowHandle,InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS,BitSet32(0),inputTargets);
/*核心:把查询到的inputChannel赋值给 target.inputChannel*/
target.inputChannel = windowInfo->inputChannel;
dispatchEventLocked(currentTime, entry, inputTargets);//发送事件
ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);//获取fd的索引
/*根据fd的索引提取对应的connection*/
sp connection = mConnectionsByFd.valueAt(connectionIndex);
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
/*把事件(多个)放入队列*/
enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
enqueueDispatchEntryLocked()
/*把dispatchEntry(某个事件)放入到connection的队列的尾部*/
connection->waitQueue.enqueueAtTail(dispatchEntry);
/*从队列取出事件,写入到对应的文件句柄之中*/
startDispatchCycleLocked(currentTime, connection);
/*从队列头部取出一个事件*/
DispatchEntry* dispatchEntry = connection->outboundQueue.head;
case EventEntry::TYPE_KEY: {//如果为按键事件
connection->inputPublisher.publishKeyEvent()//发送事件
mChannel->sendMessage(&msg);//构建一个msg,调用该函数发送
/*写入到mFd中,对应的应用程序,马上就能读取到事件*/
nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
函数调用到send(),Dispatcher线程基本完成了他的使命,剩下的就是应用程序的事情了。上述函数的详细调用框图如下: