当前位置: 首页 > news >正文

成都住建局官网官网官方/上海seo推广整站

成都住建局官网官网官方,上海seo推广整站,清洁公司,网站建设 英文文章托管在gitee上 Android Notes , 同步csdn InputDispatcher 的创建 如前所述,InputDispatcher 是在 InputManager 构造方法中通过工厂方法createInputDispatcher 创建. 此处的policy 实际上就是 NativeInputManager, 它是相关策略的实现类 sp<InputDispatcherInterface…

文章托管在gitee上 Android Notes , 同步csdn

InputDispatcher 的创建

如前所述,InputDispatcher 是在 InputManager 构造方法中通过工厂方法createInputDispatcher 创建.
此处的policy 实际上就是 NativeInputManager, 它是相关策略的实现类

sp<InputDispatcherInterface> createInputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) {// 直接通过new创建return new android::inputdispatcher::InputDispatcher(policy);
}

创建 InputDispatcher

构造函数主要做一些初始化工作

/// @frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp
InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy): mPolicy(policy), // 派发策略mPendingEvent(nullptr),  // 待分发的事件mLastDropReason(DropReason::NOT_DROPPED),  // 上次事件丢弃的原因mIdGenerator(IdGenerator::Source::INPUT_DISPATCHER),mAppSwitchSawKeyDown(false),mAppSwitchDueTime(LONG_LONG_MAX), // app 切换的超时时间mNextUnblockedEvent(nullptr),mDispatchEnabled(false),mDispatchFrozen(false),mInputFilterEnabled(false),// mInTouchMode will be initialized by the WindowManager to the default device config.// To avoid leaking stack in case that call never comes, and for tests,// initialize it here anyways.mInTouchMode(true), // 默认touch mode// 设置focus DisplayId为默认idmFocusedDisplayId(ADISPLAY_ID_DEFAULT) {mLooper = new Looper(false); // 创建 Looper// The interface used by the InputDispatcher to report information about input events after// it is sent to the application, such as if a key is unhandled or dropped.// 上报unhandled or dropped key 的信息, 目前是空实现mReporter = createInputReporter();mKeyRepeatState.lastKeyEntry = nullptr;policy->getDispatcherConfiguration(&mConfig);
}

派发策略 InputDispatcherPolicyInterface

事件派发策略, 它的实现通常是在java层的PhoneWindowManager

class InputDispatcherPolicyInterface : public virtual RefBase {
protected:InputDispatcherPolicyInterface() {}virtual ~InputDispatcherPolicyInterface() {}public:/* Notifies the system that a configuration change has occurred. */virtual void notifyConfigurationChanged(nsecs_t when) = 0;/* Notifies the system that an application is not responding.* Returns a new timeout to continue waiting, or 0 to abort dispatch. */virtual nsecs_t notifyAnr(const sp<InputApplicationHandle>& inputApplicationHandle,const sp<IBinder>& token, const std::string& reason) = 0;  // 通知ANR/* Notifies the system that an input channel is unrecoverably broken. */virtual void notifyInputChannelBroken(const sp<IBinder>& token) = 0;virtual void notifyFocusChanged(const sp<IBinder>& oldToken, const sp<IBinder>& newToken) = 0;  // 焦点改变/* Gets the input dispatcher configuration. */virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0;/* Filters an input event.* Return true to dispatch the event unmodified, false to consume the event.* A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED* to injectInputEvent.*/virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) = 0;/* Intercepts a key event immediately before queueing it.* The policy can use this method as an opportunity to perform power management functions* and early event preprocessing such as updating policy flags.** This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event* should be dispatched to applications.*/virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0; // 入队之前的拦截操作/* Intercepts a touch, trackball or other motion event before queueing it.* The policy can use this method as an opportunity to perform power management functions* and early event preprocessing such as updating policy flags.** This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event* should be dispatched to applications.*/virtual void interceptMotionBeforeQueueing(const int32_t displayId, nsecs_t when,uint32_t& policyFlags) = 0;/* Allows the policy a chance to intercept a key before dispatching. */   // 分发之前的拦截操作virtual nsecs_t interceptKeyBeforeDispatching(const sp<IBinder>& token,const KeyEvent* keyEvent,uint32_t policyFlags) = 0;/* Allows the policy a chance to perform default processing for an unhandled key.* Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */virtual bool dispatchUnhandledKey(const sp<IBinder>& token, const KeyEvent* keyEvent,uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0;/* Notifies the policy about switch events.*/virtual void notifySwitch(nsecs_t when, uint32_t switchValues, uint32_t switchMask,uint32_t policyFlags) = 0;/* Poke user activity for an event dispatched to a window. */virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0;/* Checks whether a given application pid/uid has permission to inject input events into other applications.** This method is special in that its implementation promises to be non-reentrant and* is safe to call while holding other locks.  (Most other methods make no such guarantees!)*/virtual bool checkInjectEventsPermissionNonReentrant(int32_t injectorPid,int32_t injectorUid) = 0;/* Notifies the policy that a pointer down event has occurred outside the current focused window.** The touchedToken passed as an argument is the window that received the input event.*/virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) = 0;
};

NativeInputManager::getDispatcherConfiguration

InputDispatcher构造的最后,通过policy获取配置信息, 此处的policy实际上是NativeInputManager对象. 通过实现可知,是通过IMS的相关方法获取时间.

void NativeInputManager::getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) {ATRACE_CALL();JNIEnv* env = jniEnv();jint keyRepeatTimeout = env->CallIntMethod(mServiceObj,gServiceClassInfo.getKeyRepeatTimeout); // 通过IMS 获取第一个按键重复事件的超时时间 默认500msif (!checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) {outConfig->keyRepeatTimeout = milliseconds_to_nanoseconds(keyRepeatTimeout);}jint keyRepeatDelay = env->CallIntMethod(mServiceObj,gServiceClassInfo.getKeyRepeatDelay); // 获取连续重复按键之间的时间 50sif (!checkAndClearExceptionFromCallback(env, "getKeyRepeatDelay")) {outConfig->keyRepeatDelay = milliseconds_to_nanoseconds(keyRepeatDelay);}
}

InputDispatcher::start

IMS#start方法会调用nativeStart, 之后在native会进一步调用InputDispatcher::start. 在这个方法中,会创建其InputThread任务线程. 如前所述,InputThread构造方法内部会创建一个线程,并启动此线程.

status_t InputDispatcher::start() {if (mThread) {return ALREADY_EXISTS;}mThread = std::make_unique<InputThread>("InputDispatcher", [this]() { dispatchOnce(); }, [this]() { mLooper->wake(); });return OK;
}

注意到创建InputThread时有三个参数,第一个是线程的名称,第二个是线程执行threadLoop时回调的函数,此处写法是C++11的lambda表达式,第三个参数是线程销毁前调用来唤醒线程的回调.
因此当线程运行时会不停的调用dispatchOnce, 来完成分发的操作

InputDispatcher::dispatchOnce

dispatchOnce 用于完成事件的派发,逻辑比较简洁:

  • 没有待处理的commands时, 执行派发操作, 派发是串行的处理
  • 处理 pending commands. Command通常是对dispatcher函数相关操作的封装,添加到mCommandQueue,等待dispatcher处理
  • 处理 ANR 事件
  • 计算下一次的唤醒时间, 若为LONG_LONG_MAX,则通知进入idle
  • 通过mLooper->pollOnce等待相关事件, 如 callback / timeout / wake
