Android Input(四) -InputDispatcher分發(fā)事件

原創(chuàng)內(nèi)容,轉(zhuǎn)載請注明出處,多謝配合。

上一篇分析了InputReader獲取事件過程,最終InputReader將input event放到InputDispatcher的mInboundQueue后喚醒InputDispacher。本篇就來分析下InputDispatcher的事件分發(fā)過程。

一、InputDispatcher初始化
frameworks/native/services/inputflinger/InputManager.cpp

InputManager::InputManager(
       const sp<EventHubInterface>& eventHub,
       const sp<InputReaderPolicyInterface>& readerPolicy,
       const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
   mDispatcher = new InputDispatcher(dispatcherPolicy);//創(chuàng)建InputDispatcher
...
}

frameworks/native/services/inputflinger/InputDispatcher.cpp

InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) ...  : {
   mLooper = new Looper(false);//這里InputDispatcher新建了一個Looper
   ...
}

InputDispatcherThread::InputDispatcherThread(const sp<InputDispatcherInterface>& dispatcher) :
       Thread(/*canCallJava*/ true), mDispatcher(dispatcher) {
}

bool InputDispatcherThread::threadLoop() {
   mDispatcher->dispatchOnce();//開始處理分發(fā)
   return true;
}
二、InputDispatcher運行
frameworks/native/services/inputflinger/InputDispatcher.cpp

void InputDispatcher::dispatchOnce() {
   nsecs_t nextWakeupTime = LONG_LONG_MAX;register_android_server_InputManager
   ...
       //優(yōu)先處理Command
       if (!haveCommandsLocked()) {
           //這里處理input event
           dispatchOnceInnerLocked(&nextWakeupTime);
       }
       if (runCommandsLockedInterruptible()) {
           // 處理完Command,立即喚醒loop來處理input event
           nextWakeupTime = LONG_LONG_MIN;
       }    
   ...
   nsecs_t currentTime = now();
   int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
   // 這里進入epoll_wait,
   // InputReader可以用Looper::wake()喚醒InputDispacher
   // 窗口也可以通過回執(zhí)event喚醒Looper
   mLooper->pollOnce(timeoutMillis);
}

InputDispatcher處理的事件主要分兩種:一種是command命令(Command是mPolicy處理的具體事務(wù),這個mPolicy就是NativeInputManager,最終對應(yīng)的上層是InputManagerService),一種是input event。每次dispatchOnce,會優(yōu)先執(zhí)行前者。

這里Command一些列回調(diào)命令保存在mCommandQueue中,主要包括:
doPokeUserActivityLockedInterruptible
doNotifyANRLockedInterruptible
doInterceptKeyBeforeDispatchingLockedInterruptible
doDispatchCycleFinishedLockedInterruptible
doNotifyInputChannelBrokenLockedInterruptible
doNotifyConfigurationChangedInterruptible

再看dispatchOnceInnerLocked處理input event部分:

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    nsecs_t currentTime = now(); 
 ...
   //當(dāng)事件分發(fā)的時間點距離該事件加入mInboundQueue的時間超過500ms,則認為app切換過期,即  
//isAppSwitchDue=true;
   bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
  ...
           if (!mPendingEvent) {
                return;
            }
        } else {
           //事件是從InboundQueue頭部取的
           mPendingEvent = mInboundQueue.dequeueAtHead();
            traceInboundQueueLengthLocked();
        }
        // Poke user activity for this event.
       if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) {
            pokeUserActivityLocked(mPendingEvent);
        }
        // Get ready to dispatch the event.
       resetANRTimeoutsLocked(); //重置ANR 超時時間
    }
    // 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 != NULL);
    bool done = false;
    DropReason dropReason = DROP_REASON_NOT_DROPPED;
    if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
        dropReason = DROP_REASON_POLICY;
    } else if (!mDispatchEnabled) {
        dropReason = DROP_REASON_DISABLED;
    }
    if (mNextUnblockedEvent == mPendingEvent) {
        mNextUnblockedEvent = NULL;
    }
    switch (mPendingEvent->type) {
    …
   //這里有很多類型的EventEntry type 重點看看key
    case EventEntry::TYPE_KEY: {
        KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
        if (isAppSwitchDue) {
            if (isAppSwitchKeyEventLocked(typedEntry)) {
                resetPendingAppSwitchLocked(true);
                isAppSwitchDue = false;
            } else if (dropReason == DROP_REASON_NOT_DROPPED) {
                dropReason = DROP_REASON_APP_SWITCH;
            }
        }
        if (dropReason == DROP_REASON_NOT_DROPPED
                && isStaleEventLocked(currentTime, typedEntry)) {
            dropReason = DROP_REASON_STALE;
        }

        if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {
            dropReason = DROP_REASON_BLOCKED;
        }

        //分發(fā)事件處理
        done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
        break;
    }
    ...
    }
    //分發(fā)操作完成
    if (done) {
        if (dropReason != DROP_REASON_NOT_DROPPED) {
            dropInboundEventLocked(mPendingEvent, dropReason);//丟棄事件
        }
        mLastDropReason = dropReason;
        releasePendingEventLocked();//釋放當(dāng)前正在處理的事件
        *nextWakeupTime = LONG_LONG_MIN;  // force next poll to wake up immediately
   }
}

