Android触摸事件的传递(四-2)--输入系统-InputDispatcher

了解更多,移步Android触摸事件传递机制系列详解

Android触摸事件的传递(四-1)--输入系统-InputReader介绍InputReader利用EventHub获取数据后,生成EventEntry事件,加入到InputDispatcher的mInboundQueue队列,再唤醒InputDispatcher线程。本文将介绍InputDispatcher,同样从threadLoop为起点开始分析。

1 threadLoop

先来回顾一下InputDispatcher对象的初始化过程:

InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
    mPolicy(policy),
    mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
    mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
    mNextUnblockedEvent(NULL),
    mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
    mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
    //创建Looper对象
    mLooper = new Looper(false);

    mKeyRepeatState.lastKeyEntry = NULL;
    //获取分发超时参数
    policy->getDispatcherConfiguration(&mConfig);
}

该方法主要工作:

  • 创建属于自己线程的Looper对象;
  • 超时参数来自于IMS,参数默认值keyRepeatTimeout = 500,keyRepeatDelay = 50。

[-> InputDispatcher.cpp]

bool InputDispatcherThread::threadLoop() {
    mDispatcher->dispatchOnce(); //【见小节1.2】
    return true;
}

整个过程不断循环地调用InputDispatcherdispatchOnce()来分发事件

2 dispatchOnce

[-> InputDispatcher.cpp]

void InputDispatcher::dispatchOnce() {
    nsecs_t nextWakeupTime = LONG_LONG_MAX;
    {
        AutoMutex _l(mLock);
        //唤醒等待线程,monitor()用于监控dispatcher是否发生死锁
        mDispatcherIsAliveCondition.broadcast();

        if (!haveCommandsLocked()) {
            //当mCommandQueue不为空时处理
            dispatchOnceInnerLocked(&nextWakeupTime);
        }

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

    nsecs_t currentTime = now();
    int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime);
    mLooper->pollOnce(timeoutMillis); //进入epoll_wait
}

线程执行Looper->pollOnce,进入epoll_wait等待状态,当发生以下任一情况则退出等待状态:

  • callback:通过回调方法来唤醒;
  • timeout:到达nextWakeupTime时间,超时唤醒;
  • wake: 主动调用Looper的wake()方法;

3 dispatchOnceInnerLocked

void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {
    nsecs_t currentTime = now(); //当前时间

    if (!mDispatchEnabled) { //默认值为false
        resetKeyRepeatLocked(); //重置操作
    }
    if (mDispatchFrozen) { //默认值为false
        return; //当分发被冻结,则不再处理超时和分发事件的工作,直接返回
    }

    //优化app切换延迟,当切换超时,则抢占分发,丢弃其他所有即将要处理的事件。
    bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;
    ...

    if (!mPendingEvent) {
        if (mInboundQueue.isEmpty()) {
            if (!mPendingEvent) {
                return; //没有事件需要处理,则直接返回
            }
        } else {
            //从mInboundQueue取出头部的事件
            mPendingEvent = mInboundQueue.dequeueAtHead();
        }
        ...
        resetANRTimeoutsLocked(); //重置ANR信息[见小节2.1.1]
    }

    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;
    }
    ...

    switch (mPendingEvent->type) {
      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;
          }
          // 分发按键事件[见小节2.2]
          done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
          break;
      }
        case EventEntry::TYPE_MOTION: {
        MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
        if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {
            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;
        }
        done = dispatchMotionLocked(currentTime, typedEntry,
                &dropReason, nextWakeupTime);
        break;
    }
      ...
    }
    ...

    //分发操作完成,则进入该分支
    if (done) {
        if (dropReason != DROP_REASON_NOT_DROPPED) {
            //[见小节2.1.2]
            dropInboundEventLocked(mPendingEvent, dropReason);
        }
        mLastDropReason = dropReason;
        releasePendingEventLocked(); //释放pending事件见小节2.10]
        *nextWakeupTime = LONG_LONG_MIN; //强制立刻执行轮询
    }
}
  • 在enqueueInboundEventLocked()的过程中已设置mAppSwitchDueTime等于eventTime加上500ms:
    mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT;
    该方法主要功能:
    1.mDispatchFrozen用于决定是否冻结事件分发工作不再往下执行;
  1. 当事件分发的时间点距离该事件加入mInboundQueue的时间超过500ms,则认为app切换过期,即isAppSwitchDue=true;
  2. mInboundQueue不为空,则取出头部的事件,放入mPendingEvent变量;并重置ANR时间;
  3. 根据EventEntry的type类型分别处理,比如按键调用dispatchKeyLocked分发事件,触摸事件调用dispatchMotionLocked分发事件;再根据分发结果来决定是否进入done;
  4. 执行完成(done)的处理:
  • 根据dropReason(默认NOT_DROPPED不处理)来决定是否丢失事件:dropInboundEventLocked
  • 释放当前正在处理的事件(即mPendingEvent):releasePendingEventLocked