void InputDispatcher::dispatchOnce() {nsecs_t nextWakeupTime = LONG_LONG_MAX;{ // acquire lockstd::scoped_lock _l(mLock);mDispatcherIsAlive.notify_all();  // 通知dispatcher线程还活跃, 用于检测死锁// Run a dispatch loop if there are no pending commands.// The dispatch loop might enqueue commands to run afterwards.if (!haveCommandsLocked()) { // 如果没有commands 则进行事件分发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()) { // 执行commandsnextWakeupTime = LONG_LONG_MIN; // 立即进行下一轮的派发}// If we are still waiting for ack on some events,// we might have to wake up earlier to check if an app is anr'ing.const nsecs_t nextAnrCheck = processAnrsLocked(); // 处理anrnextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);// We are about to enter an infinitely long sleep, because we have no commands or// pending or queued eventsif (nextWakeupTime == LONG_LONG_MAX) {mDispatcherEnteredIdle.notify_all();  // 通知进入idle}} // 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);
}

InputDispatcher::dispatchOnceInnerLocked

这个函数完成一次事件的派发流程. 通常对于一个事件,调用一次就可以完成派发, 而某些事件比如key事件,当需要传递给user时,会先经过策略类进行处理,从而导致会调用多次.
这个函数的功能相对简单:

  • 取出pending事件, 当队列有事件时取出队列头, 当事件队列为空时,则尝试处理重复事件
  • 处理需要 drop 的事件
  • 针对type处理相关事件的派发
  • 结束事件派发
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {nsecs_t currentTime = now();// Reset the key repeat timer whenever normal dispatch is suspended while the// device is in a non-interactive state.  This is to ensure that we abort a key// repeat if the device is just coming out of sleep.if (!mDispatchEnabled) {  // 分发被禁止, 通常设备处于 non-interactiveresetKeyRepeatLocked();}// If dispatching is frozen, do not process timeouts or try to deliver any new events.if (mDispatchFrozen) { // 分发被冻结,直接返回if (DEBUG_FOCUS) {ALOGD("Dispatch frozen.  Waiting some more.");}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.bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;  // app 切换时间到期if (mAppSwitchDueTime < *nextWakeupTime) { // 下次唤醒时间大于 app 切换时间到期时间,则更新唤醒时间为早的*nextWakeupTime = mAppSwitchDueTime;}/// 下面进入派发流程// Ready to start a new event.// If we don't already have a pending event, go grab one.if (!mPendingEvent) { // 尝试获取新的Event来处理if (mInboundQueue.empty()) { // 派发队列是空的if (isAppSwitchDue) { // 这种情况如果app切换超时, 需要重置// 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) { // 到了时间 生成一个重复事件mPendingEvent = synthesizeKeyRepeatLocked(currentTime);} else {if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) { // 下次repeat时间较短,设置成wakeup时间*nextWakeupTime = mKeyRepeatState.nextRepeatTime;}}}// Nothing to do if there is no pending event.if (!mPendingEvent) { // 没有pending的直接返回return;}} else { // 不为空,则取出队列头的作为待分发事件// Inbound queue has at least one entry.mPendingEvent = mInboundQueue.front(); // 取出队列头元素mInboundQueue.pop_front();  // 出队traceInboundQueueLengthLocked();}// Poke user activity for this event.if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) { // 传给user, 则需要通知user活动// 此处会回调到PowerManagerService的userActivityFromNative// 下面调用会被封装成一个command,在下次派发循环中处理pokeUserActivityLocked(*mPendingEvent);}}// 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 != nullptr);bool done = false;// 判断事件是否被丢弃, 丢弃的事件不会进行分发DropReason dropReason = DropReason::NOT_DROPPED;// 如果不传递给user, 通常是在interceptKeyBeforeQueueing处理是否传递// 没有FLAG POLICY_FLAG_PASS_TO_USER , 则会因为DropReason::POLICY 而被丢弃if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {dropReason = DropReason::POLICY;} else if (!mDispatchEnabled) { // 若分发被禁止dropReason = DropReason::DISABLED;}if (mNextUnblockedEvent == mPendingEvent) { // 下一个不阻塞的事件mNextUnblockedEvent = nullptr;}// 下面针对类型进行派发switch (mPendingEvent->type) {case EventEntry::Type::CONFIGURATION_CHANGED: { // input device configuration has changedConfigurationChangedEntry* typedEntry =static_cast<ConfigurationChangedEntry*>(mPendingEvent);done = dispatchConfigurationChangedLocked(currentTime, typedEntry);dropReason = DropReason::NOT_DROPPED; // configuration changes are never droppedbreak;}case EventEntry::Type::DEVICE_RESET: { //  device resetDeviceResetEntry* typedEntry = static_cast<DeviceResetEntry*>(mPendingEvent);done = dispatchDeviceResetLocked(currentTime, typedEntry);dropReason = DropReason::NOT_DROPPED; // device resets are never droppedbreak;}case EventEntry::Type::FOCUS: {FocusEntry* typedEntry = static_cast<FocusEntry*>(mPendingEvent);dispatchFocusLocked(currentTime, typedEntry);done = true;dropReason = DropReason::NOT_DROPPED; // focus events are never droppedbreak;}case EventEntry::Type::KEY: { // 派发 key 事件KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);if (isAppSwitchDue) {  // app切换的key事件到期, 需要丢弃此事件之前的所有事件if (isAppSwitchKeyEvent(*typedEntry)) { // 当前事件是app切换的key事件,则重置到期时间resetPendingAppSwitchLocked(true);isAppSwitchDue = false;} else if (dropReason == DropReason::NOT_DROPPED) { // 否则此未丢弃的事件会因为APP_SWITCH而丢弃dropReason = DropReason::APP_SWITCH;}}if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) { // 过期事件, 此时距离事件发生时间>=10secdropReason = DropReason::STALE;}if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) { // 有非阻塞事件需要处理dropReason = DropReason::BLOCKED;}done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);  // 处理key事件派发break;}case EventEntry::Type::MOTION: {  // 派发触摸事件MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) { // app切换到期dropReason = DropReason::APP_SWITCH;}if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) { // 过期事件dropReason = DropReason::STALE;}if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) { // 有非阻塞事件需要处理dropReason = DropReason::BLOCKED;}done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);break;}}if (done) { // 完成派发?if (dropReason != DropReason::NOT_DROPPED) { // 如果被丢弃dropInboundEventLocked(*mPendingEvent, dropReason);}mLastDropReason = dropReason;releasePendingEventLocked();*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately}
}

InputDispatcher::synthesizeKeyRepeatLocked

此函数用于合成一个重重复key事件, 注意repeatCount都递增了1

KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) {KeyEntry* entry = mKeyRepeatState.lastKeyEntry;// Reuse the repeated key entry if it is otherwise unreferenced.uint32_t policyFlags = entry->policyFlags &(POLICY_FLAG_RAW_MASK | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED); // 添加flagif (entry->refCount == 1) { // 没有其他引用时复用,防止冲突. entry->refCount默认是1entry->recycle();entry->id = mIdGenerator.nextId();entry->eventTime = currentTime;entry->policyFlags = policyFlags;entry->repeatCount += 1;} else { // 已在其他地方被引用,需要创建新entryKeyEntry* newEntry =new KeyEntry(mIdGenerator.nextId(), currentTime, entry->deviceId, entry->source,entry->displayId, policyFlags, entry->action, entry->flags,entry->keyCode, entry->scanCode, entry->metaState,entry->repeatCount + 1, entry->downTime);mKeyRepeatState.lastKeyEntry = newEntry;entry->release();entry = newEntry;}entry->syntheticRepeat = true; // 设置事件是合成的// Increment reference count since we keep a reference to the event in// mKeyRepeatState.lastKeyEntry in addition to the one we return.entry->refCount += 1;mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay; // 注意此处的nextRepeatTime,与当前间隔keyRepeatDelay 50msreturn entry;
}

接下来以key事件的派发流程来分析事件派发的过程.

InputDispatcher::dispatchKeyLocked

bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,DropReason* dropReason, nsecs_t* nextWakeupTime) {// Preprocessing.if (!entry->dispatchInProgress) { // 如果不是在派发过程中// 处理key事件的repeat// repeat条件: ①repeatCount为0 , ②是Down事件, ③是trusted事件 ④策略没有禁止repeat// 上面条件说明这是一个 initial Down事件(可能是设备驱动生成的repeat事件)if (entry->repeatCount == 0 && entry->action == AKEY_EVENT_ACTION_DOWN &&(entry->policyFlags & POLICY_FLAG_TRUSTED) &&(!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) {// 根据下面的注释看,是设备驱动生成了repeat事件, 为什么此处不是之前合成的重复事件? 之前一直忽略了repeatCount成员// 如果是之前合成的重复事件,repeatCount则不为0(synthesizeKeyRepeatLocked函数对其进行过递增), 上面的repeat条件将不满足而无法进入  if (mKeyRepeatState.lastKeyEntry &&  // 既然设备驱动生成了repeat事件(也就是当前entry), 那么就不需要自己去合成一个了mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {// 存在lastKeyEntry, 且keyCode一致 说明此key之前触发过// 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; // 递增repeatCountresetKeyRepeatLocked(); // 重置 mKeyRepeatState 为nullptrmKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves} else {// 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; // 设置新的lastKeyEntryentry->refCount += 1;} else if (!entry->syntheticRepeat) { // 不是合成的repeat事件resetKeyRepeatLocked(); // 重置 lastKeyEntry}if (entry->repeatCount == 1) { // repeatCount 为1, 则添加长按事件的FLAGentry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;} else {entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS;}entry->dispatchInProgress = true; // 派发中..logOutboundKeyDetails("dispatchKey - ", *entry);}// Handle case where the policy asked us to try again later last time.// 之前策略决定稍后重试,这个根据PhoneWindowManager#interceptKeyBeforeDispatching 返回值决定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;  // 重置, 让policy再次处理entry->interceptKeyWakeupTime = 0;}// Give the policy a chance to intercept the key.// interceptKeyResult有三种情况 :// INTERCEPT_KEY_RESULT_SKIP(跳过派发)  INTERCEPT_KEY_RESULT_CONTINUE(继续派发) INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER(稍后重试派发)if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { // 为unknown,认为没有处理过if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { // 如果需要传递给user, 则需要调用策略类进行处理// 将doInterceptKeyBeforeDispatchingLockedInterruptible操作封装成command,在执行dispatchOnceInnerLocked后处理commandstd::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(&InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);sp<InputWindowHandle> focusedWindowHandle =getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(*entry));// 获取指定displayId对应的focusedWindowHandleif (focusedWindowHandle != nullptr) {commandEntry->inputChannel = getInputChannelLocked(focusedWindowHandle->getToken());}commandEntry->keyEntry = entry;postCommandLocked(std::move(commandEntry)); // 投递commandentry->refCount += 1;return false; // wait for the command to run  此处返回false会先执行command, 然后再继续进行此事件派发} else {  // 否则继续派发entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;}} else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) { // 如果是skip则drop事件if (*dropReason == DropReason::NOT_DROPPED) {*dropReason = DropReason::POLICY;}}// Clean up if dropping the event.if (*dropReason != DropReason::NOT_DROPPED) { // 事件丢弃处理setInjectionResult(entry,*dropReason == DropReason::POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED: INPUT_EVENT_INJECTION_FAILED); // 设置事件注入的结果mReporter->reportDroppedKey(entry->id);return true;}// Identify targets.std::vector<InputTarget> inputTargets;  // 目标窗口结果保存在此集合int32_t injectionResult =findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime); // 寻找到焦点窗口if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { // pending表示需要等待return false;}setInjectionResult(entry, injectionResult); // 设置事件注入的结果if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { // 非success将不会被派发return true;}// Add monitor channels from event's or focused display.addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry)); // 将monitor列表的window也加入派发目标窗口列表// Dispatch the key.dispatchEventLocked(currentTime, entry, inputTargets);  // 开始派发事件到目标窗口return true;
}

