Android R input (三) 之 InputDispatcher 工作流程

文章托管在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为默认id
        mFocusedDisplayId(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 获取第一个按键重复事件的超时时间 默认500ms
    if (!checkAndClearExceptionFromCallback(env, "getKeyRepeatTimeout")) {
        outConfig->keyRepeatTimeout = milliseconds_to_nanoseconds(keyRepeatTimeout);
    }

    jint keyRepeatDelay = env->CallIntMethod(mServiceObj,
            gServiceClassInfo.getKeyRepeatDelay); // 获取连续重复按键之间的时间 50s
    if (!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 lock
        std::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()) { // 执行commands
            nextWakeupTime = 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(); // 处理anr
        nextWakeupTime = std::min(nextWakeupTime, nextAnrCheck);

        // We are about to enter an infinitely long sleep, because we have no commands or
        // pending or queued events
        if (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-interactive
        resetKeyRepeatLocked();
    }

    // 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 changed
            ConfigurationChangedEntry* typedEntry =
                    static_cast<ConfigurationChangedEntry*>(mPendingEvent);
            done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
            dropReason = DropReason::NOT_DROPPED; // configuration changes are never dropped
            break;
        }

        case EventEntry::Type::DEVICE_RESET: { //  device reset
            DeviceResetEntry* typedEntry = static_cast<DeviceResetEntry*>(mPendingEvent);
            done = dispatchDeviceResetLocked(currentTime, typedEntry);
            dropReason = DropReason::NOT_DROPPED; // device resets are never dropped
            break;
        }

        case EventEntry::Type::FOCUS: {
            FocusEntry* typedEntry = static_cast<FocusEntry*>(mPendingEvent);
            dispatchFocusLocked(currentTime, typedEntry);
            done = true;
            dropReason = DropReason::NOT_DROPPED; // focus events are never dropped
            break;
        }

        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)) { // 过期事件, 此时距离事件发生时间>=10sec
                dropReason = 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); // 添加flag
    if (entry->refCount == 1) { // 没有其他引用时复用,防止冲突. entry->refCount默认是1
        entry->recycle();
        entry->id = mIdGenerator.nextId();
        entry->eventTime = currentTime;
        entry->policyFlags = policyFlags;
        entry->repeatCount += 1;
    } else { // 已在其他地方被引用,需要创建新entry
        KeyEntry* 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 50ms
    return 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; // 递增repeatCount
                resetKeyRepeatLocked(); // 重置 mKeyRepeatState 为nullptr
                mKeyRepeatState.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; // 设置新的lastKeyEntry
            entry->refCount += 1;
        } else if (!entry->syntheticRepeat) { // 不是合成的repeat事件
            resetKeyRepeatLocked(); // 重置 lastKeyEntry
        }

        if (entry->repeatCount == 1) { // repeatCount 为1, 则添加长按事件的FLAG
            entry->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后处理command
            std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
                    &InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
            sp<InputWindowHandle> focusedWindowHandle =
                    getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(*entry));// 获取指定displayId对应的focusedWindowHandle
            if (focusedWindowHandle != nullptr) {
                commandEntry->inputChannel = getInputChannelLocked(focusedWindowHandle->getToken());
            }
            commandEntry->keyEntry = entry;
            postCommandLocked(std::move(commandEntry)); // 投递command
            entry->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 token
    sp<IBinder> token = commandEntry->inputChannel != nullptr
            ? commandEntry->inputChannel->getConnectionToken()
            : nullptr;
    // 调用路径 NativeInputManager -> InputManagerService -> InputManagerCallback -> PhoneWindowManager
    nsecs_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); // 获取焦点窗口 handle
    sp<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 timer
            const 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 event
            ALOGE("Dropping %s event because there is no focused window",
                  EventEntry::typeToString(entry.type));
            return INPUT_EVENT_INJECTION_FAILED; // 已经等待超时, 返回失败
        } else {
            // Still waiting for the focused window
            return INPUT_EVENT_INJECTION_PENDING;  // 还未超时, 继续等待
        }
    }

    // we have a valid, non-null focused window
    resetNoFocusedWindowTimeoutLocked();  // 重置超时时间, Resetting ANR timeouts

    // Check permissions. 主要是通过IMS来检查权限 android.Manifest.permission.INJECT_EVENTS
    if (!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, 在派发时生成对应的dispatchEntry
                          BitSet32(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 for
        mKeyIsWaitingForEventsTimeout = std::nullopt; // 清除等待超时
        return false;
    }

    // 到此说明之前还有事件没有派发完, mKeyIsWaitingForEventsTimeout没有value则说明还没设置等待
    if (!mKeyIsWaitingForEventsTimeout.has_value()) {
        // Start the timer
        ALOGD("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 timer
    if (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 window
    ALOGW("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()) { // 不存在对应的InputTarget
        InputTarget inputTarget;
        sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken()); // 根据token查找InputChannel
        if (inputChannel == nullptr) { // 不存在InputChannel, 直接返回
            ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());
            return;
        }
        // 初始化 InputTarget
        inputTarget.inputChannel = inputChannel;
        inputTarget.flags = targetFlags;
        inputTarget.globalScaleFactor = windowInfo->globalScaleFactor; // ignored for KeyEvents
        inputTargets.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_INJECTION
        ALOGD("Setting input event injection result to %d.  "
              "injectorPid=%d, injectorUid=%d",
              injectionResult, injectionState->injectorPid, injectionState->injectorUid);
#endif

        if (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_CYCLE
    ALOGD("dispatchEventToCurrentInputTargets");
#endif

    ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true

    pokeUserActivityLocked(*eventEntry); // 通知PMS user activity

    for (const InputTarget& inputTarget : inputTargets) { // 遍历目标窗口
        sp<Connection> connection =
                getConnectionLocked(inputTarget.inputChannel->getConnectionToken()); // 根据InputChannel的token获取窗口的connection
        if (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()) { /// trace
        std::string message =
                StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, id=0x%" PRIx32 ")",
                             connection->getInputChannelName().c_str(), eventEntry->id);
        ATRACE_NAME(message.c_str());
    }
#if DEBUG_DISPATCH_CYCLE
    ALOGD("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_CYCLE
        ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
              connection->getInputChannelName().c_str(), connection->getStatusLabel());
#endif
        return;
    }

    // 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)) { // 过滤掉不包含的dispatchMode
        return;
    }
    // 去掉除了dispatchMode的其他mode
    inputTargetFlags = (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_CYCLE
                ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",
                      connection->getInputChannelName().c_str());
#endif
                return; // 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事件添加了此FLAG
        incrementPendingForegroundDispatches(newEntry); // 尝试增加 injectionState->pendingForegroundDispatches
    }

    // Enqueue the dispatch entry.
    connection->outboundQueue.push_back(dispatchEntry.release()); // 添加到connection->outboundQueue
    traceOutboundQueueLength(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, 默认5s
                getDispatchingTimeoutLocked(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_CYCLE
                    ALOGD("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));  // 从派发队列移除已完成的dispatchEntry
        traceOutboundQueueLength(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;
    }

    // 将相关信息转换为 InputMessage
    InputMessage 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_MESSAGES
        ALOGD("channel '%s' ~ error sending message of type %d, %s", mName.c_str(),
              msg->header.type, strerror(error));
#endif
        if (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_MESSAGES
        ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
                mName.c_str(), msg->header.type);
#endif
        return DEAD_OBJECT;
    }

#if DEBUG_CHANNEL_MESSAGES
    ALOGD("channel '%s' ~ sent message of type %d", mName.c_str(), msg->header.type);
#endif
    return 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_CYCLE
    ALOGD("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_BROKEN

        if (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_UP
          dropInboundEventLocked(*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-interactive
            if (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_UP
    std::vector<EventEntry*> cancelationEvents =
            connection->inputState.synthesizeCancelationEvents(currentTime, options);

    if (cancelationEvents.empty()) {
        return;
    }
#if DEBUG_OUTBOUND_EVENT_DETAILS
    ALOGD("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);
#endif

    InputTarget 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 ref
                                   target, 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事件时删除对应的memento
    for (KeyMemento& memento : mKeyMementos) { // 此列表的元素都是已经发生key Down, 但是还没有UP的记录
        if (shouldCancelKey(memento, options)) {  // 判断是否需要取消key
            events.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()) { // 判断keyCode
        return false;
    }

    if (options.deviceId && memento.deviceId != options.deviceId.value()) { // 判断deviceId
        return false;
    }

    if (options.displayId && memento.displayId != options.displayId.value()) { // 判断displayId
        return false;
    }
    // 下面根据取消的模式
    switch (options.mode) {
        case CancelationOptions::CANCEL_ALL_EVENTS:
        case CancelationOptions::CANCEL_NON_POINTER_EVENTS:  // 上面取消key事件设置的此mode
            return 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;
        // 执行command
        command(*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 long
    if (mNoFocusedWindowTimeoutTime.has_value() && mAwaitedFocusedApplication != nullptr) {// 等待焦点应用的focused 窗口出现
        if (currentTime >= *mNoFocusedWindowTimeoutTime) { // 等待超时
            onAnrLocked(mAwaitedFocusedApplication);  // 通知ANR
            mAwaitedFocusedApplication.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  还没到检查时间,即还没发生ANR
        return 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 connection
    mAnrTracker.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 situation
    if (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 responding
        sp<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处理完事件反馈, 这才算是一个完整的事件派发循环. 关于事件反馈的发送与处理将在另一篇详细说明.

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值