InputDispatcher分发事件

InputDispatcher分发事件

我知道在Input系统初始化时InputManager会调用InputDispatcher的start方法,我们从这个方法入手开始分析分发逻辑

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

void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
        //将事件加入mInboundQueue
        needWake = enqueueInboundEventLocked(newEntry);
    //唤起dispatchOnce
    if (needWake) {
        mLooper->wake();
    }
}

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    {
        if (!haveCommandsLocked()) {
            dispatchOnceInnerLocked(&nextWakeupTime);
        }

        if (runCommandsLockedInterruptible()) {
            nextWakeupTime = LONG_LONG_MIN;
        }
}

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    nsecs_t currentTime = now();
    //从mInboundQueue队列中取出一个事件
    mPendingEvent = mInboundQueue.front();

    switch (mPendingEvent->type) {
        ...
        case EventEntry::Type::KEY: {
            KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
            ...
            //Key事件调用dispatchKeyLocked
            done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
            break;
        }
        case EventEntry::Type::MOTION: {
            MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
            ...
            //Motion事件调用dispatchMotionLocked
            done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
            break;
        }
    }
    ...
    }
}

在start方法中开启一个InputDispatcher的线程执行dispatchOnce这个方法,在InputReader调用到InputDispatcher的notifyKey方法除了入队事件,还会唤醒线程,线程只要mLooper->wake触发就会执行这个方法,dispatchOnce方法从mInboundQueue取出一个事件,然后调用dispatchOnceInnerLocked,不同类型调用的方法不一样,比如

  • Key事件调用dispatchKeyLocked
  • Motion事件调用dispatchMotionLocked

但大致逻辑是一样的,这里我们看Key的处理流程

bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
                                        DropReason* dropReason, nsecs_t* nextWakeupTime) {

    ...
    std::vector<InputTarget> inputTargets;
   //找到当前处在focus状态的Window窗口,并将其加入到inputTargets中
    int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
            entry, inputTargets, nextWakeupTime);
    //找到需要监听全局按键的InputChannel,封装成InputTarget,加入到inputTargets中 
    addMonitoringTargetsLocked(inputTargets);
 
    //将按键分发到上面inputTargets的InputChannel中
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,
                                          const std::vector<InputTarget>& inputTargets) {
    //遍历InputTarget,获取connection
    for (const InputTarget& inputTarget : inputTargets) {
        //从mConnectionsByFd中获取
        sp<Connection> connection =
                getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
        if (connection != nullptr) {
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget);
        } 
        }
    }
}

这里涉及系统中对于按键事件的策略逻辑:简单来说就是当前获取焦点的Window接收到事件,方法findFocusedWindowTargetsLocked,而触摸事件就不太一样,会根据当前触摸的位置,判断触碰点是否在目标Window内,然后根据Z进行排序,方法findTouchedWindowTargetsLocked,这些find的目标信息都会保存在inputTargets内。然后调到dispatchEventLocked方法,这里会依次取出inputTargets中的InputTarget,根据InputTarget的InputChannel找到保存在mConnectionByFd中的Connection对象,调用prepareDispatchCycleLocked函数进行分发

void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
                                                 const sp<Connection>& connection,
                                                 EventEntry* eventEntry,
                                                 const InputTarget& inputTarget) {
    //各种检查
    //调用enqueueDispatchEntriesLocked排队
    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);
}

void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
                                                   const sp<Connection>& connection,
                                                   EventEntry* eventEntry,
                                                   const InputTarget& inputTarget) {

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

    // 将不同调度模式的event事件排队
    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);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                               InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
                               InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);

    // If the outbound queue was previously empty, start the dispatch cycle going.
    if (wasEmpty && !connection->outboundQueue.empty()) {
        startDispatchCycleLocked(currentTime, connection);
    }
}

void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
                                                 EventEntry* eventEntry,
                                                 const InputTarget& inputTarget,
                                                 int32_t dispatchMode) {
    //生成dispatchEntry
    std::unique_ptr<DispatchEntry> dispatchEntry =
            createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);
    // 加入connection的outboundQueue队列里
    connection->outboundQueue.push_back(dispatchEntry.release());
    traceOutboundQueueLength(connection);
}

这个函数首先获取以前的connection的outboundQueue是否为空,然后调用enqueueDispatchEntryLocked将事件加入到outboundQueue中。

如果队列以前为空,现在不为空,则调用startDispatchCycleLocked开始分发。
如果以前不为空,说明当前的Activity正在处理前面的按键,则不需要再调用startDispatchCycleLocked。
这里 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();
        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);

                // 发布按键事件
                status =
                        connection->inputPublisher
                                .publishKeyEvent(dispatchEntry->seq, dispatchEntry->resolvedEventId,
                                                 keyEntry->deviceId, keyEntry->source,
                                                 ...
                                                 keyEntry->eventTime);
                break;
            }

            case EventEntry::Type::MOTION: {
                MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);

                // 发布触摸事件
                status = connection->inputPublisher
                                 .publishMotionEvent(dispatchEntry->seq,
                                                     dispatchEntry->resolvedEventId,
                                                     motionEntry->deviceId, motionEntry->source,
                                                     ...
                                                     motionEntry->pointerProperties, usingCoords);
                reportTouchEventForStatistics(*motionEntry);
                break;
            }
        }

        //从outboundQueue移除已经发布的事件,加入waitQueue中
        connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
                                                    connection->outboundQueue.end(),
                                                    dispatchEntry));
        connection->waitQueue.push_back(dispatchEntry);
    }
}