3.1 resetANRTimeoutsLocked重置ANR时间

void InputDispatcher::resetANRTimeoutsLocked() {
    // 重置等待超时cause和handle
    mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
    mInputTargetWaitApplicationHandle.clear();
}

3.2 dispatchMotionLocked分发事件

bool InputDispatcher::dispatchMotionLocked(
        nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) {
      ....
      Vector<InputTarget> inputTargets;
if (isPointerEvent) {
        // Pointer event.  (eg. touchscreen)
      //寻找目标窗口
        injectionResult = findTouchedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime, &conflictingPointerActions);
    } else {
        // Non touch event.  (eg. trackball)
        injectionResult = findFocusedWindowTargetsLocked(currentTime,
                entry, inputTargets, nextWakeupTime);
    }
    ....
    dispatchEventLocked(currentTime, entry, inputTargets);
    return true;
}
  • 主要工作
  1. 在dispatchEventLocked发送事件之前,会先去判断这个事件是点击事件(isPointEvent)还是其他事件--寻找目标窗口
  2. 分发事件

3.3 findTouchedWindowTargetsLocked


int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,
        const MotionEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime,
        bool* outConflictingPointerActions) {
    enum InjectionPermission {
        INJECTION_PERMISSION_UNKNOWN,
        INJECTION_PERMISSION_GRANTED,
        INJECTION_PERMISSION_DENIED
    };
 
    nsecs_t startTime = now();
 
    ......
 
    // Ensure all touched foreground windows are ready for new input.
    for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
        const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
        if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
            // Check whether the window is ready for more input.
            String8 reason = checkWindowReadyForMoreInputLocked(currentTime,
                    touchedWindow.windowHandle, entry, "touched");
            if (!reason.isEmpty()) {
                injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
                        NULL, touchedWindow.windowHandle, nextWakeupTime, reason.string());
                goto Unresponsive;
            }
        }
    }
    ......
    for (size_t i = 0; i < mTempTouchState.windows.size(); i++) {
        const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i);
        addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
                touchedWindow.pointerIds, inputTargets);
    }
 
    ......
    return injectionResult;
}

  • 这是一个很长的方法
  • 大体是判断这个事件的类型
  • 获取能够处理这个事件的forceground window,如果这个window不能够继续处理事件,就是说这个window的主线程被某些耗时操作占据,我们继续看handleTargetsNotReadyLocked这个方法。

3.3 handleTargetsNotReadyLocked

