通过前面几个小节,知道Reader线程从驱动读取到事件之后,还要经过很多的处理才能发送给应用程序,我们来回顾一下,再次粘贴框图如下:
Reader线程读取事件之后,会把事件稍作处理,然后放入mInboundQueue队列中,然后Dispatcher线程会从这个队列中读取事件,稍作处理之后把这些事件放入到APP应用程序mOutBoundQueue队列之中。然后取出事件发送给对应的APP。
从前面的小节我们知道,Reader线程从驱动读取到事件之后,会调用
getListener()->notifyKey(&args);//通知Dispatcher线程
通知Dispatcher线程,该函数notifyKey位于InputDispatcher.cpp中,首先调用:
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
稍作处理,然后无论处理结果如何,调用:
needWake = enqueueInboundEventLocked(newEntry);
if (needWake) {
mLooper->wake();
}
放入mInbound队列中,然后唤醒Dispatcher线程,Dispatcher线程线程的主题循环(InputDispatcher.cpp中):
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
if (!haveCommandsLocked()) {//如果没有命令
dispatchOnceInnerLocked(&nextWakeupTime);//生成命令
if (runCommandsLockedInterruptible()) {//运行命令
nextWakeupTime = LONG_LONG_MIN;
单命令队列为空的时候,会从mInboundQueue取出事件,用它生成命令,然后放入命令队列,或者直接丢弃。,然后通过runCommandsLockedInterruptible()运行命令(对事件稍作处理),最后Dispatcher他。
这是一个大概的流程,下面我们开始阅读代码,下面讲解一个简单例程,不需要把事件常给user。
policyFlags = ~ACTION_PASS_TO_USER;//同时设置标志位,该按键不传递给用户
下面我们找到函数:
bool InputDispatcherThread::threadLoop() {
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
mPendingEvent = mInboundQueue.dequeueAtHead();//从队列取出事件
/*如果这个事件不需要传递给user,则丢弃改事件*/
if (dropReason != DROP_REASON_NOT_DROPPED) {
dropInboundEventLocked(mPendingEvent, dropReason);//丢弃事件
case EventEntry::TYPE_KEY: {
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
if (done) {
*nextWakeupTime = LONG_LONG_MIN; // 处理完之后,继续处理下一个事件
无论GlobalKeys,SystemKey都和上述分析一样,只是在dispatchKeyLocked中的处理不一样:
bool InputDispatcherThread::threadLoop() {
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
mPendingEvent = mInboundQueue.dequeueAtHead();//从队列取出事件
/*如果这个事件不需要传递给user,则丢弃改事件*/
if (dropReason != DROP_REASON_NOT_DROPPED) {
dropInboundEventLocked(mPendingEvent, dropReason);//丢弃事件
case EventEntry::TYPE_KEY: {
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
/*如果需要拷贝给user*/
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER)
/*构建一个命令*/
CommandEntry* commandEntry = postCommandLocked(&InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
if (mFocusedWindowHandle != NULL) {
commandEntry->inputWindowHandle = mFocusedWindowHandle;
}
commandEntry->keyEntry = entry;
entry->refCount += 1;
return false; // wait for the command to run
Vector<InputTarget> inputTargets;
/*寻找需要接收的应用程序*/
int32_t injectionResult =
findFocusedWindowTargetsLocked(currentTime,entry, inputTargets, nextWakeupTime);
./*发送事件给应用程序*/
dispatchEventLocked(currentTime, entry, inputTargets);
runCommandsLockedInterruptible()//执行命令
CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
Command command = commandEntry->command;
/*实际调用前面构造的InputDispatcher::doInterceptKeyBeforeDispatchingLoc方法
*/
(this->*command)(commandEntry);
/*调用WindowManagerPolicy.java中的interceptKeyBeforeDispatching
根据返回结果设置解析结果*/
nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle,&event, entry->policyFlags);
mLock.lock();
if (delay < 0) {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
} else if (!delay) {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
} else {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
entry->interceptKeyWakeupTime = now() + delay;
}
上面提到会调用WindowManagerPolicy.java中的interceptKeyBeforeDispatching,那么我们查看一下,我们只关心GlobalKeys:
public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags)
if (isValidGlobalKey(keyCode)&& mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event))
return -1;
如果为GlobalKeys会返回-1,那么执行:
if (delay < 0) {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
就会把这个按键忽略,不会传递给user,现在我们来看看mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)函数:
mGlobalKeyManager.handleGlobalKey(mContext, keyCode, event)
/*根据一个Global_Key.xml发送广播给某个组件*/
context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null);
看了这么多思绪应该比较混乱,下面我们重新总结一些