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

2,314 阅读13分钟

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

// 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);
    // ...

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

    // ...

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

    int32_t keyCode = args.keyCode;
    
    // ...

    // 这里创建 KeyEvent 保存按键数据,是为了发送给策略处理
    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();

        // 如果上层设置了 InputFilter,这里要把事件先发送给 InputFilter 处理
        if (shouldSendKeyToInputFilterLocked(args)) {
            // ...
        }

        // 创建 KeyEvent 保存按键事件数据,之后由 InputDispatcher 线程处理
        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);
        // KeyEvent 加入到 inbound queue 中
        needWake = enqueueInboundEventLocked(std::move(newEntry));
        mLock.unlock();
    } // release lock

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

InputDisptcher 收到按键事件后,创建 KeyEvent 包装按键事件数据,先交给策略处理,看看其是否要截断。如果策略截断了,会在 policyFlags 中添加 POLICY_FLAG_PASS_TO_USER 标志位,InputDispatcher 会在之后的分发事件流程中,丢弃这个按键事件。截断策略是一个大课题,后面会专用一篇文章详细分析。

然后,创建 KeyEntry 包装按键事件数据,并保存到 InputDispatcher 的 inbound queue 中,随后唤醒线程处理按键事件,如下


// 通过线程循环分发按键事件
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

    // ...
}


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();
        }

        // ...
    }

    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) {
        // ...
    }

    // ...

    switch (mPendingEvent->type) {
        // ...

        case EventEntry::Type::KEY: {
            std::shared_ptr<KeyEntry> keyEntry = std::static_pointer_cast<KeyEntry>(mPendingEvent);
            
            // ...

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

        // ...
    }

    // ...
}


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

    // 策略要求稍后再分发按键事件
    if (entry->interceptKeyResult == KeyEntry::InterceptKeyResult::TRY_AGAIN_LATER) {
        if (currentTime < entry->interceptKeyWakeupTime) {
            if (entry->interceptKeyWakeupTime < *nextWakeupTime) {
                *nextWakeupTime = entry->interceptKeyWakeupTime;
            }
            return false; // wait until next wakeup
        }
        entry->interceptKeyResult = KeyEntry::InterceptKeyResult::UNKNOWN;
        entry->interceptKeyWakeupTime = 0;
    }
    
    
    if (entry->interceptKeyResult == KeyEntry::InterceptKeyResult::UNKNOWN) {
        if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { // 策略不截断按键事件
            sp<IBinder> focusedWindowToken =
                    mFocusResolver.getFocusedWindowToken(getTargetDisplayId(*entry));

            // 1. 通过一个命令,询问策略如何分发
            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) {
        if (*dropReason == DropReason::NOT_DROPPED) {
            // 丢弃的原因是策略要求丢弃
            *dropReason = DropReason::POLICY;
        }
    }

    // 如果有丢弃的原因,那么事件不再分发
    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;

    // 2. 寻找焦点窗口
    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;

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

    // global monitor 也需要创建 InputTarget,并加入到 inputTargets
    addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(*entry));

    // 4. 把按键事件分发给每一个 InputTarget
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}

InputDispatcher 通过一个线程循环,从 inbound queue 中取出一个按键事件,首先询问策略该如何分发。这个分发策略主要是为了实现组合按键的功能,例如,电源键 + 音量下键的组合键,可以实现截图。后面我将一篇文章详细分析分发策略如何实现组合按键功能,这里我们假设分发的按键事件,不属于任何一个组合键功能,因此策略会 InputDispatcher 继续后面的分发流程。

既然策略允许继续分发按键事件,那么需要为按键事件寻找一个焦点窗口,如下

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 获取焦点窗口 token
    // 从数据结构 mFocusedWindowTokenByDisplay,根据 display id 获取焦点窗口 token
    sp<IBinder> focusedToken = mFocusResolver.getFocusedWindowToken(displayId);

    // 根据焦点窗口 token 获取焦点窗口
    return getWindowHandleLocked(focusedToken, displayId);
}

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

    // 根据屏幕下所有窗口的 token,匹配出焦点窗口
    for (const sp<WindowInfoHandle>& windowHandle : getWindowHandlesLocked(displayId)) {
        if (windowHandle->getToken() == windowHandleToken) {
            return windowHandle;
        }
    }
    return nullptr;
}

焦点窗口,涉及 WMS,SurfaceFlinger 模块的知识,读者可以参考我写的 WMS 焦点窗口的文章,这里不详细讲解焦点窗口到底怎么来的。