从outboundQueue中取出需要处理的事件,交给connection的inputPublisher去分发,将事件加入到connection的waitQueue中。这里分发事件是通过InputPublisher的publishKeyEvent/publishMotionEvent来完成

status_t InputPublisher::publishKeyEvent() {

    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;
    ...
    return mChannel->sendMessage(&msg);
}

这里的mChannel就是InputChannel对象,代码在:
native/libs/input/InputTransport.cpp

InputChannel::InputChannel(const std::string& name, android::base::unique_fd fd, sp<IBinder> token)
      : mName(name), mFd(std::move(fd)), mToken(token) {
}

status_t InputChannel::sendMessage(const InputMessage* msg) {
    const size_t msgLength = msg->size();
    InputMessage cleanMsg;
    msg->getSanitizedCopy(&cleanMsg);
    ssize_t nWrite;
    do {
        nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
    } while (nWrite == -1 && errno == EINTR);
    return OK;
}

InputDispatcher是运行在system_process上,而APP是运行在各自APP的进程上的,通信的桥梁就是InputChannel,内部保存两个socket,server_socket和client_socket,这里通过send函数往socket的server端写入InputMessage对象,应用程序正睡眠在client端的fd上,此时client端就会收到该InputMessage,client被唤醒后会进行按键事件的分发。最后dispatcher线程通过connection对象和APP之间建立连接。因为使用的是socket,所以能实现了Input事件的跨进程通信。

还记得上面说过已经发布的事件会移到connection->waitQueue中去,其实这边也是一个很重要的对已分发事件的处理逻辑,我们知道事件分发的socket是异步通信,InputDispatcher线程将Input事件发送之后就直接返回了,对于APP端具体执行结果其实是不知道的,待APP端事件处理完之后是会反馈给InputDispatcher的,入口就是handleReceiveCallback方法

int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
    InputDispatcher* d = static_cast<InputDispatcher*>(data);

    { 
            sp<Connection> connection = d->mConnectionsByFd[fd];
            for (;;) {
                uint32_t seq;
                bool handled;
                //接收窗口处理完成的消息
                status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
                if (status) {
                    break;
                } 
                // 这里post一个command,其实就是调用doDispatchCycleFinishedLockedInterruptible方法
                d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
                gotOne = true;
            }
            if (gotOne) {
                //执行command
                d->runCommandsLockedInterruptible();
                if (status == WOULD_BLOCK) {
                    return 1;
                }
            }
}

void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) {
    sp<Connection> connection = commandEntry->connection;

    dispatchEntryIt = connection->findWaitQueueEntry(seq);
    // 从waitQueue中将当前entry移除
    if (dispatchEntryIt != connection->waitQueue.end()) {
        dispatchEntry = *dispatchEntryIt;
        connection->waitQueue.erase(dispatchEntryIt);
    }

    //如果当前connection的outBoundQueque里还有Event,则继续下一轮的Dispatch周期
    startDispatchCycleLocked(now(), connection);
}

APP侧处理完事件之后,会发送一个反馈信息给到InputDispatcher,InputDispatcher的handleReceiveCallback方法接收到这个反馈,通过一个CommandEntry将事件从waitQueue中移除

在这里插入图片描述

简单总结下InputDispatcher分发事件流程:

  1. InputReader唤醒InputDispacher执行分发处理。
    InputReader主要是将EventHub中的input_event转换成具体的EventEntry,并添加到InputDispatcher的mInboundQueue里,然后唤醒InputDispacher线程。InputDispacher线程有自己的Looper,被唤醒后会执行dispatchOnce方法,InputDispatcher处理的事件主要分两种:一种是command命令(Command是mPolicy处理的具体事务,这个mPolicy就是NativeInputManager,最终对应的上层是InputManagerService),一种是input event。每次dispatchOnce,会优先执行前者。

  2. InboundQueue队头取出事件,匹配焦点窗口,传递eventEntry。
    从mInboundQueue队列头部取出一个事件,寻找与之匹配的焦点窗口的inputTargets,这里先通过InputWindowHandle找到InputWindowInfo,再找到InputChannel,最终找到Connection,每个焦点窗口在InputDispacher里都有一个对应的Connection,通过这个Connection可以跟InputDispacher通信。然后会将eventEntry转为DispatchEntry放入Connection的outboundQueue。通过InputPublisher通过 InputChannel::sendMessage将DispatchEntry发送给窗口,再将dispatchEntry从outboundQueue移到waitQueue里。该通信过程是异步的,也就是说当InputDispatcher将Input事件发送给目标窗口后会立即返回,并不会等待窗口的处理结果。

  3. 窗口处理完又将处理结果返回给InputDispatcher
    当窗口处理完事件后,会通过handleReceiveCallback()回调函数通知InputDispatcher。回调主要是post一个command,从waitQueue中将当前DispatchEntry移除,如果当前connection的outBoundQueque里还有DispatchEntry,则继续下一轮的Dispatch周期。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值