Andorid U Input系统:按键事件分发

1,962 阅读8分钟

本文只讨论一次成功的按键事件分发的流程。

InputDispatcher 处理按键事件

// InputDispatcher.cpp

void InputDispatcher::notifyKey(const NotifyKeyArgs& args) {
    ALOGD_IF(debugInboundEventDetails(),
             "notifyKey - id=%" PRIx32 ", eventTime=%" PRId64
             ", deviceId=%d, source=%s, displayId=%" PRId32
             "policyFlags=0x%x, action=%s, flags=0x%x, keyCode=%s, scanCode=0x%x, metaState=0x%x, "
             "downTime=%" PRId64,
             args.id, args.eventTime, args.deviceId, inputEventSourceToString(args.source).c_str(),
             args.displayId, args.policyFlags, KeyEvent::actionToString(args.action), args.flags,
             KeyEvent::getLabel(args.keyCode), args.scanCode, args.metaState, args.downTime);
    Result<void> keyCheck = validateKeyEvent(args.action);
    if (!keyCheck.ok()) {
        LOG(ERROR) << "invalid key event: " << keyCheck.error();
        return;
    }

    // policyFlags 来自于按键映射的文件
    uint32_t policyFlags = args.policyFlags;
    // flags 目前为 AKEY_EVENT_FLAG_FROM_SYSTEM
    int32_t flags = args.flags;
    // meta 按键的状态
    int32_t metaState = args.metaState;

    // InputDispatcher tracks and generates key repeats on behalf of
    // whatever notifies it, so repeatCount should always be set to 0
    constexpr int32_t repeatCount = 0;
    if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) {
        policyFlags |= POLICY_FLAG_VIRTUAL;
        flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY;
    }
    if (policyFlags & POLICY_FLAG_FUNCTION) {
        metaState |= AMETA_FUNCTION_ON;
    }

    // 来自输入设备的按键事件,都是受信任的
    policyFlags |= POLICY_FLAG_TRUSTED;

    int32_t keyCode = args.keyCode;
    // 根据 meta state 转换 key code
    accelerateMetaShortcuts(args.deviceId, args.action, keyCode, metaState);

    KeyEvent event;
    event.initialize(args.id, args.deviceId, args.source, args.displayId, INVALID_HMAC, args.action,
                     flags, keyCode, args.scanCode, metaState, repeatCount, args.downTime,
                     args.eventTime);
    android::base::Timer t;
    // 按键事件加入到队列前,先让策略尝试截断处理
    mPolicy.interceptKeyBeforeQueueing(event, /*byref*/ policyFlags);
    if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
        ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms",
              std::to_string(t.duration().count()).c_str());
    }

    bool needWake = false;
    { // acquire lock
        mLock.lock();

        if (shouldSendKeyToInputFilterLocked(args)) {
            mLock.unlock();

            policyFlags |= POLICY_FLAG_FILTERED;
            if (!mPolicy.filterInputEvent(event, policyFlags)) {
                return; // event was consumed by the filter
            }

            mLock.lock();
        }

        std::unique_ptr<KeyEntry> newEntry =
                std::make_unique<KeyEntry>(args.id, args.eventTime, args.deviceId, args.source,
                                           args.displayId, policyFlags, args.action, flags, keyCode,
                                           args.scanCode, metaState, repeatCount, args.downTime);
        // 按键事件加入到 inbound queue 中
        needWake = enqueueInboundEventLocked(std::move(newEntry));
        mLock.unlock();
    } // release lock

    // 如果有必要,唤醒 InputDispatcher 线程,处理按键事件
    if (needWake) {
        mLooper->wake();
    }
}

当 InputDispatcher 收到按键事件时,首先是询问策略,如果策略允许分发事件,那么会在 policyFlags 中添加 POLICY_FLAG_PASS_TO_USER ,表示策略允许分发按键事件给窗口,否则表示策略不允许分发事件。