下面看一些关键的方法的具体实现.

InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible

如上分析, 当key事件需要分发到user时,需要先通过策略处理. 将doInterceptKeyBeforeDispatchingLockedInterruptible方法的操作封装成了一个Command,然后投递到command队列.
在dispatchOnceInnerLocked完后,会执行runCommandsLockedInterruptible处理command, 因此会导致该方法被调用. 在执行完策略处理后,事件的interceptKeyResult有三种取值:

  • KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
  • KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
  • KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry) {KeyEntry* entry = commandEntry->keyEntry;KeyEvent event = createKeyEvent(*entry);mLock.unlock();android::base::Timer t;// InputChannel对应的IBinder tokensp<IBinder> token = commandEntry->inputChannel != nullptr? commandEntry->inputChannel->getConnectionToken(): nullptr;// 调用路径 NativeInputManager -> InputManagerService -> InputManagerCallback -> PhoneWindowManagernsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, &event, entry->policyFlags);if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms",std::to_string(t.duration().count()).c_str());}mLock.lock();if (delay < 0) { // <0 , 事件将会跳过, 可能已经被policy处理了entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;} else if (!delay) { // = 0 , 继续分发entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;} else { // > 0 , 延时分发entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;entry->interceptKeyWakeupTime = now() + delay;}entry->release();
}

在处理此command后,会继续进行之前未派发完的事件派发任务, 然后根据interceptKeyResult判断是否需要继续还是丢弃事件.

InputDispatcher::findFocusedWindowTargetsLocked

再次回到dispatchKeyLocked分发, 当处理完interceptBeforeDispatch的策略后,若事件没有被丢弃,则会尝试寻找focusd window. 逻辑如下:

  • 获取指定displayId的焦点窗口和焦点应用,如果两者都不存在,则说明没有找到.如果有焦点应用,但是没有焦点窗口,则需要等待焦点窗口的出现, 默认等待5s
  • 如果找到焦点窗口,重置ANR相关信息
  • 如果是注入(inject)的事件,需要检查相关权限(android.permission.INJECT_EVENTS)
  • 如果焦点窗口处于paused状态,则需要等待
  • 如果是key事件, 则需要等待之前的事件全部处理完成才派发. 等待超时时间500ms
  • 添加当前目标窗口到inputTargets列表, 注意添加时的FLAG FLAG_FOREGROUND和FLAG_DISPATCH_AS_IS

返回值表示查找的状态:

  • INPUT_EVENT_INJECTION_FAILED 没有找到焦点窗口或等待焦点窗口出现超时
  • INPUT_EVENT_INJECTION_PENDING
    - 等待焦点窗口
    - 焦点窗口处于paused状态
    - 如果是key事件,等待之前的事件全部处理完成
  • INPUT_EVENT_INJECTION_PERMISSION_DENIED
    - 注册事件的应用uid 与目标窗口应用的uid不一致, 且没有权限 android.permission.INJECT_EVENTS
  • INPUT_EVENT_INJECTION_SUCCEEDED 找到焦点窗口
int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,const EventEntry& entry,std::vector<InputTarget>& inputTargets,nsecs_t* nextWakeupTime) {std::string reason;int32_t displayId = getTargetDisplayId(entry);sp<InputWindowHandle> focusedWindowHandle =getValueByKey(mFocusedWindowHandlesByDisplay, displayId); // 获取焦点窗口 handlesp<InputApplicationHandle> focusedApplicationHandle =getValueByKey(mFocusedApplicationHandlesByDisplay, displayId); // 获取焦点应用handle// If there is no currently focused window and no focused application// then drop the event.if (focusedWindowHandle == nullptr && focusedApplicationHandle == nullptr) { // 没有焦点应用且没有焦点窗口ALOGI("Dropping %s event because there is no focused window or focused application in ""display %" PRId32 ".",EventEntry::typeToString(entry.type), displayId);return INPUT_EVENT_INJECTION_FAILED;}// Compatibility behavior: raise ANR if there is a focused application, but no focused window.// Only start counting when we have a focused event to dispatch. The ANR is canceled if we// start interacting with another application via touch (app switch). This code can be removed// if the "no focused window ANR" is moved to the policy. Input doesn't know whether// an app is expected to have a focused window.if (focusedWindowHandle == nullptr && focusedApplicationHandle != nullptr) { // 有焦点应用但是没有焦点窗口if (!mNoFocusedWindowTimeoutTime.has_value()) { // 新窗口可能在添加中, 等待添加完成// We just discovered that there's no focused window. Start the ANR timerconst nsecs_t timeout = focusedApplicationHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT.count());mNoFocusedWindowTimeoutTime = currentTime + timeout;mAwaitedFocusedApplication = focusedApplicationHandle;ALOGW("Waiting because no window has focus but %s may eventually add a ""window when it finishes starting up. Will wait for %" PRId64 "ms",mAwaitedFocusedApplication->getName().c_str(), ns2ms(timeout));*nextWakeupTime = *mNoFocusedWindowTimeoutTime;return INPUT_EVENT_INJECTION_PENDING; // 返回 pending} else if (currentTime > *mNoFocusedWindowTimeoutTime) {// Already raised ANR. Drop the eventALOGE("Dropping %s event because there is no focused window",EventEntry::typeToString(entry.type));return INPUT_EVENT_INJECTION_FAILED; // 已经等待超时, 返回失败} else {// Still waiting for the focused windowreturn INPUT_EVENT_INJECTION_PENDING;  // 还未超时, 继续等待}}// we have a valid, non-null focused windowresetNoFocusedWindowTimeoutLocked();  // 重置超时时间, Resetting ANR timeouts// Check permissions. 主要是通过IMS来检查权限 android.Manifest.permission.INJECT_EVENTSif (!checkInjectionPermission(focusedWindowHandle, entry.injectionState)) {return INPUT_EVENT_INJECTION_PERMISSION_DENIED;}if (focusedWindowHandle->getInfo()->paused) { // 窗口paused状态,等待ALOGI("Waiting because %s is paused", focusedWindowHandle->getName().c_str());return INPUT_EVENT_INJECTION_PENDING;}// If the event is a key event, then we must wait for all previous events to// complete before delivering it because previous events may have the// side-effect of transferring focus to a different window and we want to// ensure that the following keys are sent to the new window.//// Suppose the user touches a button in a window then immediately presses "A".// If the button causes a pop-up window to appear then we want to ensure that// the "A" key is delivered to the new pop-up window.  This is because users// often anticipate pending UI changes when typing on a keyboard.// To obtain this behavior, we must serialize key events with respect to all// prior input events.if (entry.type == EventEntry::Type::KEY) { // 如果是key事件, 则需要等待之前的事件全部处理完成才派发if (shouldWaitToSendKeyLocked(currentTime, focusedWindowHandle->getName().c_str())) {*nextWakeupTime = *mKeyIsWaitingForEventsTimeout; // 设置下次唤醒时间为等待超时时间return INPUT_EVENT_INJECTION_PENDING;}}// Success!  Output targets.addWindowTargetLocked(focusedWindowHandle,InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS,// 注意此处的FLAG, 在派发时生成对应的dispatchEntryBitSet32(0), inputTargets);  // 保存到inputTargets// Done.return INPUT_EVENT_INJECTION_SUCCEEDED;
}
InputDispatcher::checkInjectionPermission