這個過程簡單看就是從mInboundQueue頭部取出事件交給dispatchKeyLocked執(zhí)行分發(fā)處理,并重置ANR時間,以及執(zhí)行完之后根據(jù)done來做一些收尾操作。

接下來看看dispatchKeyLocked:

bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
        DropReason* dropReason, nsecs_t* nextWakeupTime) {
    ...
    //尋找焦點窗口inputTargets
    int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime,
            entry, inputTargets, nextWakeupTime);
    if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {
        return false;
    }
    setInjectionResultLocked(entry, injectionResult);
    if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {
        return true;
    }
    addMonitoringTargetsLocked(inputTargets);
    //只有injectionResult為true才會繼續(xù)往下執(zhí)行分發(fā)操作
   dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}

這個方法核心內(nèi)容是執(zhí)行findFocusedWindowTargetsLocked尋找焦點窗口inputTargets,但是在此之前會有若干判斷有可能直接return 。

int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
        const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
    int32_t injectionResult;
    String8 reason;
  ...
    // Check permissions.
   if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) {
        injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
        goto Failed;
    }
    // 檢測窗口是否為更多的輸入操作而準備就緒
   reason = checkWindowReadyForMoreInputLocked(currentTime,
            mFocusedWindowHandle, entry, "focused");
    if (!reason.isEmpty()) { //如果滿足,handleTargetsNotReadyLocked會觸發(fā)anr判斷
        injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());
        goto Unresponsive;
    }
    // Success!  Output targets.
   injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;
    //添加目標窗口
    addWindowTargetLocked(mFocusedWindowHandle,
            InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0),
            inputTargets);
    // Done.
Failed:
Unresponsive:
    nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
    updateDispatchStatisticsLocked(currentTime, entry,
            injectionResult, timeSpentWaitingForApplication);
#if DEBUG_FOCUS
    ALOGD("findFocusedWindow finished: injectionResult=%d, "
           "timeSpentWaitingForApplication=%0.1fms",
            injectionResult, timeSpentWaitingForApplication / 1000000.0);
#endif
   return injectionResult;
}

這里主要就是添加目標窗口,與目前窗口建立InputChannel連接

void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
        int32_t targetFlags, BitSet32 pointerIds, Vector<InputTarget>& inputTargets) {
    inputTargets.push();
    const InputWindowInfo* windowInfo = windowHandle->getInfo();
    InputTarget& target = inputTargets.editTop();
    target.inputChannel = windowInfo->inputChannel;
    target.flags = targetFlags;
    target.xOffset = - windowInfo->frameLeft;
    target.yOffset = - windowInfo->frameTop;
    target.scaleFactor = windowInfo->scaleFactor;
    target.pointerIds = pointerIds;
}

將當(dāng)前聚焦窗口mFocusedWindowHandle的inputChannel傳遞到inputTargets。

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
#if DEBUG_DISPATCH_CYCLE
    ALOGD("dispatchEventToCurrentInputTargets");
#endif
   ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true
   //調(diào)用到Java層的PowerManagerService.java中的userActivityFromNative()方法. 這也是PMS中唯一的native call方法
   pokeUserActivityLocked(eventEntry);
    for (size_t i = 0; i < inputTargets.size(); i++) {
        const InputTarget& inputTarget = inputTargets.itemAt(i);
       //根據(jù)inputChannel的fd從mConnectionsByFd隊列中查詢目標connection.
        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
        if (connectionIndex >= 0) {
            sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
            //找到目標連接
            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().string());
#endif
       }
    }
}