策略不在本文的讨论范围。

策略处理了之后,按键事件加入到 InputDispatcher 的 inbound queue 中,然后唤醒 InputDispatcher 线程开始分发按键事件

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LLONG_MAX;
    { // acquire lock
        std::scoped_lock _l(mLock);
        mDispatcherIsAlive.notify_all();

        // Run a dispatch loop if there are no pending commands.
        // The dispatch loop might enqueue commands to run afterwards.
        // 如果没有命令,就执行一次分发循环
        // 何为循环,就是是把事件发送给窗口,窗口反馈处理事件的结果
        if (!haveCommandsLocked()) {
            dispatchOnceInnerLocked(&nextWakeupTime);
        }

        // ...
        }
    } // release lock

    // ...
}

假设此时没有命令需要执行,那么会先执行一次分发循环(dispatch loop)

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    // ...

    if (!mPendingEvent) {
        if (mInboundQueue.empty()) {
            // ...
        } else {
            // Inbound queue has at least one entry.
            // 从 inbound queue 队头取出事件
            mPendingEvent = mInboundQueue.front();
            mInboundQueue.pop_front();
            traceInboundQueueLengthLocked();
        }

        // ...
    }

    // 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;
    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::KEY: {
            std::shared_ptr<KeyEntry> keyEntry = std::static_pointer_cast<KeyEntry>(mPendingEvent);
            if (isAppSwitchDue) {
                if (isAppSwitchKeyEvent(*keyEntry)) {
                    resetPendingAppSwitchLocked(true);
                    isAppSwitchDue = false;
                } else if (dropReason == DropReason::NOT_DROPPED) {
                    dropReason = DropReason::APP_SWITCH;
                }
            }
            if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *keyEntry)) {
                dropReason = DropReason::STALE;
            }
            if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
                dropReason = DropReason::BLOCKED;
            }

            // 分发按键事件
            done = dispatchKeyLocked(currentTime, keyEntry, &dropReason, nextWakeupTime);
            break;
        }

        // ...
    }

    // ...
}

从 InputDispatcher inbound queue 中取出按键事件,然后开始分发

bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry,
                                        DropReason* dropReason, nsecs_t* nextWakeupTime) {
    // ...

    // 1. 再次循环策略
    if (entry->interceptKeyResult == KeyEntry::InterceptKeyResult::TRY_AGAIN_LATER) {
        // ...
    }
    if (entry->interceptKeyResult == KeyEntry::InterceptKeyResult::UNKNOWN) {
        if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
            sp<IBinder> focusedWindowToken =
                    mFocusResolver.getFocusedWindowToken(getTargetDisplayId(*entry));

            // 通过一个命令再次询问策略
            auto command = [this, focusedWindowToken, entry]() REQUIRES(mLock) {
                doInterceptKeyBeforeDispatchingCommand(focusedWindowToken, *entry);
            };
            postCommandLocked(std::move(command));
            // Poke user activity for keys not passed to user
            pokeUserActivityLocked(*entry);

            // 此次分发循环结束
            return false; // wait for the command to run
        } else {
            entry->interceptKeyResult = KeyEntry::InterceptKeyResult::CONTINUE;
        }
    } else if (entry->interceptKeyResult == KeyEntry::InterceptKeyResult::SKIP) {
        // ...
    }

    // 2. 如果有丢弃的原因,那么事件不再分发
    if (*dropReason != DropReason::NOT_DROPPED) {
        setInjectionResult(*entry,
                           *dropReason == DropReason::POLICY ? InputEventInjectionResult::SUCCEEDED
                                                             : InputEventInjectionResult::FAILED);
        mReporter->reportDroppedKey(entry->id);
        // Poke user activity for undispatched keys
        pokeUserActivityLocked(*entry);
        return true;
    }

    // Identify targets.
    InputEventInjectionResult injectionResult;

    // 3. 寻找焦点窗口
    sp<WindowInfoHandle> focusedWindow =
            findFocusedWindowTargetLocked(currentTime, *entry, nextWakeupTime,
                                          /*byref*/ injectionResult);
    if (injectionResult == InputEventInjectionResult::PENDING) {
        return false;
    }

    setInjectionResult(*entry, injectionResult);
    if (injectionResult != InputEventInjectionResult::SUCCEEDED) {
        return true;
    }
    LOG_ALWAYS_FATAL_IF(focusedWindow == nullptr);

    // inputTargets 保存的事件要分发的目标
    std::vector<InputTarget> inputTargets;

    // 4.为焦点窗口,创建 InputTarget,保存到 inputTargets 中
    addWindowTargetLocked(focusedWindow,
                          InputTarget::Flags::FOREGROUND | InputTarget::Flags::DISPATCH_AS_IS,
                          /*pointerIds=*/{}, getDownTime(*entry), inputTargets);

    // TODO: 暂不讨论 global monitor
    addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));

    // 5.继续分发事件
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}