检查注入事件的权限,看是否能向当前窗口注入事件:

  • 注册事件的应用uid 与目标窗口应用的uid一致, 则可以直接注入
  • 若不一致, 则还需要权限 android.permission.INJECT_EVENTS
bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,const InjectionState* injectionState) {if (injectionState &&(windowHandle == nullptr ||// 注册事件的应用uid 与目标窗口应用的uid不一致. 此处若相等,则整个if不成立windowHandle->getInfo()->ownerUid != injectionState->injectorUid) &&// 没有权限 android.permission.INJECT_EVENTS!hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {if (windowHandle != nullptr) {ALOGW("Permission denied: injecting event from pid %d uid %d to window %s ""owned by uid %d",injectionState->injectorPid, injectionState->injectorUid,windowHandle->getName().c_str(), windowHandle->getInfo()->ownerUid);} else {ALOGW("Permission denied: injecting event from pid %d uid %d",injectionState->injectorPid, injectionState->injectorUid);}return false;}return true;
}
InputDispatcher::shouldWaitToSendKeyLocked

看key事件是否需要等待之前的事件派发完成

bool InputDispatcher::shouldWaitToSendKeyLocked(nsecs_t currentTime,const char* focusedWindowName) {// mAnrTracker为空,说明之前的事件都已经发送事件反馈,将相关anr记录从其中移除,即事件都已经派发完毕                                              if (mAnrTracker.empty()) {// already processed all events that we waited formKeyIsWaitingForEventsTimeout = std::nullopt; // 清除等待超时return false;}// 到此说明之前还有事件没有派发完, mKeyIsWaitingForEventsTimeout没有value则说明还没设置等待if (!mKeyIsWaitingForEventsTimeout.has_value()) {// Start the timerALOGD("Waiting to send key to %s because there are unprocessed events that may cause ""focus to change",focusedWindowName);mKeyIsWaitingForEventsTimeout = currentTime + KEY_WAITING_FOR_EVENTS_TIMEOUT.count(); // 设置等待超时return true;}// We still have pending events, and already started the timerif (currentTime < *mKeyIsWaitingForEventsTimeout) { // 判断等待超时事件是否还没有到return true; // Still waiting}// Waited too long, and some connection still hasn't processed all motions// Just send the key to the focused windowALOGW("Dispatching key to %s even though there are other unprocessed events",focusedWindowName);mKeyIsWaitingForEventsTimeout = std::nullopt; // 清除等待超时return false;  // 已超时,不需要等待
}
InputDispatcher::addWindowTargetLocked
void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,int32_t targetFlags, BitSet32 pointerIds,std::vector<InputTarget>& inputTargets) {// 查找 windowHandle 对应的 InputTarget                                        std::vector<InputTarget>::iterator it =std::find_if(inputTargets.begin(), inputTargets.end(),[&windowHandle](const InputTarget& inputTarget) {return inputTarget.inputChannel->getConnectionToken() ==windowHandle->getToken();  // 根据InputChannel的token判断是否存在});const InputWindowInfo* windowInfo = windowHandle->getInfo();if (it == inputTargets.end()) { // 不存在对应的InputTargetInputTarget inputTarget;sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken()); // 根据token查找InputChannelif (inputChannel == nullptr) { // 不存在InputChannel, 直接返回ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());return;}// 初始化 InputTargetinputTarget.inputChannel = inputChannel;inputTarget.flags = targetFlags;inputTarget.globalScaleFactor = windowInfo->globalScaleFactor; // ignored for KeyEventsinputTargets.push_back(inputTarget);it = inputTargets.end() - 1;}ALOG_ASSERT(it->flags == targetFlags);ALOG_ASSERT(it->globalScaleFactor == windowInfo->globalScaleFactor);it->addPointers(pointerIds, -windowInfo->frameLeft, -windowInfo->frameTop,windowInfo->windowXScale, windowInfo->windowYScale); // 设置Pointer信息
}

InputDispatcher::setInjectionResult

这个函数用于设置通过InputDispatcher::injectInputEvent 注入事件的结果. 后续再开篇分析事件注入.

void InputDispatcher::setInjectionResult(EventEntry* entry, int32_t injectionResult) {InjectionState* injectionState = entry->injectionState;if (injectionState) { // 不为nullptr, 则是通过injectInputEvent注入的事件
#if DEBUG_INJECTIONALOGD("Setting input event injection result to %d.  ""injectorPid=%d, injectorUid=%d",injectionResult, injectionState->injectorPid, injectionState->injectorUid);
#endifif (injectionState->injectionIsAsync && !(entry->policyFlags & POLICY_FLAG_FILTERED)) {// Log the outcome since the injector did not wait for the injection result.switch (injectionResult) {case INPUT_EVENT_INJECTION_SUCCEEDED:ALOGV("Asynchronous input event injection succeeded.");break;case INPUT_EVENT_INJECTION_FAILED:ALOGW("Asynchronous input event injection failed.");break;case INPUT_EVENT_INJECTION_PERMISSION_DENIED:ALOGW("Asynchronous input event injection permission denied.");break;case INPUT_EVENT_INJECTION_TIMED_OUT:ALOGW("Asynchronous input event injection timed out.");break;}}injectionState->injectionResult = injectionResult;mInjectionResultAvailable.notify_all(); // 唤醒在injectInputEvent函数中的等待,处理结果}
}

InputDispatcher::addGlobalMonitoringTargetsLocked

将全局监视器也添加到目标窗口. 通过InputManagerService#monitorInput可以注册事件监听器. PointerEventDispatcher的实现是基于此原理实现的.

void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets,int32_t displayId, float xOffset,float yOffset) {std::unordered_map<int32_t, std::vector<Monitor>>::const_iterator it =mGlobalMonitorsByDisplay.find(displayId);if (it != mGlobalMonitorsByDisplay.end()) {const std::vector<Monitor>& monitors = it->second;for (const Monitor& monitor : monitors) {addMonitoringTargetLocked(monitor, xOffset, yOffset, inputTargets);}}
}

addMonitoringTargetLocked方法如下

void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, float xOffset,float yOffset,std::vector<InputTarget>& inputTargets) {InputTarget target;target.inputChannel = monitor.inputChannel;target.flags = InputTarget::FLAG_DISPATCH_AS_IS;target.setDefaultPointerInfo(xOffset, yOffset, 1 /* windowXScale */, 1 /* windowYScale */);inputTargets.push_back(target);
}

InputDispatcher::dispatchEventLocked

再次回到dispatchKeyLocked, 当获取到目标窗口后, 就可以调用dispatchEventLocked来将事件派发到窗口.

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,const std::vector<InputTarget>& inputTargets) {ATRACE_CALL();
#if DEBUG_DISPATCH_CYCLEALOGD("dispatchEventToCurrentInputTargets");
#endifALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to truepokeUserActivityLocked(*eventEntry); // 通知PMS user activityfor (const InputTarget& inputTarget : inputTargets) { // 遍历目标窗口sp<Connection> connection =getConnectionLocked(inputTarget.inputChannel->getConnectionToken()); // 根据InputChannel的token获取窗口的connectionif (connection != nullptr) { // 开始派发prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);} else {if (DEBUG_FOCUS) {ALOGD("Dropping event delivery to target with channel '%s' because it ""is no longer registered with the input dispatcher.",inputTarget.inputChannel->getName().c_str());}}}
}

InputDispatcher::prepareDispatchCycleLocked

