InputDispatcher线程分发事件-Android12

Posted xhBruce

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了InputDispatcher线程分发事件-Android12相关的知识,希望对你有一定的参考价值。

InputDispatcher线程分发事件-android12

android12-release


1. 唤醒InputDispatcher中InputThread

1.1 例如notifyKey通知唤醒InputDispatcher时将事件添加到mInboundQueue

  • KeyEvent event 初始化KeyEvent对象
  • mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags)最终调用到PhoneWindowManger.interceptKeyBeforeQueueing方法是否拦截;mPolicy是com_android_server_input_InputManagerService.cpp中NativeInputManager
  • mPolicy->filterInputEvent是否开启辅助服务拦截
  • std::unique_ptr<KeyEntry> newEntry 初始化KeyEntry对象
  • enqueueInboundEventLocked()KeyEntry加入到mInboundQueue
  • mLooper->wake() 唤醒InputDispatcher中mThread执行dispatchOnce()
void InputDispatcher::notifyKey(const NotifyKeyArgs* args) 
    // ... ...
    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;
     // 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);

        needWake = enqueueInboundEventLocked(std::move(newEntry));
        mLock.unlock();
     // release lock

    if (needWake) 
        mLooper->wake();
    

2. 开始执行分发dispatchOnce()

  • haveCommandsLocked() 当mCommandQueue不为空时分发dispatchOnceInnerLocked(&nextWakeupTime)
  • runCommandsLockedInterruptible() 处理mCommandQueue中命令CommandEntry
  • mLooper->pollOnce(timeoutMillis)进入epoll_wait等待状态
void InputDispatcher::dispatchOnce() 
    nsecs_t nextWakeupTime = LONG_LONG_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);
        

        // Run all pending commands if there are any.
        // If any commands were run then force the next poll to wake up immediately.
        if (runCommandsLockedInterruptible()) 
            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();
        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();
        
     // 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);

2.1 dispatchOnceInnerLocked(&nextWakeupTime)

  • currentTime = now()开始发送事件,计算ANR超时
  • mPendingEvent将要分发的事件,为空就取出mInboundQueue中EventEntry;若挂起事件mInboundQueue也没有退出不处理
  • 例如EventEntry::Type::KEY类型分发done = dispatchKeyLocked()
  • 分发操作完成,releasePendingEventLocked()释放mPendingEvent,并强制在此唤醒*nextWakeupTime = LONG_LONG_MIN; ,立刻执行轮询
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) 
    nsecs_t currentTime = now();
    // ... ...
    if (!mPendingEvent) 
        if (mInboundQueue.empty()) 
            // ... ...
            // Nothing to do if there is no pending event.
            if (!mPendingEvent) 
                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) 
            pokeUserActivityLocked(*mPendingEvent);
        
    
    // ... ...
    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;
        
        // ... ...
    

    if (done) 
        if (dropReason != DropReason::NOT_DROPPED) 
            dropInboundEventLocked(*mPendingEvent, dropReason);
        
        mLastDropReason = dropReason;

        releasePendingEventLocked();
        *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately
    

2.2 dispatchKeyLocked()分发KeyEvent事件

  • currentTime < entry->interceptKeyWakeupTime当前事件小于唤醒时间不分发,返回false
  • postCommandLocked(std::move(commandEntry))执行命令CommandEntry doInterceptKeyBeforeDispatchingLockedInterruptible,policy分发前拦截事件的情况mPolicy->interceptKeyBeforeDispatching,最终调用到PhoneWindowManger.interceptKeyBeforeDispatching方法,并返回false
  • findFocusedWindowTargetsLocked寻找焦点窗口
  • dispatchEventLocked()继续
bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry,
                                        DropReason* dropReason, nsecs_t* nextWakeupTime) 
    // ... ...
    // Handle case where the policy asked us to try again later last time.
    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;
        entry->interceptKeyWakeupTime = 0;
    

    // Give the policy a chance to intercept the key.
    if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) 
        if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) 
            std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
                    &InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
            sp<IBinder> focusedWindowToken =
                    mFocusResolver.getFocusedWindowToken(getTargetDisplayId(*entry));
            commandEntry->connectionToken = focusedWindowToken;
            commandEntry->keyEntry = entry;
            postCommandLocked(std::move(commandEntry));
            return false; // wait for the command to run
         else 
            entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
        
     else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) 
        if (*dropReason == DropReason::NOT_DROPPED) 
            *dropReason = DropReason::POLICY;
        
    
    // ... ...
    InputEventInjectionResult injectionResult =
            findFocusedWindowTargetsLocked(currentTime, *entry, inputTargets, nextWakeupTime);
    if (injectionResult == InputEventInjectionResult::PENDING) 
        return false;
    
    // ... ...
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;

2.3 继续dispatchEventLocked()

  • 找到目标connection继续prepareDispatchCycleLocked(currentTime, connection, eventEntry, inputTarget)
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
                                          std::shared_ptr<EventEntry> eventEntry,
                                          const std::vector<InputTarget>& inputTargets) 
    //... ...
    pokeUserActivityLocked(*eventEntry);

    for (const InputTarget& inputTarget : inputTargets) 
        sp<Connection> connection =
                getConnectionLocked(inputTarget.inputChannel->getConnectionToken());
        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());
            
        
    

2.4 继续prepareDispatchCycleLocked()

  • connection->status != Connection::STATUS_NORMAL当连接connection破坏丢弃事件
  • 继续enqueueDispatchEntriesLocked
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
                                                 const sp<Connection>& connection,
                                                 std::shared_ptr<EventEntry> eventEntry,
                                                 const InputTarget& inputTarget) 
    // ... ...
    // 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) 
#if DEBUG_DISPATCH_CYCLE
        ALOGD("channel '%s' ~ Dropping event because the channel status is %s",
              connection->getInputChannelName().c_str(), connection->getStatusLabel());
#endif
        return;
    
    //... ...
    // Not splitting.  Enqueue dispatch entries for the event as is.
    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);

2.5 继续enqueueDispatchEntriesLocked()

  • enqueueDispatchEntryLocked()根据dispatchMode来决定是否需要将dispatchEntry加入outboundQueue队列
  • 当原先的outbound队列为空, 且当前outbound不为空的情况执行startDispatchCycleLocked()
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
                                                   const sp<Connection>& connection,
                                                   std::shared_ptr<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();

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

2.5 继续startDispatchCycleLocked()

  • 当Connection状态正常,且outboundQueue不为空,发送connection->inputPublisher.publishKeyEvent(),InputChannel通过socket向远端的socket发送消息。
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 std::chrono::nanoseconds timeout =
                getDispatchingTimeoutLocked(connection->inputChannel->getConnectionToken());
        dispatchEntry->timeoutTime = currentTime + timeout.count();

        // Publish the event.
        status_t status;
        const EventEntry& eventEntry = *(dispatchEntry->eventEntry);
        switch (eventEntry.type) 
            case EventEntry::Type::KEY: 
                const KeyEntry& keyEntry = static_cast<const KeyEntry&>(eventEntry);
                std::array<uint8_t, 32> hmac = getSignature(keyEntry, *dispatchEntry);

                // Publish the key event.
                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. InputPublisher::publishKeyEvent

IMS:InputDispatcher线程分发事件

  • InputDispatcher经过InputChannel通过socket向远端的socket发送消息给Window
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 (ATRACE_ENABLED()) 
        std::string message = StringPrintf("publishKeyEvent(inputChannel=%s, keyCode=%" PRId32 ")",
                mChannel->getName().c_str(), keyCode);
        ATRACE_NAME(message.c_str());
    
    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()以上是关于InputDispatcher线程分发事件-Android12的主要内容,如果未能解决你的问题,请参考以下文章

IMS:InputDispatcher的焦点设置

IMS:InputManagerService小结

IMS:Input事件可拦截位置

InputManagerService实体按键及组合按键-Android12

InputManagerService实体按键及组合按键-Android12

InputManagerService实体按键及组合按键-Android12