該方法主要功能是將eventEntry發(fā)送到目標inputTargets。

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

void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget) {
   bool wasEmpty = connection->outboundQueue.isEmpty();
   ...
   enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, InputTarget::FLAG_DISPATCH_AS_IS);
   ...
   if (wasEmpty && !connection->outboundQueue.isEmpty()) {
       startDispatchCycleLocked(currentTime, connection);
   }
}

void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,  int32_t dispatchMode) {
   int32_t inputTargetFlags = inputTarget->flags;
   if (!(inputTargetFlags & dispatchMode)) {
       return;
   }
   //這里又轉(zhuǎn)了一次數(shù)據(jù)結(jié)構(gòu),生成新的事件, 加入connection的outbound隊列。
   DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, inputTarget->scaleFactor);
   switch (eventEntry->type) {
   case EventEntry::TYPE_KEY: {
       KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
       dispatchEntry->resolvedAction = keyEntry->action;
       dispatchEntry->resolvedFlags = keyEntry->flags;
       break;
   }

   //添加到outboundQueue隊尾
   connection->outboundQueue.enqueueAtTail(dispatchEntry);
}

執(zhí)行到這里,其實等于由做了一次搬運的工作,將InputDispatcher中mInboundQueue中的eventEntry事件取出后, 找到目標window后,將eventEntry封裝dispatchEntry加入到connection的outbound隊列。

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection) {
   while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.isEmpty()) {
       DispatchEntry* dispatchEntry = connection->outboundQueue.head;
       dispatchEntry->deliveryTime = currentTime;
       // Publish the event.
       status_t status;
       EventEntry* eventEntry = dispatchEntry->eventEntry;
       switch (eventEntry->type) {
       case EventEntry::TYPE_KEY: {
           KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
           status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
                   keyEntry->deviceId, keyEntry->source,
                   dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
                   keyEntry->keyCode, keyEntry->scanCode,
                   keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
                   keyEntry->eventTime);
           break;
       }
       ...
       }
       // Re-enqueue the event on the wait queue.
       connection->outboundQueue.dequeue(dispatchEntry);
       connection->waitQueue.enqueueAtTail(dispatchEntry);
    }

通過InputPublisher將DispatchEntry發(fā)送給窗口,再將DispatchEntry從outboundQueue移到waitQueue里。該通信過程是異步的,當(dāng)窗口處理完事件后會通過handleReceiveCallback()回調(diào)函數(shù)通知InputDispatcher。

status_t InputPublisher::publishKeyEvent(...) {
   if (!seq) {
       return BAD_VALUE;
   }
   InputMessage msg;
   msg.header.type = InputMessage::TYPE_KEY;
   msg.body.key.seq = seq;
   msg.body.key.deviceId = deviceId;
   msg.body.key.source = source;
   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;
   //通過InputChannel來發(fā)送消息
   return mChannel->sendMessage(&msg);
}

publishKeyEvent調(diào)用InputChanel的SendMessage(),SendMessage()再動用socket的send()函數(shù),將打包好的Message發(fā)送給窗口。

最后看看handleReceiveCallback回調(diào):

frameworks/native/services/inputflinger/InputDispatcher.cpp
int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) {
    InputDispatcher* d = static_cast<InputDispatcher*>(data); 
    ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd); 
    sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);
    if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
        nsecs_t currentTime = now();
        bool gotOne = false;
        status_t status;
        for (;;) {
            uint32_t seq;
            bool handled;
            //接收窗口處理完成的消息
            status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled);
            if (status) { // 讀完socket即返回WOULD_BLOCK
                break;
            }
            // 這里post一個command
            d->finishDispatchCycleLocked(currentTime, connection, seq, handled);
            gotOne = true;
        }
        if (gotOne) {
            // 這里執(zhí)行command的handle
            d->runCommandsLockedInterruptible();
            if (status == WOULD_BLOCK) {  // 正常流程走這里
                return 1;
            }
        }
    }
    // 這里是socket鏈接出現(xiàn)異常的情況
    d->unregisterInputChannelLocked(connection->inputChannel, notify);
    return 0; // remove the callback
}

再看看post command

frameworks/native/services/inputflinger/InputDispatcher.cpp