按键事件,在分发之前,会通过一个命令,再次询问策略,而此次询问策略,一般是为了实现组合按键的功能,本文不深入讨论。

假设此次策略仍然允许按键事件分发,那么会为这个按键事件寻找焦点窗口

sp<WindowInfoHandle> InputDispatcher::findFocusedWindowTargetLocked(
        nsecs_t currentTime, const EventEntry& entry, nsecs_t* nextWakeupTime,
        InputEventInjectionResult& outInjectionResult) {
    std::string reason;
    outInjectionResult = InputEventInjectionResult::FAILED; // Default result

    int32_t displayId = getTargetDisplayId(entry);
    // 获取屏幕的焦点窗口
    sp<WindowInfoHandle> focusedWindowHandle = getFocusedWindowHandleLocked(displayId);

    // ...

    outInjectionResult = InputEventInjectionResult::SUCCEEDED;
    return focusedWindowHandle;
}

sp<WindowInfoHandle> InputDispatcher::getFocusedWindowHandleLocked(int displayId) const {
    // 先从 FocusResolver 获取焦点窗口
    sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(displayId);

    // 验证这个焦点窗口是否存在 diaplay 下
    // 因此焦点窗口可能过期了,但是屏幕下的所有窗口,是会实时更新的
    return getWindowHandleLocked(focusedToken, displayId);
}

sp<WindowInfoHandle> InputDispatcher::getWindowHandleLocked(const sp<IBinder>& windowHandleToken,
                                                            int displayId) const {
    if (windowHandleToken == nullptr) {
        return nullptr;
    }

    // 根据 token 匹配 display 下的窗口
    for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesLocked(displayId)) {
        if (windowHandle->getToken() == windowHandleToken) {
            return windowHandle;
        }
    }
    return nullptr;
}

焦点窗口是从 FocusResolver 获取的

// FocusResolver.cpp

sp<IBinder> FocusResolver::getFocusedWindowToken(int32_t displayId) const {
    // 这个焦点窗口,是从 WMS 设置下来的,或者 FocusResolver 根据屏幕下的所有窗口解析出来的
    auto it = mFocusedWindowTokenByDisplay.find(displayId);
    return it != mFocusedWindowTokenByDisplay.end() ? it->second.second : nullptr;
}

FocusResolver 中通过一个数据结构,保存了焦点窗口。那么这个焦点窗口哪里来的呢? 有两种情况,一种是 WMS 设置下来的,另外一种情况是 FocusResolver 自己解析出来。本文不深入探讨这个焦点窗口的话题。

当找到焦点窗口后,会继续分发按键事件

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
                                          std::shared_ptr<EventEntry> eventEntry,
                                          const std::vector<InputTarget>& inputTargets) {
    // ...

    for (const InputTarget& inputTarget : inputTargets) {

        // 根据 InputChannel token 获取 Connection
        std::shared_ptr<Connection> connection =
                getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
        if (connection != nullptr) {
            // 准备分发循环
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
        } else {
            
        }
    }
}