int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime,
    const EventEntry* entry,
    const sp<InputApplicationHandle>& applicationHandle,
    const sp<InputWindowHandle>& windowHandle,
    nsecs_t* nextWakeupTime, const char* reason) {
    if (applicationHandle == NULL && windowHandle == NULL) {
        if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) {
            mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY;
            mInputTargetWaitStartTime = currentTime; //当前时间
            mInputTargetWaitTimeoutTime = LONG_LONG_MAX;
            mInputTargetWaitTimeoutExpired = false;
            mInputTargetWaitApplicationHandle.clear();
        }
    } else {
        if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
            nsecs_t timeout;
            if (windowHandle != NULL) {
                timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
            } else if (applicationHandle != NULL) {
                timeout = applicationHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
            } else {
                timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; // 5s
            }

            mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
            mInputTargetWaitStartTime = currentTime; //当前时间
            mInputTargetWaitTimeoutTime = currentTime + timeout;
            mInputTargetWaitTimeoutExpired = false;
            mInputTargetWaitApplicationHandle.clear();

            if (windowHandle != NULL) {
                mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;
            }
            if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) {
                mInputTargetWaitApplicationHandle = applicationHandle;
            }
        }
    }

    if (mInputTargetWaitTimeoutExpired) {
        return INPUT_EVENT_INJECTION_TIMED_OUT; //等待超时已过期,则直接返回
    }

    //当超时5s则进入ANR流程
    if (currentTime >= mInputTargetWaitTimeoutTime) {
        onANRLocked(currentTime, applicationHandle, windowHandle,
                entry->eventTime, mInputTargetWaitStartTime, reason);

        *nextWakeupTime = LONG_LONG_MIN; //强制立刻执行轮询来执行ANR策略
        return INPUT_EVENT_INJECTION_PENDING;
    } else {
        if (mInputTargetWaitTimeoutTime < *nextWakeupTime) {
            *nextWakeupTime = mInputTargetWaitTimeoutTime; //当触发超时则强制执行轮询
        }
        return INPUT_EVENT_INJECTION_PENDING;
    }
}
  • 此处mInputTargetWaitTimeoutTime是由当前时间戳+5s, 并设置mInputTargetWaitCause等于INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY. 也就是说ANR时间段是指input等待理由处于INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY(应用没有准备就绪)的时间长达5s的场景.而前面resetANRTimeoutsLocked() 过程是唯一用于重置等待理由的地方.

  • 那么, ANR时间区间是指当前这次的事件dispatch过程中执行findTouchedWindowTargetsLocked()方法到下一次执行resetANRTimeoutsLocked()的时间区间.

  • 当applicationHandle和windowHandle同时为空, 且system准备就绪的情况下
  1. 设置等待理由 INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY;
  2. 设置超时等待时长为无限大;
  3. 设置TimeoutExpired= false
  4. 清空等待队列;
  • 当applicationHandle和windowHandle至少一个不为空, 且application准备就绪的情况下:
  1. 设置等待理由 INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY;
  2. 设置超时等待时长为5s;
  3. 设置TimeoutExpired= false
  4. 清空等待队列;

findTouchedWindowTargetsLocked,如果没有发生ANR,则addWindowTargetLocked()将该事件添加到inputTargets。

3.4 addWindowTargetLocked

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

将当前聚焦窗口mFocusedWindowHandle的inputChannel传递到inputTargets。

3.5 dispatchEventLocked

void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
        EventEntry* eventEntry, const Vector<InputTarget>& inputTargets) {
    //向mCommandQueue队列添加doPokeUserActivityLockedInterruptible命令
    pokeUserActivityLocked(eventEntry);

    for (size_t i = 0; i < inputTargets.size(); i++) {
        const InputTarget& inputTarget = inputTargets.itemAt(i);
        //
        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
        if (connectionIndex >= 0) {
            sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
            //找到目标连接
            prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
        }
    }
}

该方法主要功能是将eventEntry发送到目标inputTargets.

其中pokeUserActivityLocked(eventEntry)方法最终会调用到Java层的PowerManagerService.java中的userActivityFromNative()方法. 这也是PMS中唯一的native call方法.

3.5.1 pokeUserActivityLocked

void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
    if (mFocusedWindowHandle != NULL) {
        const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
        if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) {
            return;
        }
    }
    ...
    //【见小节2.4.2】
    CommandEntry* commandEntry = postCommandLocked(
            & InputDispatcher::doPokeUserActivityLockedInterruptible);
    commandEntry->eventTime = eventEntry->eventTime;
    commandEntry->userActivityEventType = eventType;
}

3.5.2 postCommandLocked

InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) {
    CommandEntry* commandEntry = new CommandEntry(command);
    // 将命令加入mCommandQueue队尾
    mCommandQueue.enqueueAtTail(commandEntry);
    return commandEntry;
}

3.6 getConnectionIndexLocked

ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
    ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd());
    if (connectionIndex >= 0) {
        sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
        if (connection->inputChannel.get() == inputChannel.get()) {
            return connectionIndex;
        }
    }
    return -1;
}

根据inputChannel的fd从mConnectionsByFd队列中查询目标connection.