void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {
   ...
   onDispatchCycleFinishedLocked(currentTime, connection, seq, handled);
}
void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime, const sp<Connection>& connection, uint32_t seq, bool handled) {
   CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
   commandEntry->connection = connection;
   commandEntry->eventTime = currentTime;
   commandEntry->seq = seq;
   commandEntry->handled = handled;
}

frameworks/native/services/inputflinger/InputDispatcher.cpp

void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) {
   sp<Connection> connection = commandEntry->connection;
   nsecs_t finishTime = commandEntry->eventTime;
   uint32_t seq = commandEntry->seq;
   bool handled = commandEntry->handled;
  // Handle post-event policy actions.
   DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);
   if (dispatchEntry) {
       nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
      // 如果一個dispatch周期超過2秒,將打印警告信息
       if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT /* 2sec */) {
           String8 msg;
           msg.appendFormat("Window '%s' spent %0.1fms processing the last input event: ", connection->getWindowName(), eventDuration * 0.000001f);
           dispatchEntry->eventEntry->appendDescription(msg);
           ALOGI("%s", msg.string());
       }
       bool restartEvent;
       if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
           KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
           // 主要是對unhandle key的policy,這里不做分析
           restartEvent = afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled);
       } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
           MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
           restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry, handled);
       } else {
           restartEvent = false;
       }
       if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
           // 從waitQueue中將當(dāng)前entry移除
           connection->waitQueue.dequeue(dispatchEntry);
           traceWaitQueueLengthLocked(connection);
           if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
               connection->outboundQueue.enqueueAtHead(dispatchEntry);
               traceOutboundQueueLengthLocked(connection);
           } else {
              // 釋放內(nèi)存
               releaseDispatchEntryLocked(dispatchEntry);
           }
       }
      // 如果當(dāng)前connection的outBoundQueque里還有Event,則繼續(xù)下一輪的Dispatch周期
       startDispatchCycleLocked(now(), connection);
   }
}

從waitQueue中將當(dāng)前DispatchEntry移除,如果當(dāng)前connection的outBoundQueque里還有EventEntry,則繼續(xù)下一輪的Dispatch周期。

最后放上整體流程圖和時序圖:

整體流程圖
時序圖

簡單總結(jié)下InputDispatcher分發(fā)事件流程:

1)InputReader喚醒InputDispacher執(zhí)行分發(fā)處理。

InputReader主要是將EventHub中的input_event轉(zhuǎn)換成具體的EventEntry,并添加到InputDispatcher的mInboundQueue里,然后喚醒InputDispacher線程。InputDispacher線程有自己的Looper,被喚醒后會執(zhí)行dispatchOnce方法,InputDispatcher處理的事件主要分兩種:一種是command命令(Command是mPolicy處理的具體事務(wù),這個mPolicy就是NativeInputManager,最終對應(yīng)的上層是InputManagerService),一種是input event。每次dispatchOnce,會優(yōu)先執(zhí)行前者。

2)InboundQueue隊頭取出事件,匹配焦點窗口,傳遞eventEntry。

從mInboundQueue隊列頭部取出一個事件,尋找與之匹配的焦點窗口的inputTargets,這里先通過InputWindowHandle找到InputWindowInfo,再找到InputChannel,最終找到Connection,每個焦點窗口在InputDispacher里都有一個對應(yīng)的Connection,通過這個Connection可以跟InputDispacher通信。然后會將eventEntry轉(zhuǎn)為DispatchEntry放入Connection的outboundQueue。通過InputPublisher通過 InputChannel::sendMessage將DispatchEntry發(fā)送給窗口,再將dispatchEntry從outboundQueue移到waitQueue里。該通信過程是異步的,也就是說當(dāng)InputDispatcher將Input事件發(fā)送給目標窗口后會立即返回,并不會等待窗口的處理結(jié)果。

3)窗口處理完又將處理結(jié)果返回給InputDispatcher

當(dāng)窗口處理完事件后,會通過handleReceiveCallback()回調(diào)函數(shù)通知InputDispatcher。回調(diào)主要是post一個command,從waitQueue中將當(dāng)前DispatchEntry移除,如果當(dāng)前connection的outBoundQueque里還有DispatchEntry,則繼續(xù)下一輪的Dispatch周期。

到這里InputDispatcher分發(fā)事件過程就介紹完了。

下一篇文章:
Android Input(五)-InputChannel通信

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容