当找到焦点窗口后,会给焦点窗口创建 InputTarget,并保存到集合 inputTargets 中,这个过程就不分析了。然后把按键事件分发给所有的 InputTargets ,如下

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

    for (const InputTarget& inputTarget : inputTargets) {

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

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

Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {
    // ...

    std::unique_ptr<InputChannel> serverChannel;
    std::unique_ptr<InputChannel> clientChannel;
    // 创建 socketpair,两端分别保存到 serverChannel 和 clientChannel
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

    // ...

    { // acquire lock
        std::scoped_lock _l(mLock);
        const sp<IBinder>& token = serverChannel->getConnectionToken();
        int fd = serverChannel->getFd();
        
        // 为 socketpair 的服务端窗口 Connection
        std::shared_ptr<Connection> connection =
                std::make_shared<Connection>(std::move(serverChannel), /*monitor=*/false,
                                             mIdGenerator);

        // ...
        
        // mConnectionsByToken 根据 input channel token 保存 Connection
        mConnectionsByToken.emplace(token, connection);

        std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
                                                            this, std::placeholders::_1, token);
        // 利用 Looper 机制,监听 socketpair 服务端 fd
        // 当窗口处理完事件,通过 socketpair 的 client 端反馈处理结果,socketpair 的服务端会收到数据
        // 然后会回调 InputDispatcher::handleReceiveCallback()
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback),
                       nullptr);
    } // release lock

    // Wake the looper because some connections have changed.
    mLooper->wake();
    
    // socketpair 的 client 端,返回给上层窗口
    return clientChannel;
}

因此,这里可以根据窗口的 input channel token 获取到 Connection。然后,通过这个 Connection,把按键事件分发给窗口,如下

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
                                                 const std::shared_ptr<Connection>& connection,
                                                 std::shared_ptr<EventEntry> eventEntry,
                                                const InputTarget& inputTarget) {
    // trace
    if (ATRACE_ENABLED()) {
        std::string message =
                StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, id=0x%" PRIx32 ")",
                             connection->getInputChannelName().c_str(), eventEntry->id);
        ATRACE_NAME(message.c_str());
    }
    
    // ALOG
    if (DEBUG_DISPATCH_CYCLE) {
        ALOGD("channel '%s' ~ prepareDispatchCycle - flags=%s, "
              "globalScaleFactor=%f, pointerIds=%s %s",
              connection->getInputChannelName().c_str(), inputTarget.flags.string().c_str(),
              inputTarget.globalScaleFactor, bitsetToString(inputTarget.pointerIds).c_str(),
              inputTarget.getPointerInfoString().c_str());
    }
    
    // ...

    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) {
    // trace
    if (ATRACE_ENABLED()) {
        std::string message =
                StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, id=0x%" PRIx32 ")",
                             connection->getInputChannelName().c_str(), eventEntry->id);
        ATRACE_NAME(message.c_str());
    }
    
    // ...

    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 the outbound queue was previously empty, start the dispatch cycle going.
    if (wasEmpty && !connection->outboundQueue.empty()) {
        // 开启分发循环
        startDispatchCycleLocked(currentTime, connection);
    }
}

在开启分发循环之前,首先对分发循环进行准备,主要是为了 DispatchEntry,并保存到 Connection::outboundQueue 中,如下

void InputDispatcher::enqueueDispatchEntryLocked(const std::shared_ptr<Connection>& connection,
                                                 std::shared_ptr<EventEntry> eventEntry,
                                                 const InputTarget& inputTarget,
                                                 ftl::Flags<InputTarget::Flags> dispatchMode) {
    // trace
    if (ATRACE_ENABLED()) {
        std::string message = StringPrintf("enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)",
                                           connection->getInputChannelName().c_str(),
                                           dispatchMode.string().c_str());
        ATRACE_NAME(message.c_str());
    }
    
    // 按键事件的 InputTarget::Flags 为 InputTarget::Flags::FOREGROUND | InputTarget::Flags::DISPATCH_AS_IS
    ftl::Flags<InputTarget::Flags> inputTargetFlags = inputTarget.flags;
    
    // 检测按键事件的 InputTarget::Flags 是否包含 dispatchMode
    if (!inputTargetFlags.any(dispatchMode)) {
        return;
    }

    // inputTargetFlags 清理 DISPATCH_MASK,仅保存 dispatchMode
    inputTargetFlags.clear(InputTarget::DISPATCH_MASK);
    inputTargetFlags |= dispatchMode;

    // 创建 DispatchEntry,之后会保存到 Connection::outboundQueue 中
    std::unique_ptr<DispatchEntry> dispatchEntry =
            createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);


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

            // ...
            break;
        }

        // ...
    }

    // Remember that we are waiting for this dispatch to complete.
    // 检测事件的 InputTargets::Flags 中是否包含 InputTarget::Flags::FOREGROUND
    // 按键事件恰好就满足
    if (dispatchEntry->hasForegroundTarget()) {
        // DispatchEntry::injectionState->pendingForegroundDispatches + 1
        incrementPendingForegroundDispatches(newEntry);
    }

    // Enqueue the dispatch entry.
    // 创建的 DispatchEntry 保存到 Connection::outboundQueue
    connection->outboundQueue.push_back(dispatchEntry.release());
    
    // trace 记录 Connection 的 outbound queue length
    traceOutboundQueueLength(*connection);
}