3.6 prepareDispatchCycleLocked

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

    if (connection->status != Connection::STATUS_NORMAL) {
        return; //当连接已破坏,则直接返回
    }
    ...

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

当connection状态不正确,则直接返回。

3.7 enqueueDispatchEntriesLocked

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

    //根据dispatchMode来分别执行DispatchEntry事件加入队列的操作。
    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 (wasEmpty && !connection->outboundQueue.isEmpty()) {
        //当原先的outbound队列为空, 且当前outbound不为空的情况执行.
        startDispatchCycleLocked(currentTime, connection);
    }
}
  • 该方法主要功能:

  • 根据dispatchMode来分别执行DispatchEntry事件加入队列的操作。

  • 当起初connection.outboundQueue等于空, 经enqueueDispatchEntryLocked处理后, outboundQueue不等于空情况下, 则执行startDispatchCycleLocked()方法.

3.8 enqueueDispatchEntryLocked

void InputDispatcher::enqueueDispatchEntryLocked(
        const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
        int32_t dispatchMode) {
    int32_t inputTargetFlags = inputTarget->flags;
    if (!(inputTargetFlags & dispatchMode)) {
        return; //分发模式不匹配,则直接返回
    }
    inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;

    //生成新的事件, 加入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;

            if (!connection->inputState.trackKey(keyEntry,
                    dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
                delete dispatchEntry;
                return; //忽略不连续的事件
            }
            break;
        }
      case EventEntry::TYPE_MOTION: {
        MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
        if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
        } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {
            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT;
        } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) {
            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
        } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) {
            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL;
        } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) {
            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN;
        } else {
            dispatchEntry->resolvedAction = motionEntry->action;
        }
        if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE
                && !connection->inputState.isHovering(
                        motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) {
#if DEBUG_DISPATCH_CYCLE
        ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event",
                connection->getInputChannelName());
#endif
            dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER;
        }

        dispatchEntry->resolvedFlags = motionEntry->flags;
        if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) {
            dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
        }

        if (!connection->inputState.trackMotion(motionEntry,
                dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) {
#if DEBUG_DISPATCH_CYCLE
            ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event",
                    connection->getInputChannelName());
#endif
            delete dispatchEntry;
            return; // skip the inconsistent event
        }
        break;
    }
        ...
    }
    ...

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

该方法主要功能:

  • 根据dispatchMode来决定是否需要加入outboundQueue队列;
  • 根据EventEntry,来生成DispatchEntry事件;
  • 将dispatchEntry加入到connection的outbound队列.

执行到这里,其实等于由做了一次搬运的工作,将InputDispatcher中mInboundQueue中的事件取出后, 找到目标window后,封装dispatchEntry加入到connection的outbound队列.

3.9 startDispatchCycleLocked