当 ViewRootImpl 向 WMS add window 时,如果窗口能够接受事件,那么 WMS 会通知 InputDispather 创建一个 InputChannel ,InputDispather 会创建 Connection 保存这个 InputChannel,然后 Connection 保存到 mConnectionsByToken 中。

因此,这里可以通过 InputChannel token 获取到 Connection,然后准备分发循环

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
                                                 const std::shared_ptr<Connection>& connection,
                                                 std::shared_ptr<EventEntry> eventEntry,
                                                 const InputTarget& inputTarget) {
    // ...

    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}

void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
                                                   const std::shared_ptr<Connection>& connection,
                                                   std::shared_ptr<EventEntry> eventEntry,
                                                   const InputTarget& inputTarget) {
    // ...

    const bool wasEmpty = connection->outboundQueue.empty();

    // Enqueue dispatch entries for the requested modes.
    // ...
    // 向 connection->outboundQueue 保存按键事件
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                               InputTarget::Flags::DISPATCH_AS_IS);
    // ...

    // 启动分发循环
    if (wasEmpty && !connection->outboundQueue.empty()) {
        startDispatchCycleLocked(currentTime, connection);
    }
}

void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connection>& connection,
                                                 std::shared_ptr<EventEntry> eventEntry,
                                                 const InputTarget& inputTarget,
                                                 ftl::Flags<InputTarget::Flags> dispatchMode) {
    // ...

    inputTargetFlags.clear(InputTarget::DISPATCH_MASK);
    // 保存 InputTarget::Flags::DISPATCH_AS_I
    inputTargetFlags |= dispatchMode;

    // 1.创建 DispatchEntry
    std::unique_ptr<DispatchEntry> dispatchEntry =
            createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);


    EventEntry& newEntry = *(dispatchEntry->eventEntry);
    switch (newEntry.type) {
        case EventEntry::Type::KEY: {
            // 2.向 DispatchEntry 填充数据
            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(newEntry);
            dispatchEntry->resolvedEventId = keyEntry.id;
            dispatchEntry->resolvedAction = keyEntry.action;
            dispatchEntry->resolvedFlags = keyEntry.flags;

            // ...
            break;
        }

        // ...
    }

    // Remember that we are waiting for this dispatch to complete.
    if (dispatchEntry->hasForegroundTarget()) {
        incrementPendingForegroundDispatches(newEntry);
    }

    // 3. DispatchEntry 保存到 connection->outboundQueue
    connection->outboundQueue.push_back(dispatchEntry.release());
    traceOutboundQueueLength(*connection);
}

所谓的准备分发循环,其实就是创建 dispatchEntry,保存按键事件信息,然后 dispatchEntry 保存到 connection->outboundQueue 中。最后,真正开始分发循环

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
                                               const std::shared_ptr<Connection>& connection) {
    // ...

    // 通过一个 while 循环,把 onnection->outboundQueue 中保存的事件全部发送出去
    while (connection->status == Connection::Status::NORMAL && !connection->outboundQueue.empty()) {

        // 1.从 onnection->outboundQueue 获取事件
        DispatchEntry* dispatchEntry = connection->outboundQueue.front();
        
        // ...
        
        status_t status;
        const EventEntry& eventEntry = *(dispatchEntry->eventEntry);
        switch (eventEntry.type) {
            case EventEntry::Type::KEY: {
                const KeyEntry& keyEntry = static_cast<const KeyEntry&>(eventEntry);
                
                // ...

                // 2. 发布事件给窗口
                status = 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;
            }

            // ...
        }

        // ...

        // 3. 把已经发布的事件从 onnection->outboundQueue 中移除
        connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
                                                    connection->outboundQueue.end(),
                                                    dispatchEntry));

        // 4. 需要等待窗口反馈事件处理结果,因此需要把已经发送的事件保存到 connection->waitQueue.
        connection->waitQueue.push_back(dispatchEntry);
        
        // ...
    }
}