Connection 的 outbound queue 中已经保存了要分发的事件,现在正式开启分发循环,把 outbound queue 中的事件分发给窗口,如下

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 的 outbound queue 中的按键事件,分发给窗口,如下

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) {
    // trace 记录了输入系统发送给窗口的 key event 数据
    if (ATRACE_ENABLED()) {
        std::string message =
                StringPrintf("publishKeyEvent(inputChannel=%s, action=%s, keyCode=%s)",
                             mChannel->getName().c_str(), KeyEvent::actionToString(action),
                             KeyEvent::getLabel(keyCode));
        ATRACE_NAME(message.c_str());
    }

    // log 也可以记录发送给窗口的 key evnet 数据
    ALOGD_IF(debugTransportPublisher(),
             "channel '%s' publisher ~ %s: seq=%u, id=%d, deviceId=%d, source=%s, "
             "action=%s, flags=0x%x, keyCode=%s, scanCode=%d, metaState=0x%x, repeatCount=%d,"
             "downTime=%" PRId64 ", eventTime=%" PRId64,
             mChannel->getName().c_str(), __func__, seq, eventId, deviceId,
             inputEventSourceToString(source).c_str(), KeyEvent::actionToString(action), flags,
             KeyEvent::getLabel(keyCode), scanCode, metaState, repeatCount, downTime, eventTime);

    if (!seq) {
        ALOGE("Attempted to publish a key event with sequence number 0.");
        return BAD_VALUE;
    }

    InputMessage msg;
    msg.header.type = InputMessage::Type::KEY;
    msg.header.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);
}

然后用 wait queue 保存已经分发的按键事件,是为了等待窗口返回按键事件的处理结果。这就是一个循环!

在创建 input channel 时,把 socketpair 的 client 发送给窗口,而 InputDispatcher 利用 Looper 机制(实际利用 epoll)监听 socketpair 的 server 端,如下

Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(const std::string& name) {
    // ...

    std::unique_ptr<InputChannel> serverChannel;
    std::unique_ptr<InputChannel> clientChannel;
    // 创建 socketpair,两端分别保存到 serverChannel 和 clientChannel
    status_t result = InputChannel::openInputChannelPair(name, serverChannel, clientChannel);

    // ...

    { // acquire lock
        std::scoped_lock _l(mLock);
        const sp<IBinder>& token = serverChannel->getConnectionToken();
        int fd = serverChannel->getFd();
        
        // 为 socketpair 的服务端窗口 Connection
        std::shared_ptr<Connection> connection =
                std::make_shared<Connection>(std::move(serverChannel), /*monitor=*/false,
                                             mIdGenerator);

        // ...
        
        // mConnectionsByToken 根据 input channel token 保存 Connection
        mConnectionsByToken.emplace(token, connection);

        std::function<int(int events)> callback = std::bind(&InputDispatcher::handleReceiveCallback,
                                                            this, std::placeholders::_1, token);
        // 利用 Looper 机制,监听 socketpair 服务端 fd
        // 当窗口处理完事件,通过 socketpair 的 client 端反馈处理结果,socketpair 的服务端会收到数据
        // 然后会回调 InputDispatcher::handleReceiveCallback()
        mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, sp<LooperEventCallback>::make(callback),
                       nullptr);
    } // release lock

    // Wake the looper because some connections have changed.
    mLooper->wake();
    
    // socketpair 的 client 端,返回给上层窗口
    return clientChannel;
}

当窗口反馈事件的处理结果时,会执行如下回调

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();
                    
            // 4.返回的结果不 OK,代表有错误码,例如,数据已经读完,没有数据可以读了
            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();
            
            // 5. 数据已经读完,直接返回1
            if (status == WOULD_BLOCK) {
                return 1;
            }
        }

        // ...
    } else {
        
    }

    // ...
}

可能很多人有疑问,为何要通过一个无线循环读取窗口反馈的结果? 因为这就是 socketpair 的特性,需要不断的读取所有数据,直到没有数据为止,我们才知道数据读完了,如下

// frameworks/native/libs/input/InputTransport.cpp

