InputDispatcher.cpp位置:framework/base/service/input/InputDispatcher.cpp
上一篇文章分析到args->notify(mInnerListener);
我们只分析key event类型
void NotifyKeyArgs::notify(const sp
listener->notifyKey(this);
}
考虑到前面分析有点快,后面我会分析得更详细。
这里会调用InputDispatcher的notifyKey()函数。
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
"flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld",
args->eventTime, args->deviceId, args->source, args->policyFlags,
args->action, args->flags, args->keyCode, args->scanCode,
args->metaState, args->downTime);
#endif
//如果不是down或者up事件,则判定为非法事件,不处理
if (!validateKeyEvent(args->action)) {
return;
}
uint32_t policyFlags = args->policyFlags;
int32_t flags = args->flags;
int32_t metaState = args->metaState;
if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
policyFlags |= POLICY_FLAG_VIRTUAL;
flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
}
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;
}
if (policyFlags & POLICY_FLAG_CAPS_LOCK) {
metaState |= AMETA_CAPS_LOCK_ON;
}
if (policyFlags & POLICY_FLAG_FUNCTION) {
metaState |= AMETA_FUNCTION_ON;
}
//从InputReader过来的事件加上POLICY_FLAG_TRUSTED标记
policyFlags |= POLICY_FLAG_TRUSTED;
KeyEvent event;
//将NotifyKeyArgs转换为KeyEvent
event.initialize(args->deviceId, args->source, args->action,
flags, args->keyCode, args->scanCode, metaState, 0,
args->downTime, args->eventTime);
//这个函数很重要,待会重点分析
mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
if (policyFlags & POLICY_FLAG_WOKE_HERE) {
flags |= AKEY_EVENT_FLAG_WOKE_HERE;
}
bool needWake;
{ // acquire lock
mLock.lock();
if (shouldSendKeyToInputFilterLocked(args)) {
mLock.unlock();
policyFlags |= POLICY_FLAG_FILTERED;
if (!mPolicy->filterInputEvent(&event, policyFlags)) {
return; // event was consumed by the filter
}
mLock.lock();
}
int32_t repeatCount = 0;
KeyEntry* newEntry = new KeyEntry(args->eventTime,
args->deviceId, args->source, policyFlags,
args->action, flags, args->keyCode, args->scanCode,
metaState, repeatCount, args->downTime);
//将newEntry即本次keyevent送到队列中
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
} // release lock
if (needWake) {
//如果需要唤醒mLooper则马上唤醒,唤醒后事件将立马进行分发
mLooper->wake();
}
}
基本上都做了注释,比较简单,我们重点看看mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags);
这是个native函数,其实现在com_android_server_input_InputManagerService.cpp中
void NativeInputManager::interceptKeyBeforeQueueing(const KeyEvent* keyEvent,
uint32_t& policyFlags) {
// Policy:
// - Ignore untrusted events and pass them along.
// - Ask the window manager what to do with normal events and trusted injected events.
// - For normal events wake and brighten the screen if currently off or dim.
if ((policyFlags & POLICY_FLAG_TRUSTED)) {//前面说了,从inputreader过来的都会加上POLICY_FLAG_TRUSTED标记
/// M:[SmartBook] Wake up SmartBook's screen @{
if (gSmartBookPlugIn && !isSbScreenOn()) {
ALOGD("Wake up SmartBook screen by key event");
android_server_PowerManagerService_sbScreenControl(2,0);
return;
}
/// @}
nsecs_t when = keyEvent->getEventTime();
bool isScreenOn = this->isScreenOn();
bool isScreenBright = this->isScreenBright();
JNIEnv* env = jniEnv();
jobject keyEventObj = android_view_KeyEvent_fromNative(env, keyEvent);
jint wmActions;
if (keyEventObj) {
//通过jni调用Java层的interceptKeyBeforeQueueing,其实现位于InputMonitor.java,然后又会调用PhoneWindowManager.java中的同名函数,这里的返回值wmActions非常重要,它将决定一部分事件的处理逻辑以及是否有必要有继续分发
wmActions = env->CallIntMethod(mServiceObj,
gServiceClassInfo.interceptKeyBeforeQueueing,
keyEventObj, policyFlags, isScreenOn);
//异常处理
if (checkAndClearExceptionFromCallback(env, "interceptKeyBeforeQueueing")) {
wmActions = 0;
}
android_view_KeyEvent_recycle(env, keyEventObj);
env->DeleteLocalRef(keyEventObj);
} else {
ALOGE("Failed to obtain key event object for interceptKeyBeforeQueueing.");
wmActions = 0;
}
if (!(policyFlags & POLICY_FLAG_INJECTED)) {
if (!isScreenOn) {
policyFlags |= POLICY_FLAG_WOKE_HERE;
}
if (!isScreenBright) {
policyFlags |= POLICY_FLAG_BRIGHT_HERE;
}
}
/// M: Power key UI monitor @{
int powerKeyCode = KEYCODE_POWER;
int keyDown = KEYEVENT_DOWN;
int keyUp = KEYEVENT_UP;
if (isScreenOn) {
if (keyEvent->getKeyCode() == powerKeyCode) {
if (keyEvent->getAction() == keyDown) {
ALOGD("Now is screen on, power down pressed: Disable monitor");
aee_ioctl_wdt_kick(WDT_SETBY_WMS_DISABLE_PWK_MONITOR);
} else if (keyEvent->getAction() == keyUp &&
(wmActions & WM_ACTION_GO_TO_SLEEP)) {
ALOGD("Now is screen on, power up pressed and go suspend: Enable monitor");
aee_ioctl_wdt_kick(WDT_SETBY_WMS_ENABLE_PWK_MONITOR);
}
}
}
/// @}
handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
} else {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
}
}
interceptKeyBeforeQueueing这个函数名字取得非常的恰到好处,就如其名字一样,执行完这个函数key event就立马被送入到了分发队列中,各位感兴趣的可以自行分析PhoneWindowManager.java的同名函数,其会对一些系统按键,比如volume+,volume-,power,endcall,media等按键进行处理,这些按键按键中的部分是不需要经过分发就可以执行对应功能的,同时也不会被ANR阻塞。
接下来我们看看handleInterceptActions(wmActions, when, /*byref*/ policyFlags);
void NativeInputManager::handleInterceptActions(jint wmActions, nsecs_t when,
uint32_t& policyFlags) {
if (wmActions & WM_ACTION_GO_TO_SLEEP) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("handleInterceptActions: Going to sleep.");
#endif
android_server_PowerManagerService_goToSleep(when);
}
if (wmActions & WM_ACTION_WAKE_UP) {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("handleInterceptActions: Waking up.");
#endif
android_server_PowerManagerService_wakeUp(when);
}
if (wmActions & WM_ACTION_PASS_TO_USER) {
policyFlags |= POLICY_FLAG_PASS_TO_USER;
} else {
#if DEBUG_INPUT_DISPATCHER_POLICY
ALOGD("handleInterceptActions: Not passing key to user.");
#endif
}
}
这个函数非常简单,根据返回值wmActions进行唤醒或者休眠操作,或者添加POLICY_FLAG_PASS_TO_USER标志,值得一提的是,wake up&sleep操作是通过JNI调用PMS相关函数实现的,不知道这么多JNI调来调去对性能有多少影响。
从这里可以看出,想要某个key具备唤醒或者休眠设备的操作实在太简单,只需要将返回值wmActions置位WM_ACTION_PASS_TO_USER或者WM_ACTION_WAKE_UP即可。
接下来我们看看enqueueInboundEventLocked(newEntry)实现
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
//如果之前队列处于空置状态,则需要唤醒,否则分发线程的Looper肯定是处于工作中,无需再次唤醒
bool needWake = mInboundQueue.isEmpty();
//添加到队列中
mInboundQueue.enqueueAtTail(entry);
traceInboundQueueLengthLocked();
switch (entry->type) {
case EventEntry::TYPE_KEY: {
// Optimize app switch latency.
// If the application takes too long to catch up then we drop all events preceding
// the app switch key.
KeyEntry* keyEntry = static_cast
if (isAppSwitchKeyEventLocked(keyEntry)) {
if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) {
mAppSwitchSawKeyDown = true;
} else if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
if (mAppSwitchSawKeyDown) {
#if DEBUG_APP_SWITCH
ALOGD("App switch is pending!");
#endif
mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
mAppSwitchSawKeyDown = false;
needWake = true;
}
}
}
break;
}
case EventEntry::TYPE_MOTION: {
// Optimize case where the current application is unresponsive and the user
// decides to touch a window in a different application.
// If the application takes too long to catch up then we drop all events preceding
// the touch into the other window.
MotionEntry* motionEntry = static_cast
if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
&& (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
&& mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
&& mInputTargetWaitApplicationHandle != NULL) {
int32_t displayId = motionEntry->displayId;
int32_t x = int32_t(motionEntry->pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_X));
int32_t y = int32_t(motionEntry->pointerCoords[0].
getAxisValue(AMOTION_EVENT_AXIS_Y));
sp
if (touchedWindowHandle != NULL
&& touchedWindowHandle->inputApplicationHandle
!= mInputTargetWaitApplicationHandle) {
// User touched a different application than the one we are waiting on.
// Flag the event, and start pruning the input queue.
mNextUnblockedEvent = motionEntry;
needWake = true;
}
}
break;
}
}
return needWake;
}
放入队列后分析就结束了,接下来我们看看分发线程是如何分发事件的
前面我们说过,C++层的Thread开启后会一直执行threadLoop()直到其返回false。
bool InputDispatcherThread::threadLoop() {
mDispatcher->dispatchOnce();
return true;
}
和InputReaderThread一样,一旦开启便永远不会结束
void InputDispatcher::dispatchOnce() {
nsecs_t nextWakeupTime = LONG_LONG_MAX;
{ // acquire lock
AutoMutex _l(mLock);
mDispatcherIsAliveCondition.broadcast();
// Run a dispatch loop if there are no pending commands.
// The dispatch loop might enqueue commands to run afterwards.
if (!haveCommandsLocked()) {
dispatchOnceInnerLocked(&nextWakeupTime);
}
// Run all pending commands if there are any.
// If any commands were run then force the next poll to wake up immediately.
if (runCommandsLockedInterruptible()) {
nextWakeupTime = LONG_LONG_MIN;
}
} // release lock
// Wait for callback or timeout or wake. (make sure we round up, not down)
nsecs_t currentTime = now();
int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
mLooper->pollOnce(timeoutMillis);
}
顺便提一下,mLooper->pollOnce实质上是个epoll_wait,这里有两种方法唤醒mLooper,一是前面提到的mLooper->wake(),二是nextWakeupTime时间到达后,这里的nextWakeupTime很有意思,设置成LONG_LONG_MAX即为永远休眠,设置成LONG_LONG_MIN则为立马唤醒。
真正分发函数是dispatchOnceInnerLocked(&nextWakeupTime);
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
nsecs_t currentTime = now();
// Reset the key repeat timer whenever we disallow key events, even if the next event
// is not a key. This is to ensure that we abort a key repeat if the device is just coming
// out of sleep.
//是否允许生成key repeat事件
if (!mPolicy->isKeyRepeatEnabled()) {
resetKeyRepeatLocked();
}
// If dispatching is frozen, do not process timeouts or try to deliver any new events.
//如果InputDispatcher处于冻结状态,则不予分发事件
if (mDispatchFrozen) {
#if DEBUG_FOCUS
ALOGD("Dispatch frozen. Waiting some more.");
#endif
return;
}
// Optimize latency of app switches.
// Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has
// been pressed. When it expires, we preempt dispatch and drop all other pending events.
//为了保证HOME按键不受ANR影响的一种处理机制
bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
if (mAppSwitchDueTime < *nextWakeupTime) {
*nextWakeupTime = mAppSwitchDueTime;
}
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (! mPendingEvent) {
//如果事件队列为空
if (mInboundQueue.isEmpty()) {
if (isAppSwitchDue) {
// The inbound queue is empty so the app switch key we were waiting
// for will never arrive. Stop waiting for it.
resetPendingAppSwitchLocked(false);
isAppSwitchDue = false;
}
// Synthesize a key repeat if appropriate.
if (mKeyRepeatState.lastKeyEntry) {
if (currentTime >= mKeyRepeatState.nextRepeatTime) {
//生成key repeat
mPendingEvent = synthesizeKeyRepeatLocked(currentTime);
} else {
if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {
//将生成的key repeat进行分发
*nextWakeupTime = mKeyRepeatState.nextRepeatTime;
}
}
}
// Nothing to do if there is no pending event.
if (!mPendingEvent) {
return;
}
} else {
// Inbound queue has at least one entry.
//从事件队列中取出一个事件
mPendingEvent = mInboundQueue.dequeueAtHead();
traceInboundQueueLengthLocked();
}
// Poke user activity for this event.
if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
pokeUserActivityLocked(mPendingEvent);
}
// Get ready to dispatch the event.
resetANRTimeoutsLocked();
}
// Now we have an event to dispatch.
// All events are eventually dequeued and processed this way, even if we intend to drop them.
ALOG_ASSERT(mPendingEvent != NULL);
bool done = false;
//在分发前会判断事件是否需要丢弃,丢弃的原因有很多,下面一个个解释
DropReason dropReason = DROP_REASON_NOT_DROPPED;
if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
//如果没有POLICY_FLAG_PASS_TO_USER标志会被丢弃,比如在PhoneWindowManager的interceptKeyBeforeQueueing中对于power key则去掉这个标志,所以power key会在这里直接被丢弃掉,不会进行分发
dropReason = DROP_REASON_POLICY;
} else if (!mDispatchEnabled) {
//InputDispatcher分发被禁止
dropReason = DROP_REASON_DISABLED;
}
if (mNextUnblockedEvent == mPendingEvent) {
mNextUnblockedEvent = NULL;
}
switch (mPendingEvent->type) {
case EventEntry::TYPE_CONFIGURATION_CHANGED: {
ConfigurationChangedEntry* typedEntry =
static_cast
done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped
break;
}
case EventEntry::TYPE_DEVICE_RESET: {
DeviceResetEntry* typedEntry =
static_cast
done = dispatchDeviceResetLocked(currentTime, typedEntry);
dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped
break;
}
//我们只讨论key event事件
case EventEntry::TYPE_KEY: {
KeyEntry* typedEntry = static_cast
if (isAppSwitchDue) {
if (isAppSwitchKeyEventLocked(typedEntry)) {
resetPendingAppSwitchLocked(true);
isAppSwitchDue = false;
} else if (dropReason == DROP_REASON_NOT_DROPPED) {
//因为阻塞了HOME key,从而丢弃
dropReason = DROP_REASON_APP_SWITCH;
}
}
if (dropReason == DROP_REASON_NOT_DROPPED
&& isStaleEventLocked(currentTime, typedEntry)) {
//事件太老了,具体有多老可以看看isStaleEventLocked实现,10s后的事件认为是太老了,比如说产生一个事件,10后InputDispatcher才开始分发
dropReason = DROP_REASON_STALE;
}
//暂时没太懂
if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DROP_REASON_BLOCKED;
}
//开始分发
done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
break;
}
case EventEntry::TYPE_MOTION: {
MotionEntry* typedEntry = static_cast
if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
dropReason = DROP_REASON_APP_SWITCH;
}
if (dropReason == DROP_REASON_NOT_DROPPED
&& isStaleEventLocked(currentTime, typedEntry)) {
dropReason = DROP_REASON_STALE;
}
if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
dropReason = DROP_REASON_BLOCKED;
}
done = dispatchMotionLocked(currentTime, typedEntry,
&dropReason, nextWakeupTime);
break;
}
default:
ALOG_ASSERT(false);
break;
}
//如果分发成功需要清空mPendingEvent等操作
if (done) {
if (dropReason != DROP_REASON_NOT_DROPPED) {
dropInboundEventLocked(mPendingEvent, dropReason);
}
releasePendingEventLocked();
*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
}
}
我们继续看dispatchKeyLocked()
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
DropReason* dropReason, nsecs_t* nextWakeupTime) {
// Preprocessing.
if (! entry->dispatchInProgress) {
if (entry->repeatCount == 0
&& entry->action == AKEY_EVENT_ACTION_DOWN
&& (entry->policyFlags & POLICY_FLAG_TRUSTED)
&& (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) {
if (mKeyRepeatState.lastKeyEntry
&& mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
// We have seen two identical key downs in a row which indicates that the device
// driver is automatically generating key repeats itself. We take note of the
// repeat here, but we disable our own next key repeat timer since it is clear that
// we will not need to synthesize key repeats ourselves.
entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1;
resetKeyRepeatLocked();
mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves
} else {
//为生成key repeat事件做准备
// Not a repeat. Save key down state in case we do see a repeat later.
resetKeyRepeatLocked();
mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout;
}
mKeyRepeatState.lastKeyEntry = entry;
entry->refCount += 1;
} else if (! entry->syntheticRepeat) {
resetKeyRepeatLocked();
}
//这样设置可以使第二生成的key repeat事件时KeyEvent.java的isLongPress()返回true
if (entry->repeatCount == 1) {
entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;
} else {
entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS;
}
entry->dispatchInProgress = true;
logOutboundKeyDetailsLocked("dispatchKey - ", entry);
}
// Handle case where the policy asked us to try again later last time.
//key event独有的机制,在分发前还会再进行一次策略检查
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) {
if (currentTime < entry->interceptKeyWakeupTime) {
if (entry->interceptKeyWakeupTime < *nextWakeupTime) {
*nextWakeupTime = entry->interceptKeyWakeupTime;
}
return false; // wait until next wakeup
}
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN;
entry->interceptKeyWakeupTime = 0;
}
// Give the policy a chance to intercept the key.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
CommandEntry* commandEntry = postCommandLocked(
& InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);//run phonewindowmanager interceptKeyBeforeDispatching
if (mFocusedWindowHandle != NULL) {
commandEntry->inputWindowHandle = mFocusedWindowHandle;
}
commandEntry->keyEntry = entry;
entry->refCount += 1;
return false; // wait for the command to run
} else {
entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
}
} else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) {
if (*dropReason == DROP_REASON_NOT_DROPPED) {
*dropReason = DROP_REASON_POLICY;
}
}
// Clean up if dropping the event.
//如果需要丢弃,则不进行分发
if (*dropReason != DROP_REASON_NOT_DROPPED) {
setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY
? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED);
return true;
}
// Identify targets.
Vector
//搜索焦点窗口
int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
entry, inputTargets, nextWakeupTime);
if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
return false;
}
setInjectionResultLocked(entry, injectionResult);
if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
return true;
}
addMonitoringTargetsLocked(inputTargets);
// Dispatch the key.
//分发事件
dispatchEventLocked(currentTime, entry, inputTargets);
return true;
}
这里我们重点分析key event独有的策略机制doInterceptKeyBeforeDispatchingLockedInterruptible()
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
CommandEntry* commandEntry) {
KeyEntry* entry = commandEntry->keyEntry;
KeyEvent event;
initializeKeyEvent(&event, entry);
mLock.unlock();
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;
}
entry->release();
}
这里会根据返回值不同,进行不同的处理,如果小于0则跳过分发,等于0则继续分发,大于0则等待delay后再分发
继续关注mPolicy->interceptKeyBeforeDispatching()
这里其实这里和前面的mPolicy->interceptMotionBeforeQueueing()是完全一样的流程,我就不详细分析了。
接下来要关注的就是dispatchEventLocked(currentTime, entry, inputTargets);了,不过这里涉及将key event事件通过InputChannel发送到ViewRootImpl中,中间很多地方还涉及WMS,比较偏Java层了,本系列文章不打算继续分析下去,以后有时间再分析吧。