这个方法开启了事件派发循环. 当将事件派发到目标窗口,在目标窗口处理完毕后, 会发送一个事件处理的反馈到dispatcher, 这才算一个闭环.

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection,EventEntry* eventEntry,const InputTarget& inputTarget) {if (ATRACE_ENABLED()) { /// tracestd::string message =StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, id=0x%" PRIx32 ")",connection->getInputChannelName().c_str(), eventEntry->id);ATRACE_NAME(message.c_str());}
#if DEBUG_DISPATCH_CYCLEALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, ""globalScaleFactor=%f, pointerIds=0x%x %s",connection->getInputChannelName().c_str(), inputTarget.flags,inputTarget.globalScaleFactor, inputTarget.pointerIds.value,inputTarget.getPointerInfoString().c_str());
#endif// Skip this event if the connection status is not normal.// We don't want to enqueue additional outbound events if the connection is broken.if (connection->status != Connection::STATUS_NORMAL) { // connection状态不是Normal的,丢弃此事件
#if DEBUG_DISPATCH_CYCLEALOGD("channel '%s' ~ Dropping event because the channel status is %s",connection->getInputChannelName().c_str(), connection->getStatusLabel());
#endifreturn;}// Split a motion event if needed.if (inputTarget.flags & InputTarget::FLAG_SPLIT) {  / /针对触摸事件LOG_ALWAYS_FATAL_IF(eventEntry->type != EventEntry::Type::MOTION,"Entry type %s should not have FLAG_SPLIT",EventEntry::typeToString(eventEntry->type));const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) {MotionEntry* splitMotionEntry =splitMotionEvent(originalMotionEntry, inputTarget.pointerIds);if (!splitMotionEntry) {return; // split event was dropped}if (DEBUG_FOCUS) {ALOGD("channel '%s' ~ Split motion event.",connection->getInputChannelName().c_str());logOutboundMotionDetails("  ", *splitMotionEntry);}enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget);splitMotionEntry->release();return;}}// Not splitting.  Enqueue dispatch entries for the event as is.enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}

InputDispatcher::enqueueDispatchEntriesLocked

将事件添加到派发队列, 然后看是否启动派发循环

  • 原来有事件在处理, 需要等待之前的结束
  • 原来队列是空, 则需要启动派发循环
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,const sp<Connection>& connection,EventEntry* eventEntry,const InputTarget& inputTarget) {if (ATRACE_ENABLED()) {std::string message =StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, id=0x%" PRIx32 ")",connection->getInputChannelName().c_str(), eventEntry->id);ATRACE_NAME(message.c_str());}bool wasEmpty = connection->outboundQueue.empty();// 添加dispatchEntry, 根据inputTarget的flags过滤不必要的, 对于key事件,对应的FLAG是FLAG_DISPATCH_AS_IS// Enqueue dispatch entries for the requested modes.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); // key事件这个dispatchMode会添加enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);// connection的派发队列为空, 添加新元素,会启动connection的事件派发, 否则等待之前的事件派发完成// 即之前的事件派发循环的反馈收到后, 再继续下一个派发循环// If the outbound queue was previously empty, start the dispatch cycle going.if (wasEmpty && !connection->outboundQueue.empty()) {   startDispatchCycleLocked(currentTime, connection);}
}
InputDispatcher::enqueueDispatchEntryLocked

对于key事件,对应的inputTarget.flags 只包含上面的FLAG_DISPATCH_AS_IS. 上面虽然加了很多dispatchMode, 但是大都被过滤掉了.

void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,EventEntry* eventEntry,const InputTarget& inputTarget,int32_t dispatchMode) {if (ATRACE_ENABLED()) {std::string message = StringPrintf("enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)",connection->getInputChannelName().c_str(),dispatchModeToString(dispatchMode).c_str());ATRACE_NAME(message.c_str());}int32_t inputTargetFlags = inputTarget.flags;if (!(inputTargetFlags & dispatchMode)) { // 过滤掉不包含的dispatchModereturn;}// 去掉除了dispatchMode的其他modeinputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;// This is a new event.// Enqueue a new dispatch entry onto the outbound queue for this connection.std::unique_ptr<DispatchEntry> dispatchEntry =createDispatchEntry(inputTarget, eventEntry, inputTargetFlags); // 对要派发的事件创建一个 DispatchEntry// Use the eventEntry from dispatchEntry since the entry may have changed and can now be a// different EventEntry than what was passed in.EventEntry* newEntry = dispatchEntry->eventEntry;// Apply target flags and update the connection's input state.switch (newEntry->type) {case EventEntry::Type::KEY: {const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*newEntry);dispatchEntry->resolvedEventId = keyEntry.id;dispatchEntry->resolvedAction = keyEntry.action;dispatchEntry->resolvedFlags = keyEntry.flags;if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction,dispatchEntry->resolvedFlags)) { // 处理 inconsistent key event
#if DEBUG_DISPATCH_CYCLEALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",connection->getInputChannelName().c_str());
#endifreturn; // skip the inconsistent event}break;}case EventEntry::Type::MOTION: {...case EventEntry::Type::FOCUS: {...case EventEntry::Type::CONFIGURATION_CHANGED: ...case EventEntry::Type::DEVICE_RESET: {...}// Remember that we are waiting for this dispatch to complete.if (dispatchEntry->hasForegroundTarget()) { // 实际上就是判断 targetFlags & InputTarget::FLAG_FOREGROUND , 处理key事件添加了此FLAGincrementPendingForegroundDispatches(newEntry); // 尝试增加 injectionState->pendingForegroundDispatches}// Enqueue the dispatch entry.connection->outboundQueue.push_back(dispatchEntry.release()); // 添加到connection->outboundQueuetraceOutboundQueueLength(connection);
}

InputDispatcher::startDispatchCycleLocked

回到enqueueDispatchEntriesLocked的最后, 假设需要启动派发循环,将调用startDispatchCycleLocked

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection) {while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) { // 取出所有的事件进行派发DispatchEntry* dispatchEntry = connection->outboundQueue.front(); // 取出头部dispatchEntry->deliveryTime = currentTime;const nsecs_t timeout =  // 计算超时时间,优先取出window->getDispatchingTimeout, 默认5sgetDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());dispatchEntry->timeoutTime = currentTime + timeout;// Publish the event.status_t status;EventEntry* eventEntry = dispatchEntry->eventEntry;switch (eventEntry->type) {case EventEntry::Type::KEY: {const KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);std::array<uint8_t, 32> hmac = getSignature(*keyEntry, *dispatchEntry);// Publish the key event.status =    /// 派发key事件connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, dispatchEntry->resolvedEventId,keyEntry->deviceId, keyEntry->source,keyEntry->displayId, std::move(hmac),dispatchEntry->resolvedAction,dispatchEntry->resolvedFlags, keyEntry->keyCode,keyEntry->scanCode, keyEntry->metaState,keyEntry->repeatCount, keyEntry->downTime,keyEntry->eventTime);break;}case EventEntry::Type::MOTION: {...case EventEntry::Type::FOCUS: {...case EventEntry::Type::CONFIGURATION_CHANGED:...case EventEntry::Type::DEVICE_RESET: {...}// Check the result.if (status) {  /// 不为 0 = OK , 说明派发失败if (status == WOULD_BLOCK) {if (connection->waitQueue.empty()) { // waitQueue 为空,没有需要等待反馈的事件,理论上发送不应该是阻塞的,说明出了问题ALOGE("channel '%s' ~ Could not publish event because the pipe is full. ""This is unexpected because the wait queue is empty, so the pipe ""should be empty and we shouldn't have any problems writing an ""event to it, status=%d",connection->getInputChannelName().c_str(), status);abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);// 处理 broken状态} else { // 这种情况需等待client处理完之前的事件// Pipe is full and we are waiting for the app to finish process some events// before sending more events to it.
#if DEBUG_DISPATCH_CYCLEALOGD("channel '%s' ~ Could not publish event because the pipe is full, ""waiting for the application to catch up",connection->getInputChannelName().c_str());
#endif}} else { // 其他错误ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, ""status=%d",connection->getInputChannelName().c_str(), status);abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);// 处理 broken状态}return; // 发送失败,此处直接返回}// Re-enqueue the event on the wait queue.connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),connection->outboundQueue.end(),dispatchEntry));  // 从派发队列移除已完成的dispatchEntrytraceOutboundQueueLength(connection);connection->waitQueue.push_back(dispatchEntry);  // 添加dispatchEntry到waitQueue, 等待client发送反馈if (connection->responsive) { // 如果connection处理可响应状态, 添加anr追踪mAnrTracker.insert(dispatchEntry->timeoutTime, // 超时时间connection->inputChannel->getConnectionToken()); // InputChannel的token}traceWaitQueueLength(connection);}
}

InputPublisher.publishKeyEvent

具体进行事件派发的是Connection的成员InputPublisher