void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
        const sp<Connection>& connection) {

    //当Connection状态正常,且outboundQueue不为空
    while (connection->status == Connection::STATUS_NORMAL
            && !connection->outboundQueue.isEmpty()) {
        DispatchEntry* dispatchEntry = connection->outboundQueue.head;
        dispatchEntry->deliveryTime = currentTime; //设置deliveryTime时间

        status_t status;
        EventEntry* eventEntry = dispatchEntry->eventEntry;
        switch (eventEntry->type) {
        case EventEntry::TYPE_KEY: {
            KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);

            // Publish the key event.
            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;
        }

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

            PointerCoords scaledCoords[MAX_POINTERS];
            const PointerCoords* usingCoords = motionEntry->pointerCoords;

            // Set the X and Y offset depending on the input source.
            float xOffset, yOffset, scaleFactor;
            if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                    && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
                scaleFactor = dispatchEntry->scaleFactor;
                xOffset = dispatchEntry->xOffset * scaleFactor;
                yOffset = dispatchEntry->yOffset * scaleFactor;
                if (scaleFactor != 1.0f) {
                    for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                        scaledCoords[i] = motionEntry->pointerCoords[i];
                        scaledCoords[i].scale(scaleFactor);
                    }
                    usingCoords = scaledCoords;
                }
            } else {
                xOffset = 0.0f;
                yOffset = 0.0f;
                scaleFactor = 1.0f;

                // We don't want the dispatch target to know.
                if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
                    for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
                        scaledCoords[i].clear();
                    }
                    usingCoords = scaledCoords;
                }
            }

            // Publish the motion event.
            status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq,
                    motionEntry->deviceId, motionEntry->source,
                    dispatchEntry->resolvedAction, motionEntry->actionButton,
                    dispatchEntry->resolvedFlags, motionEntry->edgeFlags,
                    motionEntry->metaState, motionEntry->buttonState,
                    xOffset, yOffset, motionEntry->xPrecision, motionEntry->yPrecision,
                    motionEntry->downTime, motionEntry->eventTime,
                    motionEntry->pointerCount, motionEntry->pointerProperties,
                    usingCoords);
            break;
        }

        default:
            ALOG_ASSERT(false);
            return;
        }

        if (status) { //publishKeyEvent失败情况
            if (status == WOULD_BLOCK) {
                if (connection->waitQueue.isEmpty()) {
                    //pipe已满,但waitQueue为空. 不正常的行为
                    abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
                } else {
                    // 处于阻塞状态
                    connection->inputPublisherBlocked = true;
                }
            } else {
                //不不正常的行为
                abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);
            }
            return;
        }

        //从outboundQueue中取出事件,重新放入waitQueue队列
        connection->outboundQueue.dequeue(dispatchEntry);
        connection->waitQueue.enqueueAtTail(dispatchEntry);

    }
}
  • startDispatchCycleLocked的主要功能: 从outboundQueue中取出事件,重新放入waitQueue队列

  • startDispatchCycleLocked触发时机:当起初connection.outboundQueue等于空, 经enqueueDispatchEntryLocked处理后, outboundQueue不等于空。

  • startDispatchCycleLocked主要功能: 从outboundQueue中取出事件,重新放入waitQueue队列

  • publishMotionEvent执行结果status不等于OK的情况下:

  1. WOULD_BLOCK,且waitQueue等于空,则调用abortBrokenDispatchCycleLocked(),该方法最终会调用到Java层的IMS.notifyInputChannelBroken().
  2. WOULD_BLOCK,且waitQueue不等于空,则处于阻塞状态,即inputPublisherBlocked=true
    其他情况,则调用abortBrokenDispatchCycleLocked
  • abortBrokenDispatchCycleLocked()方法最终会调用到Java层的IMS.notifyInputChannelBroken().

3.10 publishMotionEvent

至此调用了connectioninputPublisherpublishMotionEvent方法将事件分发消耗。

status_t InputPublisher::publishMotionEvent(...) {
  ....
  InputMessage msg;
  msg.header.type = InputMessage::TYPE_MOTION;
  msg.body.motion.seq = seq;
  msg.body.motion.deviceId = deviceId;
  msg.body.motion.source = source;
  msg.body.motion.action = action;
  msg.body.motion.actionButton = actionButton;
  msg.body.motion.flags = flags;
  msg.body.motion.edgeFlags = edgeFlags;
  msg.body.motion.metaState = metaState;
  msg.body.motion.buttonState = buttonState;
  msg.body.motion.xOffset = xOffset;
  msg.body.motion.yOffset = yOffset;
  msg.body.motion.xPrecision = xPrecision;
  msg.body.motion.yPrecision = yPrecision;
  msg.body.motion.downTime = downTime;
  msg.body.motion.eventTime = eventTime;
  msg.body.motion.pointerCount = pointerCount;
  for (uint32_t i = 0; i < pointerCount; i++) {
      msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
      msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
  }
    return mChannel->sendMessage(&msg);
}

InputChannel通过socket向远端的socket发送消息。

3.11 releasePendingEventLocked

void InputDispatcher::releasePendingEventLocked() {
    if (mPendingEvent) {
        resetANRTimeoutsLocked(); //重置ANR超时时间
        releaseInboundEventLocked(mPendingEvent); //释放mPendingEvent对象,并记录到mRecentQueue队列
        mPendingEvent = NULL; //置空mPendingEvent变量.
    }
}

4 处理Comand

4.1 runCommandsLockedInterruptible