android::base::Result<InputPublisher::ConsumerResponse> InputPublisher::receiveConsumerResponse() {
    InputMessage msg;
    // 通过一个无线循环,不断从 socketpair 的 servier 端读取数据
    status_t result = mChannel->receiveMessage(&msg);

    // 有错误码,直接返回
    if (result) {
        ALOGD_IF(debugTransportPublisher(), "channel '%s' publisher ~ %s: %s",
                 mChannel->getName().c_str(), __func__, strerror(result));
        return android::base::Error(result);
    }

    // 走到这里,代表读到正常的数据

    if (msg.header.type == InputMessage::Type::FINISHED) {
        ALOGD_IF(debugTransportPublisher(),
                 "channel '%s' publisher ~ %s: finished: seq=%u, handled=%s",
                 mChannel->getName().c_str(), __func__, msg.header.seq,
                 toString(msg.body.finished.handled));
        return Finished{
                .seq = msg.header.seq,
                .handled = msg.body.finished.handled,
                .consumeTime = msg.body.finished.consumeTime,
        };
    }

    // TODO: 这是什么数据?
    if (msg.header.type == InputMessage::Type::TIMELINE) {
        ALOGD_IF(debugTransportPublisher(), "channel '%s' publisher ~ %s: timeline: id=%d",
                 mChannel->getName().c_str(), __func__, msg.body.timeline.eventId);
        return Timeline{
                .inputEventId = msg.body.timeline.eventId,
                .graphicsTimeline = msg.body.timeline.graphicsTimeline,
        };
    }

    // 这里表示,读取的不是期望的数据,代表未知异常,表示窗口反馈的数据格式有问题
    ALOGE("channel '%s' publisher ~ Received unexpected %s message from consumer",
          mChannel->getName().c_str(), ftl::enum_string(msg.header.type).c_str());
    return android::base::Error(UNKNOWN_ERROR);
}


status_t InputChannel::receiveMessage(InputMessage* msg) {
    ssize_t nRead;
    
    // 从 socketpair 中读取 InputMessage 大小的数据
    do {
        nRead = ::recv(getFd(), msg, sizeof(InputMessage), MSG_DONTWAIT);
    } while (nRead == -1 && errno == EINTR);

    
    // 没有从 socketpair 读取到数据
    if (nRead < 0) {
        int error = errno;
        ALOGD_IF(DEBUG_CHANNEL_MESSAGES, "channel '%s' ~ receive message failed, errno=%d",
                 mName.c_str(), errno);
                 
        // 表示没有数据可读
        if (error == EAGAIN || error == EWOULDBLOCK) {
            return WOULD_BLOCK;
        }
        
        // EPIPE 管道异常,ENOTCONN 代表 socket 未连接,ECONNREFUSED 代表连接被拒绝
        if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED) {
            return DEAD_OBJECT;
        }
        return -error;
    }

    // 代表 client 端关闭了
    if (nRead == 0) { // check for EOF
        ALOGD_IF(DEBUG_CHANNEL_MESSAGES,
                 "channel '%s' ~ receive message failed because peer was closed", mName.c_str());
        return DEAD_OBJECT;
    }

    if (!msg->isValid(nRead)) {
        ALOGE("channel '%s' ~ received invalid message of size %zd", mName.c_str(), nRead);
        return BAD_VALUE;
    }

    ALOGD_IF(DEBUG_CHANNEL_MESSAGES, "channel '%s' ~ received message of type %s", mName.c_str(),
             ftl::enum_string(msg->header.type).c_str());
    return OK;
}

当成功读取到窗口返回的数据后,就要结束此次分发循环,如下

void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime,
                                                const std::shared_ptr<Connection>& connection,
                                                uint32_t seq, bool handled, nsecs_t consumeTime) {
    
    // 结束分发循环的 log
    if (DEBUG_DISPATCH_CYCLE) {
        ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s",
              connection->getInputChannelName().c_str(), seq, toString(handled));
    }

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

结束分发循环只是创建一个命令并保存到集合中,然后执行第3步,执行命令,如下

bool InputDispatcher::runCommandsLockedInterruptable() {
    if (mCommandQueue.empty()) {
        return false;
    }

    do {
    
        // 从 mCommandQueue 取出命令,并执行
        auto command = std::move(mCommandQueue.front());
        mCommandQueue.pop_front();
        // Commands are run with the lock held, but may release and re-acquire the lock from within.
        command();
    } while (!mCommandQueue.empty());
    return true;
}

结束分发循环的命令,主要就是从 Connection 的 wait queue 中移除按键事件,如下


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

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

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

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

        // ...
    }

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

自此,Connection 的按键事件分发循环就成功结束了,也代表 InputDispatcher 一次按键事件的分发完成。