/// @frameworks/native/libs/input/InputTransport.cpp
status_t InputPublisher::publishKeyEvent(uint32_t seq, int32_t eventId, int32_t deviceId,int32_t source, int32_t displayId,std::array<uint8_t, 32> hmac, int32_t action,int32_t flags, int32_t keyCode, int32_t scanCode,int32_t metaState, int32_t repeatCount, nsecs_t downTime,nsecs_t eventTime) {if (DEBUG_TRANSPORT_ACTIONS) {ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, ""action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,""downTime=%" PRId64 ", eventTime=%" PRId64,mChannel->getName().c_str(), seq, deviceId, source, action, flags, keyCode, scanCode,metaState, repeatCount, downTime, eventTime);}if (!seq) {ALOGE("Attempted to publish a key event with sequence number 0.");return BAD_VALUE;}// 将相关信息转换为 InputMessageInputMessage msg;msg.header.type = InputMessage::Type::KEY;msg.body.key.seq = seq;msg.body.key.eventId = eventId;msg.body.key.deviceId = deviceId;msg.body.key.source = source;msg.body.key.displayId = displayId;msg.body.key.hmac = std::move(hmac);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;return mChannel->sendMessage(&msg); // 通过 InputChannel 发送信息到Client.  返回值表示了发送结果状态
}

InputChannel::sendMessage

下面的返回值状态值 定义在 system/core/libutils/include/utils/Errors.h

  • OK = 0, // Preferred constant for checking success.
  • WOULD_BLOCK = -EWOULDBLOCK,
  • DEAD_OBJECT = -EPIPE,
status_t InputChannel::sendMessage(const InputMessage* msg) {const size_t msgLength = msg->size();InputMessage cleanMsg;msg->getSanitizedCopy(&cleanMsg);ssize_t nWrite;do {  // 此处向socket pair的server端写入, client端将会收到数据nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);} while (nWrite == -1 && errno == EINTR);if (nWrite < 0) { // 写入失败int error = errno;
#if DEBUG_CHANNEL_MESSAGESALOGD("channel '%s' ~ error sending message of type %d, %s", mName.c_str(),msg->header.type, strerror(error));
#endifif (error == EAGAIN || error == EWOULDBLOCK) {return WOULD_BLOCK;}if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) {return DEAD_OBJECT;}return -error;}if (size_t(nWrite) != msgLength) { // 写入不完整
#if DEBUG_CHANNEL_MESSAGESALOGD("channel '%s' ~ error sending message type %d, send was incomplete",mName.c_str(), msg->header.type);
#endifreturn DEAD_OBJECT;}#if DEBUG_CHANNEL_MESSAGESALOGD("channel '%s' ~ sent message of type %d", mName.c_str(), msg->header.type);
#endifreturn OK;  // 0
}

回到InputDispatcher::startDispatchCycleLocked, 在InputPublisher::publishKeyEvent发布事件后,如果成功,则将从派发队列移除已完成的dispatchEntry,并添加dispatchEntry到waitQueue, 等待client发送反馈,如果超时不能得到反馈,将触发ANR. 如果发布事件失败, 那么需要进行处理, 若是真正的阻塞状态,则进行等待就好;若是其他错误,则会调用abortBrokenDispatchCycleLocked处理管道broken.

InputDispatcher::abortBrokenDispatchCycleLocked
void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime,const sp<Connection>& connection,bool notify) {
#if DEBUG_DISPATCH_CYCLEALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s",connection->getInputChannelName().c_str(), toString(notify));
#endif// Clear the dispatch queues.drainDispatchQueue(connection->outboundQueue); // 清空派发队列traceOutboundQueueLength(connection);drainDispatchQueue(connection->waitQueue); / /清空等待队列traceWaitQueueLength(connection);// The connection appears to be unrecoverably broken.// Ignore already broken or zombie connections.if (connection->status == Connection::STATUS_NORMAL) {connection->status = Connection::STATUS_BROKEN;  // 标记connection状态为STATUS_BROKENif (notify) { // 通知broken状态// Notify other system components.onDispatchCycleBrokenLocked(currentTime, connection);  }}
}void InputDispatcher::drainDispatchQueue(std::deque<DispatchEntry*>& queue) {while (!queue.empty()) {DispatchEntry* dispatchEntry = queue.front();queue.pop_front();releaseDispatchEntry(dispatchEntry);}
}

看onDispatchCycleBrokenLocked实现,实际上就是投递了一个command. 最终的操作会交给doNotifyInputChannelBrokenLockedInterruptible

void InputDispatcher::onDispatchCycleBrokenLocked(nsecs_t currentTime,const sp<Connection>& connection) {ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",connection->getInputChannelName().c_str());std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(&InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);commandEntry->connection = connection;postCommandLocked(std::move(commandEntry));
}
InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible
void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry) {sp<Connection> connection = commandEntry->connection;if (connection->status != Connection::STATUS_ZOMBIE) { // 不是 unregistered 状态mLock.unlock();// 通知策略类,此connection的InputChannel的broken状态mPolicy->notifyInputChannelBroken(connection->inputChannel->getConnectionToken());mLock.lock();}
}

到此,关于key的派发已经通过InputChannel发送给了client, 后续client处理完后,会发送处理完毕的反馈.

回到InputDispatcher::dispatchOnceInnerLocked,当处理完事件派发后, 会根据dispatchKeyLocked的返回值done判断是否结束此处派发, 如果事件被丢弃了或者派发完成都会返回true

InputDispatcher::dispatchOnceInnerLocked(...){...if (done) { // 完成派发?if (dropReason != DropReason::NOT_DROPPED) { // 如果被丢弃// 给被丢弃的事件补发一个取消事件 AKEY_EVENT_ACTION_UPdropInboundEventLocked(*mPendingEvent, dropReason); // 处理丢弃的事件}mLastDropReason = dropReason; // 记录此处丢弃原因releasePendingEventLocked(); // 释放mPendingEvent// 立减进行下一轮派发*nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately}}

接下来看drop事件的处理

InputDispatcher::dropInboundEventLocked

void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason dropReason) {const char* reason;switch (dropReason) {case DropReason::POLICY: // 因为策略被丢弃, 事件可能在策略中被消耗ALOGD("Dropped event because policy consumed it.");reason = "inbound event was dropped because the policy consumed it";break;case DropReason::DISABLED: // 事件分发被禁止,通常设备处于 non-interactiveif (mLastDropReason != DropReason::DISABLED) {ALOGI("Dropped event because input dispatch is disabled.");}reason = "inbound event was dropped because input dispatch is disabled";break;case DropReason::APP_SWITCH: // app切换时间到期,需要丢弃此事件之前的所有事件ALOGI("Dropped event because of pending overdue app switch.");reason = "inbound event was dropped because of pending overdue app switch";break;case DropReason::BLOCKED: // 用户切换到新应用,因而丢弃之前ALOGI("Dropped event because the current application is not responding and the user ""has started interacting with a different application.");reason = "inbound event was dropped because the current application is not responding ""and the user has started interacting with a different application";break;case DropReason::STALE: // 事件长时间没有被处理,已过期ALOGI("Dropped event because it is stale.");reason = "inbound event was dropped because it is stale";break;case DropReason::NOT_DROPPED: {LOG_ALWAYS_FATAL("Should not be dropping a NOT_DROPPED event");return;}}switch (entry.type) {case EventEntry::Type::KEY: {CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason);// 此处尝试向所有的connection派发取消事件synthesizeCancelationEventsForAllConnectionsLocked(options);break;}case EventEntry::Type::MOTION: {const MotionEntry& motionEntry = static_cast<const MotionEntry&>(entry);if (motionEntry.source & AINPUT_SOURCE_CLASS_POINTER) {CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason);synthesizeCancelationEventsForAllConnectionsLocked(options);} else {CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason);synthesizeCancelationEventsForAllConnectionsLocked(options);}break;}case EventEntry::Type::FOCUS:case EventEntry::Type::CONFIGURATION_CHANGED:case EventEntry::Type::DEVICE_RESET: {LOG_ALWAYS_FATAL("Should not drop %s events", EventEntry::typeToString(entry.type));break;}}
}

InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked

void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(const CancelationOptions& options) {for (const auto& pair : mConnectionsByFd) { // 遍历所有的connection进行处理synthesizeCancelationEventsForConnectionLocked(pair.second, options);}
}

InputDispatcher::synthesizeCancelationEventsForConnectionLocked

void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(const sp<Connection>& connection, const CancelationOptions& options) {if (connection->status == Connection::STATUS_BROKEN) {return;}nsecs_t currentTime = now();// 创建取消事件, 它的KeyEntry的action是 AKEY_EVENT_ACTION_UPstd::vector<EventEntry*> cancelationEvents =connection->inputState.synthesizeCancelationEvents(currentTime, options);if (cancelationEvents.empty()) {return;}
#if DEBUG_OUTBOUND_EVENT_DETAILSALOGD("channel '%s' ~ Synthesized %zu cancelation events to bring channel back in sync ""with reality: %s, mode=%d.",connection->getInputChannelName().c_str(), cancelationEvents.size(), options.reason,options.mode);
#endifInputTarget target;sp<InputWindowHandle> windowHandle =getWindowHandleLocked(connection->inputChannel->getConnectionToken());if (windowHandle != nullptr) { // 获取InputChannel token对应的window信息const InputWindowInfo* windowInfo = windowHandle->getInfo();target.setDefaultPointerInfo(-windowInfo->frameLeft, -windowInfo->frameTop,windowInfo->windowXScale, windowInfo->windowYScale);target.globalScaleFactor = windowInfo->globalScaleFactor;}target.inputChannel = connection->inputChannel;target.flags = InputTarget::FLAG_DISPATCH_AS_IS;for (size_t i = 0; i < cancelationEvents.size(); i++) {EventEntry* cancelationEventEntry = cancelationEvents[i];switch (cancelationEventEntry->type) {case EventEntry::Type::KEY: {logOutboundKeyDetails("cancel - ",static_cast<const KeyEntry&>(*cancelationEventEntry));break;}case EventEntry::Type::MOTION: {logOutboundMotionDetails("cancel - ",static_cast<const MotionEntry&>(*cancelationEventEntry));break;}case EventEntry::Type::FOCUS: {LOG_ALWAYS_FATAL("Canceling focus events is not supported");break;}case EventEntry::Type::CONFIGURATION_CHANGED:case EventEntry::Type::DEVICE_RESET: {LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue",EventEntry::typeToString(cancelationEventEntry->type));break;}}// 添加到派发队列enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments reftarget, InputTarget::FLAG_DISPATCH_AS_IS);cancelationEventEntry->release();}// 开始派发startDispatchCycleLocked(currentTime, connection);
}
InputState::synthesizeCancelationEvents
std::vector<EventEntry*> InputState::synthesizeCancelationEvents(nsecs_t currentTime, const CancelationOptions& options) {std::vector<EventEntry*> events;// 遍历事件处理记录 , mKeyMementos 在Down事件时通过addKeyMemento添加memento, 在UP事件时删除对应的mementofor (KeyMemento& memento : mKeyMementos) { // 此列表的元素都是已经发生key Down, 但是还没有UP的记录if (shouldCancelKey(memento, options)) {  // 判断是否需要取消keyevents.push_back(new KeyEntry(mIdGenerator.nextId(), currentTime, memento.deviceId,memento.source, memento.displayId, memento.policyFlags,AKEY_EVENT_ACTION_UP, // up事件memento.flags | AKEY_EVENT_FLAG_CANCELED, memento.keyCode,memento.scanCode, memento.metaState, 0 /*repeatCount*/,memento.downTime));}}...// 省略motion event处理return events;
}

判断是否需要取消key事件, 返回true表示需要.

bool InputState::shouldCancelKey(const KeyMemento& memento, const CancelationOptions& options) {if (options.keyCode && memento.keyCode != options.keyCode.value()) { // 判断keyCodereturn false;}if (options.deviceId && memento.deviceId != options.deviceId.value()) { // 判断deviceIdreturn false;}if (options.displayId && memento.displayId != options.displayId.value()) { // 判断displayIdreturn false;}// 下面根据取消的模式switch (options.mode) {case CancelationOptions::CANCEL_ALL_EVENTS:case CancelationOptions::CANCEL_NON_POINTER_EVENTS:  // 上面取消key事件设置的此modereturn true;case CancelationOptions::CANCEL_FALLBACK_EVENTS:return memento.flags & AKEY_EVENT_FLAG_FALLBACK;default:return false;}
}

通过对上面的分析来看, 对于被丢弃的事件, 如果之前它存在Down事件, 会尝试补发一个UP事件,补全Down/Up事件对.

到此,dispatchOnceInnerLocked流程大致分析完毕, 回到dispatchOnce, 接下来执行runCommandsLockedInterruptible方法, 来处理pending的commands

InputDispatcher::runCommandsLockedInterruptible

这个方法主要用来处理pending的commands, 比如事件分发过程中处理interceptBeforeDispatch, 就是封装成一个command, 在dispatchOnceInnerLocked返回后接着被处理.

bool InputDispatcher::runCommandsLockedInterruptible() {if (mCommandQueue.empty()) {return false;}do {std::unique_ptr<CommandEntry> commandEntry = std::move(mCommandQueue.front()); // 取出头部mCommandQueue.pop_front();Command command = commandEntry->command;// 执行commandcommand(*this, commandEntry.get()); // commands are implicitly 'LockedInterruptible'commandEntry->connection.clear();} while (!mCommandQueue.empty());return true;
}

InputDispatcher::processAnrsLocked

在处理完command后, 会处理ANR检查,返回值表示下次唤醒的事件,方法逻辑如下:

  • 如果有在等待出现焦点窗口的操作,判断是否有超时
  • 对所有的connection检查是否有ANR出现
  • 如果出现超时,则会调用 onAnrLocked 通知出现ANR
/*** Check if any of the connections' wait queues have events that are too old.* If we waited for events to be ack'ed for more than the window timeout, raise an ANR.* Return the time at which we should wake up next.*/
nsecs_t InputDispatcher::processAnrsLocked() {const nsecs_t currentTime = now();nsecs_t nextAnrCheck = LONG_LONG_MAX;// Check if we are waiting for a focused window to appear. Raise ANR if waited too longif (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) {// 等待焦点应用的focused 窗口出现if (currentTime >= *mNoFocusedWindowTimeoutTime) { // 等待超时onAnrLocked(mAwaitedFocusedApplication);  // 通知ANRmAwaitedFocusedApplication.clear(); // 清除等待焦点应用信息return LONG_LONG_MIN;} else {// Keep waiting  继续等待焦点窗口出现, 计算到超时事件还有多久const nsecs_t millisRemaining = ns2ms(*mNoFocusedWindowTimeoutTime - currentTime);ALOGW("Still no focused window. Will drop the event in %" PRId64 "ms", millisRemaining);nextAnrCheck = *mNoFocusedWindowTimeoutTime;}}// Check if any connection ANRs are due 检查是否有connection中的ANR触发时间到了nextAnrCheck = std::min(nextAnrCheck, mAnrTracker.firstTimeout()); // 取出mAnrTracker最近的超时时间if (currentTime < nextAnrCheck) { // most likely scenario  还没到检查时间,即还没发生ANRreturn nextAnrCheck;          // everything is normal. Let's check again at nextAnrCheck}// If we reached here, we have an unresponsive connection.sp<Connection> connection = getConnectionLocked(mAnrTracker.firstToken());if (connection == nullptr) {ALOGE("Could not find connection for entry %" PRId64, mAnrTracker.firstTimeout());return nextAnrCheck;}connection->responsive = false; // 修改为未响应// Stop waking up for this unresponsive connectionmAnrTracker.eraseToken(connection->inputChannel->getConnectionToken()); // 移除此token对应的记录onAnrLocked(connection); // 通知ANR发生return LONG_LONG_MIN;
}

InputDispatcher::onAnrLocked

void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {// Since we are allowing the policy to extend the timeout, maybe the waitQueue// is already healthy again. Don't raise ANR in this situationif (connection->waitQueue.empty()) { // 如果此时waitQueue为空,没有等待处理的事件,不触发ANR.此种情况说明connection恢复正常ALOGI("Not raising ANR because the connection %s has recovered",connection->inputChannel->getName().c_str());return;}/*** The "oldestEntry" is the entry that was first sent to the application. That entry, however,* may not be the one that caused the timeout to occur. One possibility is that window timeout* has changed. This could cause newer entries to time out before the already dispatched* entries. In that situation, the newest entries caused ANR. But in all likelihood, the app* processes the events linearly. So providing information about the oldest entry seems to be* most useful.*/DispatchEntry* oldestEntry = *connection->waitQueue.begin();const nsecs_t currentWait = now() - oldestEntry->deliveryTime;std::string reason =android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s",connection->inputChannel->getName().c_str(),ns2ms(currentWait),oldestEntry->eventEntry->getDescription().c_str()); // 未响应原因updateLastAnrStateLocked(getWindowHandleLocked(connection->inputChannel->getConnectionToken()),reason);// 将ANR处理的操作封装为command投递到队列. 处理command会调用 doNotifyAnrLockedInterruptible函数                        std::unique_ptr<CommandEntry> commandEntry =std::make_unique<CommandEntry>(&InputDispatcher::doNotifyAnrLockedInterruptible);commandEntry->inputApplicationHandle = nullptr;commandEntry->inputChannel = connection->inputChannel;commandEntry->reason = std::move(reason);postCommandLocked(std::move(commandEntry));
}

看一下updateLastAnrStateLocked方法的处理

void InputDispatcher::updateLastAnrStateLocked(const sp<InputWindowHandle>& window,const std::string& reason) {const std::string windowLabel = getApplicationWindowLabel(nullptr, window);updateLastAnrStateLocked(windowLabel, reason);
}// dump ANR 记录
void InputDispatcher::updateLastAnrStateLocked(const std::string& windowLabel,const std::string& reason) {// Capture a record of the InputDispatcher state at the time of the ANR.time_t t = time(nullptr);struct tm tm;localtime_r(&t, &tm);char timestr[64];strftime(timestr, sizeof(timestr), "%F %T", &tm);mLastAnrState.clear();mLastAnrState += INDENT "ANR:\n";mLastAnrState += StringPrintf(INDENT2 "Time: %s\n", timestr);mLastAnrState += StringPrintf(INDENT2 "Reason: %s\n", reason.c_str());mLastAnrState += StringPrintf(INDENT2 "Window: %s\n", windowLabel.c_str());dumpDispatchStateLocked(mLastAnrState);
}
InputDispatcher::doNotifyAnrLockedInterruptible

处理ANR

void InputDispatcher::doNotifyAnrLockedInterruptible(CommandEntry* commandEntry) {sp<IBinder> token =commandEntry->inputChannel ? commandEntry->inputChannel->getConnectionToken() : nullptr;mLock.unlock();// 通过策略来通知ANR的发生const nsecs_t timeoutExtension =mPolicy->notifyAnr(commandEntry->inputApplicationHandle, token, commandEntry->reason);mLock.lock();if (timeoutExtension > 0) { // 延长ANR到timeoutExtension后再触发extendAnrTimeoutsLocked(commandEntry->inputApplicationHandle, token, timeoutExtension);} else {// stop waking up for events in this connection, it is already not respondingsp<Connection> connection = getConnectionLocked(token);if (connection == nullptr) {return;}cancelEventsForAnrLocked(connection); // 尝试派发取消事件}
}

总结

到此InputDispatcher的工作流程分析完毕, 可以发现事件派发的逻辑是串行派发,如果某些事件需要快速响应(如app switch),可能会导致之前的事件被丢弃,而让这些事件得到处理. 下面列出了事件丢弃的原因:

  • NOT_DROPPED, 未丢弃
  • POLICY, 策略原因,比如不传递给user. 可能是在策略处理中消耗了事件
  • APP_SWITCH, 应用切换按键事件(HOME,ENDCALL,APP_SWITCH)原因, 在这些事件之前的所有事件需要在0.5s 内派发完成, 否则就会被丢弃
  • DISABLED, 事件派发被禁止, 通过setInputDispatchMode设置
  • BLOCKED, 用户切换到新应用,因而丢弃之前. 通常是当前应用未响应 用户切换到新应用
  • STALE, 事件长时间未得到处理而过期 10s

另外,关于两个策略处理函数需要做一些说明:

  • NativeInputManager::interceptKeyBeforeQueueing
    - 方法在InputReader线程调用
    - 在InputReader将事件添加到InputDispatcher的派发队列之前调用
    - 通常处理事件是否传给user,可能被PhoneWindowManager消费掉
    - 回调java层的PhoneWindowManager#interceptKeyBeforeQueueing, 其返回1表示传递给user
  • NativeInputManager::interceptKeyBeforeDispatching 这方法在InputDispatcher线程调用
    - 方法在InputDispatcher线程调用
    - 在InputDispatcher::dispatchKeyLocked的事件派发之前,通过command调用
    - 回调PhoneWindowManager#interceptKeyBeforeDispatching, 返回值表示是否延时派发事件:
    - < 0 KeyEntry::INTERCEPT_KEY_RESULT_SKIP 跳过此事件,会被丢弃
    - = 0 INTERCEPT_KEY_RESULT_CONTINUE 不延时,继续处理
    - > 0 KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER 需要延时处理

InputDispatcher的工作主要在dispatchOnce方法中进行处理, 由其工作线程的threadLoop反复调用,处理相关逻辑.

  • dispatchOnceInnerLocked 进行一次事件派发的逻辑, 流程如下(key事件):

    • dispatchKeyLocked
      • doInterceptKeyBeforeDispatchingLockedInterruptible 这个操作是异步的,完成后会再次调用dispatchOnceInnerLocked
      • findFocusedWindowTargetsLocked 寻找焦点窗口
        - getValueByKey(mFocusedWindowHandlesByDisplay, displayId) 获取焦点应用
        - getValueByKey(mFocusedApplicationHandlesByDisplay, displayId) 获取焦点应用
        - shouldWaitToSendKeyLocked 若要派发的是key事件,需要等待之前的事件派发完成, 等待超时时间KEY_WAITING_FOR_EVENTS_TIMEOUT=500ms
        - addWindowTargetLocked 添加当前目标窗口到inputTargets列表
      • addGlobalMonitoringTargetsLocked 添加全局窗口监视器
    • dispatchEventLocked 遍历inputTargets, 给connection派发事件
    • prepareDispatchCycleLocked
    • enqueueDispatchEntriesLocked
      • enqueueDispatchEntryLocked 添加dispatchEntry到outboundQueue
    • startDispatchCycleLocked 完成事件派发 dispatchEntry 从 outboundQueue -> waitQueue , 添加ANR追踪
    • InputPublisher.publishKeyEvent 将事件信息转换成InputMessage,交给InputChannel发送
    • InputChannel->sendMessage 通过socket向client发送事件
  • runCommandsLockedInterruptible 执行相关的command,实际上是一系列函数操作的封装. 包括:

    • doNotifyAnrLockedInterruptible
    • doNotifyFocusChangedLockedInterruptible
    • doNotifyInputChannelBrokenLockedInterruptible
    • doDispatchCycleFinishedLockedInterruptible
    • doOnPointerDownOutsideFocusLockedInterruptible
    • doPokeUserActivityLockedInterruptible
    • doInterceptKeyBeforeDispatchingLockedInterruptible
    • doNotifyConfigurationChangedLockedInterruptible
  • processAnrsLocked 处理ANR的相关逻辑

    • 处理等待焦点窗口出现的超时 ,默认超时时间5s
    • 处理connection的超时(派发了事件,没有在超时时间内接收到事件反馈) ,默认超时时间5s

关于重复key事件(repeat key):

  • 默认自动合成repeat key(通过KeyRepeatState实现),第一次重复事件相较initial Down 间隔keyRepeatTimeout 500ms.且只有第一次(repeatCount=1)才会触发长按事件
  • 自动合成的多次重复事件之间的间隔是KeyRepeatDelay 50ms
  • 在派发队列mInboundQueue为空的时候才会去尝试合成重复事件,因此它的优先级较低
  • 若设备驱动生成了repeat key事件,则不需要自己合成重复事件,会重置mKeyRepeatState.lastKeyEntry,且设置nextRepeatTime = LONG_LONG_MAX. 设置且设置nextRepeatTime为最大,说明不再需要帮忙合成.

本篇主要将了如何将事件从InputDispatcher派发到焦点窗口,但这并不是一个完整的事件派发循环, 当client端处理事件后发送事件反馈, 如何InputDispatcher处理完事件反馈, 这才算是一个完整的事件派发循环. 关于事件反馈的发送与处理将在另一篇详细说明.

http://www.lbrq.cn/news/1562509.html

相关文章:

  • 网站配置到iis后读不了数据/在线生成个人网站免费
  • 武汉在建项目一览表/百度seo标题优化软件
  • 科技网站建设分析/补肾壮阳吃什么药效果好
  • 零代码开发/信阳seo推广
  • 国外特效网站/站长工具平台
  • 域名服务器ip/麒麟seo
  • 慈善公益网站建设/建站模板网站
  • 有哪些做网站好的公司好/武汉seo优化排名公司
  • 怎么分析竞争对手网站/网络营销成功案例
  • 做暖暖免费视频网站/新的数据新闻
  • 用css做网站的好处/北京网络营销招聘
  • 代办公司注册流程及材料/seo推广服务
  • b站推广引流最佳方法/seo推广有哪些方式
  • 快速迁移网站/seo模拟点击软件源码
  • 响应式企业网站制作公司/行者seo无敌
  • 郑州郑东新区网站建设/长尾词排名优化软件
  • 东营 网站建设/如何提高自己在百度的排名
  • 传奇做网站/seo网站推广什么意思
  • 网站视频链接/西安网站建设推广专家
  • 网站开发 例子/卢松松外链工具
  • 广州市建设监理协会网站/哪些店铺适合交换友情链接
  • 装饰公司营销型网站建设/西安关键词排名推广
  • 平顶山市建设委员会网站/郑州搜索引擎优化
  • 西安高校定制网站建设公司推荐/优化网站平台
  • 做游戏陪玩网站/推广文案范例
  • 网站建设市场分析报告/口碑营销案例ppt
  • 江苏句容市疫情最新情况/青岛seo网站关键词优化
  • 有人在相亲网站骗人做传销/单页面seo搜索引擎优化
  • 网站筛选功能/我在百度下的订单如何查询
  • 路由器 东莞网站建设/建站流程主要有哪些
  • ISO27001 高阶架构 之 支持 -2
  • Python 项目高频设计模式实战指南:从理念到落地的全景剖析
  • Tomcat架构深度解析:从Server到Servlet的全流程揭秘
  • Flutter Provider 模式实现:基于 InheritedWidget 的状态管理实现
  • 【Twincat3】IO的SCAN 不可选中,SCAN中后扫描不到设备
  • 【LeetCode 热题 100】55. 跳跃游戏