bool InputDispatcher::runCommandsLockedInterruptible() {
    if (mCommandQueue.isEmpty()) {
        return false;
    }

    do {
        //从mCommandQueue队列的头部取出第一个元素
        CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();

        Command command = commandEntry->command;
        //此处调用的命令隐式地包含'LockedInterruptible'
        (this->*command)(commandEntry);

        commandEntry->connection.clear();
        delete commandEntry;
    } while (! mCommandQueue.isEmpty());
    return true;
}

通过循环方式处理完mCommandQueue队列的所有命令,处理过程从mCommandQueue中取出CommandEntry.

typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry);
struct CommandEntry : Link<CommandEntry> {
    CommandEntry(Command command);

    Command command;
    sp<Connection> connection;
    nsecs_t eventTime;
    KeyEntry* keyEntry;
    sp<InputApplicationHandle> inputApplicationHandle;
    sp<InputWindowHandle> inputWindowHandle;
    String8 reason;
    int32_t userActivityEventType;
    uint32_t seq;
    bool handled;
};

在dispatchEventLocked中添加的doPokeUserActivityLockedInterruptible命令.

3.2

[-> InputDispatcher]

void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) {
    mLock.unlock();

    mPolicy->pokeUserActivity(commandEntry->eventTime, commandEntry->userActivityEventType);

    mLock.lock();
}

3.3 pokeUserActivity

[-> com_android_server_input_InputManagerService.cpp]

void NativeInputManager::pokeUserActivity(nsecs_t eventTime, int32_t eventType) {

  android_server_PowerManagerService_userActivity(eventTime, eventType);
}

3.4 android_server_PowerManagerService_userActivity

[-> com_android_server_power_PowerManagerService.cpp]

void android_server_PowerManagerService_userActivity(nsecs_t eventTime, int32_t eventType) {
    // Tell the power HAL when user activity occurs.
    if (gPowerModule && gPowerModule->powerHint) {
        gPowerModule->powerHint(gPowerModule, POWER_HINT_INTERACTION, NULL);
    }

    if (gPowerManagerServiceObj) {
        ...
        //[见小节4.5]
        env->CallVoidMethod(gPowerManagerServiceObj,
                gPowerManagerServiceClassInfo.userActivityFromNative,
                nanoseconds_to_milliseconds(eventTime), eventType, 0);
    }
}

3.5 PMS.userActivityFromNative

[-> PowerManagerService.java]

private void userActivityFromNative(long eventTime, int event, int flags) {
    userActivityInternal(eventTime, event, flags, Process.SYSTEM_UID);
}

private void userActivityInternal(long eventTime, int event, int flags, int uid) {
    synchronized (mLock) {
        if (userActivityNoUpdateLocked(eventTime, event, flags, uid)) {
            updatePowerStateLocked();
        }
    }
}

runCommandsLockedInterruptible是不断地从mCommandQueue队列取出命令,然后执行直到全部执行完成。 除了doPokeUserActivityLockedInterruptible,还有其他如下命令:

  • doNotifyANRLockedInterruptible
  • doInterceptKeyBeforeDispatchingLockedInterruptible
  • doDispatchCycleFinishedLockedInterruptible
  • doNotifyInputChannelBrokenLockedInterruptible
  • doNotifyConfigurationChangedInterruptible

总结

InputDispatcher.png
    1. dispatchOnceInnerLocked(): 从InputDispatcher的mInboundQueue队列,取出事件EventEntry。另外该方法开始执行的时间点(currentTime)便是后续事件dispatchEntry的分发时间(deliveryTime)
    1. dispatchKeyLocked():满足一定条件时会添加命令doInterceptKeyBeforeDispatchingLockedInterruptible;
  • 3.enqueueDispatchEntryLocked():生成事件DispatchEntry并加入connection的outbound队列
    1. startDispatchCycleLocked():从outboundQueue中取出事件DispatchEntry, 重新放入connection的waitQueue队列;
    1. InputChannel.sendMessage通过socket方式将消息发送给远程进程;
    1. runCommandsLockedInterruptible():通过循环遍历地方式,依次处理mCommandQueue队列中的所有命令。而mCommandQueue队列中的命令是通过postCommandLocked()方式向该队列添加的。

参考

Input系统—InputDispatcher线程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345