分发循环,就是把 connection->outboundQueue 中的事件发送给窗口。但是,为了防止窗口无响应,或者响应慢,因此还需要把已经发送的事件保存到 connection->waitQueue。

至此,按键事件的分发已经完成。但是,既然分发循环,就得有来有回,当窗口处理完事件后,会反馈时间处理结果给 InpputDispatcher。 InputDispatcher 利用 Looper 机制,会收到回调

int InputDispatcher::handleReceiveCallback(int events, sp<IBinder> connectionToken) {
    std::scoped_lock _l(mLock);
    std::shared_ptr<Connection> connection = getConnectionLocked(connectionToken);


    bool notify;
    if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {

        nsecs_t currentTime = now();
        bool gotOne = false;
        status_t status = OK;

        // 通过一个无线循环,读取所有消息
        for (;;) {
            // 1 获取窗口返回的结果
            Result<InputPublisher::ConsumerResponse> result =
                    connection->inputPublisher.receiveConsumerResponse();
            if (!result.ok()) {
                status = result.error().code();
                break;
            }

            if (std::holds_alternative<InputPublisher::Finished>(*result)) {
                const InputPublisher::Finished& finish =
                        std::get<InputPublisher::Finished>(*result);

                // 2 完成此次分发循环
                finishDispatchCycleLocked(currentTime, connection, finish.seq, finish.handled,
                                          finish.consumeTime);
            } else if (std::holds_alternative<InputPublisher::Timeline>(*result)) {

            }
            gotOne = true;
        }

        if (gotOne) {
            // 3 运行完成分发循环中保存的命令
            runCommandsLockedInterruptable();
            if (status == WOULD_BLOCK) {
                return 1;
            }
        }

        notify = status != DEAD_OBJECT || !connection->monitor;
        if (notify) {
            ALOGE("channel '%s' ~ Failed to receive finished signal.  status=%s(%d)",
                  connection->getInputChannelName().c_str(), statusToString(status).c_str(),
                  status);
        }
    } else {
        
    }

    // TODO: 为何要移除 InputChannel 呢?
    removeInputChannelLocked(connection->inputChannel->getConnectionToken(), notify);
    return 0; // remove the callback
}

收到窗口的反馈后,立即完成此次分发循环

void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
                                                const std::shared_ptr<Connection>& connection,
                                                uint32_t seq, bool handled, nsecs_t consumeTime) {
    // ...

    // 创建一个命令保存到 mCommandQueue 中
    auto command = [this, currentTime, connection, seq, handled, consumeTime]() REQUIRES(mLock) {
        doDispatchCycleFinishedCommand(currentTime, connection, seq, handled, consumeTime);
    };
    postCommandLocked(std::move(command));
}

完成分发循环只是保存了一个命令,而下一步就是执行这个命令


void InputDispatcher::doDispatchCycleFinishedCommand(nsecs_t finishTime,
                                                     const std::shared_ptr<Connection>& connection,
                                                     uint32_t seq, bool handled,
                                                     nsecs_t consumeTime) {
    // ...

    // 从 wait queue 中获取事件
    dispatchEntryIt = connection->findWaitQueueEntry(seq);

    if (dispatchEntryIt != connection->waitQueue.end()) {
        dispatchEntry = *dispatchEntryIt;

        // 从 wait queue 中移除事件
        connection->waitQueue.erase(dispatchEntryIt);

        // ...
    }

    // 如果 connection 的 outbound queu 中还有事件,那么再次启动分发循环
    startDispatchCycleLocked(now(), connection);
}

完成分发循环是,事件从 connection 的 wait queue 中移除,这样就不会发生 ANR。