一张图带你掌握Android Q上InputDispatcher事件分发流程(系统层)_第1张图片

frameworks\native\services\inputflinger\dispatcher\InputDispatcher.cpp
frameworks\native\services\inputflinger\dispatcher\InputDispatcher.h

frameworks\native\include\android\input.h
frameworks\native\services\inputflinger\dispatcher\InputState.cpp
frameworks\native\services\inputflinger\dispatcher\InputState.h
frameworks\native\libs\input\InputTransport.cpp

sourcecode\frameworks\base\core\jni\android_view_InputEventReceiver.cpp
sourcecode\frameworks\base\core\java\android\view\InputEventReceiver.java
sourcecode\frameworks\base\core\java\android\view\ViewRootImpl.java
sourcecode\frameworks\base\core\java\android\view\View.java
frameworks\base\core\java\android\view\ViewGroup.java

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()) {//执行命令并将下一次唤醒时间设为c++中的最小值            nextWakeupTime = LONG_LONG_MIN;        }    } // 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);//进行下一次循环或者进入休眠}
bool InputDispatcher::haveCommandsLocked() const {    //判断命令队列是否为null,里面存储的是CommandEntry实体    return !mCommandQueue.isEmpty();}
bool InputDispatcher::runCommandsLockedInterruptible() {    if (mCommandQueue.isEmpty()) {        return false;    }    do {        //取出队头的命令开始执行        CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();        Command command = commandEntry->command;        (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'        commandEntry->connection.clear();        delete commandEntry;//释放内存    } while (!mCommandQueue.isEmpty());    return true;}

 

void InputDispatcher::resetKeyRepeatLocked() {    if (mKeyRepeatState.lastKeyEntry) {        mKeyRepeatState.lastKeyEntry->release();        mKeyRepeatState.lastKeyEntry = nullptr;    }}
void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) {    nsecs_t currentTime = now();    // Reset the key repeat timer whenever normal dispatch is suspended while the    // device is in a non-interactive state.  This is to ensure that we abort a key    // repeat if the device is just coming out of sleep.    //判断事件分发是否允许,也就是在未开机、IMS未成功启动、关机等状态下是不可用的,默认值是false    if (!mDispatchEnabled) {        resetKeyRepeatLocked();//重置重复按键次数    }    // If dispatching is frozen, do not process timeouts or try to deliver any new events.    //判断分发线程是否被冻结,是否可以配发,默认值是false    if (mDispatchFrozen) {#if DEBUG_FOCUS        ALOGD("Dispatch frozen.  Waiting some more.");#endif        return;    }    // Optimize latency of app switches.    // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has    // been pressed.  When it expires, we preempt dispatch and drop all other pending events.    //判断此处是不是正在切换应用,以便在home和endcall按键到来时,及时丢弃之前的事件,而直接响应特殊键    bool isAppSwitchDue = mAppSwitchDueTime <= currentTime;    if (mAppSwitchDueTime < *nextWakeupTime) {        *nextWakeupTime = mAppSwitchDueTime;    }    // Ready to start a new event.    // If we don't already have a pending event, go grab one.    if (!mPendingEvent) {//mPendingEvent是即将要被配发的事件,此处是判断是否正在配发事件        if (mInboundQueue.isEmpty()) {//判断配发事件队列            if (isAppSwitchDue) {                // The inbound queue is empty so the app switch key we were waiting                // for will never arrive.  Stop waiting for it.                //如果队列是null。那么要等到的home或者挂机键永远不会到来,需要重置                resetPendingAppSwitchLocked(false);                isAppSwitchDue = false;            }            // Synthesize a key repeat if appropriate.            //对于某些设备,需要补发按下的重复事件            if (mKeyRepeatState.lastKeyEntry) {                if (currentTime >= mKeyRepeatState.nextRepeatTime) {                    mPendingEvent = synthesizeKeyRepeatLocked(currentTime);                } else {                    if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) {                        *nextWakeupTime = mKeyRepeatState.nextRepeatTime;                    }                }            }            // Nothing to do if there is no pending event.            if (!mPendingEvent) {                return;            }        } else {            // Inbound queue has at least one entry.            //如果正在配发的事件为null,那么就从配发队列中取出一个,开始配发            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.        //重置此次事件分发的ANR超时时间,如果超过5秒,就会产生ANR        resetANRTimeoutsLocked();    }    // 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 != nullptr);    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 = nullptr;    }    switch (mPendingEvent->type) {        case EventEntry::TYPE_CONFIGURATION_CHANGED: {            ConfigurationChangedEntry* typedEntry =                    static_cast(mPendingEvent);            done = dispatchConfigurationChangedLocked(currentTime, typedEntry);            dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped            break;        }        case EventEntry::TYPE_DEVICE_RESET: {            DeviceResetEntry* typedEntry = static_cast(mPendingEvent);            done = dispatchDeviceResetLocked(currentTime, typedEntry);            dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped            break;        }        case EventEntry::TYPE_KEY: {            KeyEntry* typedEntry = static_cast(mPendingEvent);            if (isAppSwitchDue) {                if (isAppSwitchKeyEvent(typedEntry)) {                    resetPendingAppSwitchLocked(true);                    isAppSwitchDue = false;                } else if (dropReason == DROP_REASON_NOT_DROPPED) {                    dropReason = DROP_REASON_APP_SWITCH;                }            }            if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEvent(currentTime, typedEntry)) {                dropReason = DROP_REASON_STALE;            }            if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {                dropReason = DROP_REASON_BLOCKED;            }            done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);            break;        }        case EventEntry::TYPE_MOTION: {            MotionEntry* typedEntry = static_cast(mPendingEvent);            if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) {                dropReason = DROP_REASON_APP_SWITCH;            }            if (dropReason == DROP_REASON_NOT_DROPPED && isStaleEvent(currentTime, typedEntry)) {                dropReason = DROP_REASON_STALE;            }            if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) {                dropReason = DROP_REASON_BLOCKED;            }            done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);            break;        }        default:            ALOG_ASSERT(false);            break;    }    if (done) {        if (dropReason != DROP_REASON_NOT_DROPPED) {            dropInboundEventLocked(mPendingEvent, dropReason);//从配发队列里面丢弃事件        }        mLastDropReason = dropReason;        releasePendingEventLocked();        *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately    }}
bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry,                                           DropReason* dropReason, nsecs_t* nextWakeupTime) {    ATRACE_CALL();    // Preprocessing.    if (!entry->dispatchInProgress) {//设置当前事件的配发进度        entry->dispatchInProgress = true;        logOutboundMotionDetails("dispatchMotion - ", entry);//打印出派发事件的详情    }    // Clean up if dropping the event.    if (*dropReason != DROP_REASON_NOT_DROPPED) {//如果是丢弃事件则直接设置派发结果        setInjectionResult(entry,                           *dropReason == DROP_REASON_POLICY ? INPUT_EVENT_INJECTION_SUCCEEDED                                                             : INPUT_EVENT_INJECTION_FAILED);        return true;    }   //判断是不是点事件    bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;    // Identify targets.    std::vector inputTargets;//派发的窗口集合    bool conflictingPointerActions = false;    int32_t injectionResult;    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);    }    if (injectionResult == INPUT_EVENT_INJECTION_PENDING) {        return false;    }    setInjectionResult(entry, injectionResult);    if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) {        if (injectionResult != INPUT_EVENT_INJECTION_PERMISSION_DENIED) {            CancelationOptions::Mode mode(isPointerEvent                                                  ? CancelationOptions::CANCEL_POINTER_EVENTS                                                  : CancelationOptions::CANCEL_NON_POINTER_EVENTS);            CancelationOptions options(mode, "input event injection failed");            synthesizeCancelationEventsForMonitorsLocked(options);        }        return true;    }    // Add monitor channels from event's or focused display.    addGlobalMonitoringTargetsLocked(inputTargets, getTargetDisplayId(entry));    if (isPointerEvent) {        ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(entry->displayId);        if (stateIndex >= 0) {            const TouchState& state = mTouchStatesByDisplay.valueAt(stateIndex);            if (!state.portalWindows.empty()) {                // The event has gone through these portal windows, so we add monitoring targets of                // the corresponding displays as well.                for (size_t i = 0; i < state.portalWindows.size(); i++) {                    const InputWindowInfo* windowInfo = state.portalWindows[i]->getInfo();                    addGlobalMonitoringTargetsLocked(inputTargets, windowInfo->portalToDisplayId,                                                     -windowInfo->frameLeft, -windowInfo->frameTop);                }            }        }    }    // Dispatch the motion.    //指针冲突,此处可能由于触摸设备的不同up或者down等动作又多次,而再输入中只允许又一次up    if (conflictingPointerActions) {        CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,                                   "conflicting pointer actions");        synthesizeCancelationEventsForAllConnectionsLocked(options);    }    dispatchEventLocked(currentTime, entry, inputTargets);    return true;}
void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,                                          const std::vector& inputTargets) {    ATRACE_CALL();#if DEBUG_DISPATCH_CYCLE    ALOGD("dispatchEventToCurrentInputTargets");#endif    ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true    pokeUserActivityLocked(eventEntry);    for (const InputTarget& inputTarget : inputTargets) {        ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);        if (connectionIndex >= 0) {            sp 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().c_str());#endif        }    }}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,                                                 const sp& connection,                                                 EventEntry* eventEntry,                                                 const InputTarget* inputTarget) {    if (ATRACE_ENABLED()) {        std::string message =                StringPrintf("prepareDispatchCycleLocked(inputChannel=%s, sequenceNum=%" PRIu32 ")",                             connection->getInputChannelName().c_str(), eventEntry->sequenceNum);        ATRACE_NAME(message.c_str());    }#if DEBUG_DISPATCH_CYCLE    ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "          "xOffset=%f, yOffset=%f, globalScaleFactor=%f, "          "windowScaleFactor=(%f, %f), pointerIds=0x%x",          connection->getInputChannelName().c_str(), inputTarget->flags, inputTarget->xOffset,          inputTarget->yOffset, inputTarget->globalScaleFactor, inputTarget->windowXScale,          inputTarget->windowYScale, inputTarget->pointerIds.value);#endif    // 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;    }    // Split a motion event if needed.    if (inputTarget->flags & InputTarget::FLAG_SPLIT) {        ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION);        MotionEntry* originalMotionEntry = static_cast(eventEntry);        if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) {            MotionEntry* splitMotionEntry =                    splitMotionEvent(originalMotionEntry, inputTarget->pointerIds);            if (!splitMotionEntry) {                return; // split event was dropped            }#if DEBUG_FOCUS            ALOGD("channel '%s' ~ Split motion event.", connection->getInputChannelName().c_str());            logOutboundMotionDetails("  ", splitMotionEntry);#endif            enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget);            splitMotionEntry->release();            return;        }    }    // Not splitting.  Enqueue dispatch entries for the event as is.    enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget);}
void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,                                                   const sp& connection,                                                   EventEntry* eventEntry,                                                   const InputTarget* inputTarget) {    if (ATRACE_ENABLED()) {        std::string message =                StringPrintf("enqueueDispatchEntriesLocked(inputChannel=%s, sequenceNum=%" PRIu32                             ")",                             connection->getInputChannelName().c_str(), eventEntry->sequenceNum);        ATRACE_NAME(message.c_str());    }    bool wasEmpty = connection->outboundQueue.isEmpty();    // 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.isEmpty()) {        startDispatchCycleLocked(currentTime, connection);    }}
void InputDispatcher::enqueueDispatchEntryLocked(const sp& connection,                                                 EventEntry* eventEntry,                                                 const InputTarget* inputTarget,                                                 int32_t dispatchMode) {    if (ATRACE_ENABLED()) {        std::string message = StringPrintf("enqueueDispatchEntry(inputChannel=%s, dispatchMode=%s)",                                           connection->getInputChannelName().c_str(),                                           dispatchModeToString(dispatchMode).c_str());        ATRACE_NAME(message.c_str());    }    int32_t inputTargetFlags = inputTarget->flags;    if (!(inputTargetFlags & dispatchMode)) {        return;    }    inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode;    // This is a new event.    // Enqueue a new dispatch entry onto the outbound queue for this connection.    DispatchEntry* dispatchEntry =            new DispatchEntry(eventEntry, // increments ref                              inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset,                              inputTarget->globalScaleFactor, inputTarget->windowXScale,                              inputTarget->windowYScale);    // Apply target flags and update the connection's input state.    switch (eventEntry->type) {        case EventEntry::TYPE_KEY: {            KeyEntry* keyEntry = static_cast(eventEntry);            dispatchEntry->resolvedAction = keyEntry->action;            dispatchEntry->resolvedFlags = keyEntry->flags;            if (!connection->inputState.trackKey(keyEntry, dispatchEntry->resolvedAction,                                                 dispatchEntry->resolvedFlags)) {#if DEBUG_DISPATCH_CYCLE                ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event",                      connection->getInputChannelName().c_str());#endif                delete dispatchEntry;                return; // skip the inconsistent event            }            break;        }        case EventEntry::TYPE_MOTION: {            MotionEntry* motionEntry = static_cast(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().c_str());#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 (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED) {                dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED;            }            if (!connection->inputState.trackMotion(motionEntry, dispatchEntry->resolvedAction,                                                    dispatchEntry->resolvedFlags)) {#if DEBUG_DISPATCH_CYCLE                ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion "                      "event",                      connection->getInputChannelName().c_str());#endif                delete dispatchEntry;                return; // skip the inconsistent event            }            dispatchPointerDownOutsideFocus(motionEntry->source, dispatchEntry->resolvedAction,                                            inputTarget->inputChannel->getToken());            break;        }    }    // Remember that we are waiting for this dispatch to complete.    if (dispatchEntry->hasForegroundTarget()) {        incrementPendingForegroundDispatches(eventEntry);    }    // Enqueue the dispatch entry.    connection->outboundQueue.enqueueAtTail(dispatchEntry);    traceOutboundQueueLength(connection);}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,                                               const sp& connection) {    if (ATRACE_ENABLED()) {        std::string message = StringPrintf("startDispatchCycleLocked(inputChannel=%s)",                                           connection->getInputChannelName().c_str());        ATRACE_NAME(message.c_str());    }#if DEBUG_DISPATCH_CYCLE    ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str());#endif    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(eventEntry);                // Publish the key event.                status = connection->inputPublisher                                 .publishKeyEvent(dispatchEntry->seq, keyEntry->deviceId,                                                  keyEntry->source, keyEntry->displayId,                                                  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(eventEntry);                PointerCoords scaledCoords[MAX_POINTERS];                const PointerCoords* usingCoords = motionEntry->pointerCoords;                // Set the X and Y offset depending on the input source.                float xOffset, yOffset;                if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) &&                    !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {                    float globalScaleFactor = dispatchEntry->globalScaleFactor;                    float wxs = dispatchEntry->windowXScale;                    float wys = dispatchEntry->windowYScale;                    xOffset = dispatchEntry->xOffset * wxs;                    yOffset = dispatchEntry->yOffset * wys;                    if (wxs != 1.0f || wys != 1.0f || globalScaleFactor != 1.0f) {                        for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {                            scaledCoords[i] = motionEntry->pointerCoords[i];                            scaledCoords[i].scale(globalScaleFactor, wxs, wys);                        }                        usingCoords = scaledCoords;                    }                } else {                    xOffset = 0.0f;                    yOffset = 0.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, motionEntry->displayId,                                                     dispatchEntry->resolvedAction,                                                     motionEntry->actionButton,                                                     dispatchEntry->resolvedFlags,                                                     motionEntry->edgeFlags, motionEntry->metaState,                                                     motionEntry->buttonState,                                                     motionEntry->classification, xOffset, yOffset,                                                     motionEntry->xPrecision,                                                     motionEntry->yPrecision, motionEntry->downTime,                                                     motionEntry->eventTime,                                                     motionEntry->pointerCount,                                                     motionEntry->pointerProperties, usingCoords);                break;            }            default:                ALOG_ASSERT(false);                return;        }        // Check the result.        if (status) {            if (status == WOULD_BLOCK) {                if (connection->waitQueue.isEmpty()) {                    ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "                          "This is unexpected because the wait queue is empty, so the pipe "                          "should be empty and we shouldn't have any problems writing an "                          "event to it, status=%d",                          connection->getInputChannelName().c_str(), status);                    abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);                } else {                    // Pipe is full and we are waiting for the app to finish process some events                    // before sending more events to it.#if DEBUG_DISPATCH_CYCLE                    ALOGD("channel '%s' ~ Could not publish event because the pipe is full, "                          "waiting for the application to catch up",                          connection->getInputChannelName().c_str());#endif                    connection->inputPublisherBlocked = true;                }            } else {                ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, "                      "status=%d",                      connection->getInputChannelName().c_str(), status);                abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/);            }            return;        }        // Re-enqueue the event on the wait queue.        connection->outboundQueue.dequeue(dispatchEntry);        traceOutboundQueueLength(connection);        connection->waitQueue.enqueueAtTail(dispatchEntry);        traceWaitQueueLength(connection);    }}
status_t InputPublisher::publishMotionEvent(        uint32_t seq,        int32_t deviceId,        int32_t source,        int32_t displayId,        int32_t action,        int32_t actionButton,        int32_t flags,        int32_t edgeFlags,        int32_t metaState,        int32_t buttonState,        MotionClassification classification,        float xOffset,        float yOffset,        float xPrecision,        float yPrecision,        nsecs_t downTime,        nsecs_t eventTime,        uint32_t pointerCount,        const PointerProperties* pointerProperties,        const PointerCoords* pointerCoords) {    if (ATRACE_ENABLED()) {        std::string message = StringPrintf(                "publishMotionEvent(inputChannel=%s, action=%" PRId32 ")",                mChannel->getName().c_str(), action);        ATRACE_NAME(message.c_str());    }#if DEBUG_TRANSPORT_ACTIONS    ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "            "displayId=%" PRId32 ", "            "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "            "metaState=0x%x, buttonState=0x%x, classification=%s, xOffset=%f, yOffset=%f, "            "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "            "pointerCount=%" PRIu32,            mChannel->getName().c_str(), seq,            deviceId, source, displayId, action, actionButton, flags, edgeFlags, metaState,            buttonState, motionClassificationToString(classification),            xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);#endif    if (!seq) {        ALOGE("Attempted to publish a motion event with sequence number 0.");        return BAD_VALUE;    }    if (pointerCount > MAX_POINTERS || pointerCount < 1) {        ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %" PRIu32 ".",                mChannel->getName().c_str(), pointerCount);        return BAD_VALUE;    }    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.displayId = displayId;    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.classification = classification;    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);}
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, &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);    } while (nWrite == -1 && errno == EINTR);    if (nWrite < 0) {        int error = errno;#if DEBUG_CHANNEL_MESSAGES        ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.c_str(),                msg->header.type, error);#endif        if (error == EAGAIN || error == EWOULDBLOCK) {            return WOULD_BLOCK;        }        if (error == EPIPE || error == ENOTCONN || error == ECONNREFUSED || error == ECONNRESET) {            return DEAD_OBJECT;        }        return -error;    }    if (size_t(nWrite) != msgLength) {#if DEBUG_CHANNEL_MESSAGES        ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",                mName.c_str(), msg->header.type);#endif        return DEAD_OBJECT;    }#if DEBUG_CHANNEL_MESSAGES    ALOGD("channel '%s' ~ sent message of type %d", mName.c_str(), msg->header.type);#endif    return OK;}

 

 

int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime,                                                        const MotionEntry* entry,                                                        std::vector& inputTargets,                                                        nsecs_t* nextWakeupTime,                                                        bool* outConflictingPointerActions) {    ATRACE_CALL();    enum InjectionPermission {        INJECTION_PERMISSION_UNKNOWN,        INJECTION_PERMISSION_GRANTED,        INJECTION_PERMISSION_DENIED    };    // For security reasons, we defer updating the touch state until we are sure that    // event injection will be allowed.    int32_t displayId = entry->displayId;    int32_t action = entry->action;    int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;    // Update the touch state as needed based on the properties of the touch event.    int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING;    InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN;    sp newHoverWindowHandle;    // Copy current touch state into mTempTouchState.    // This state is always reset at the end of this function, so if we don't find state    // for the specified display then our initial state will be empty.    const TouchState* oldState = nullptr;    ssize_t oldStateIndex = mTouchStatesByDisplay.indexOfKey(displayId);    if (oldStateIndex >= 0) {        oldState = &mTouchStatesByDisplay.valueAt(oldStateIndex);        mTempTouchState.copyFrom(*oldState);    }    bool isSplit = mTempTouchState.split;    bool switchedDevice = mTempTouchState.deviceId >= 0 && mTempTouchState.displayId >= 0 &&            (mTempTouchState.deviceId != entry->deviceId ||             mTempTouchState.source != entry->source || mTempTouchState.displayId != displayId);    bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE ||                          maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||                          maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT);    bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN ||                       maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction);    bool wrongDevice = false;    if (newGesture) {        bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;        if (switchedDevice && mTempTouchState.down && !down && !isHoverAction) {#if DEBUG_FOCUS            ALOGD("Dropping event because a pointer for a different device is already down "                  "in display %" PRId32,                  displayId);#endif            // TODO: test multiple simultaneous input streams.            injectionResult = INPUT_EVENT_INJECTION_FAILED;            switchedDevice = false;            wrongDevice = true;            goto Failed;        }        mTempTouchState.reset();        mTempTouchState.down = down;        mTempTouchState.deviceId = entry->deviceId;        mTempTouchState.source = entry->source;        mTempTouchState.displayId = displayId;        isSplit = false;    } else if (switchedDevice && maskedAction == AMOTION_EVENT_ACTION_MOVE) {#if DEBUG_FOCUS        ALOGI("Dropping move event because a pointer for a different device is already active "              "in display %" PRId32,              displayId);#endif        // TODO: test multiple simultaneous input streams.        injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;        switchedDevice = false;        wrongDevice = true;        goto Failed;    }    if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {        /* Case 1: New splittable pointer going down, or need target for hover or scroll. */        int32_t pointerIndex = getMotionEventActionPointerIndex(action);        int32_t x = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X));        int32_t y = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));        bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;        sp newTouchedWindowHandle =                findTouchedWindowAtLocked(displayId, x, y, isDown /*addOutsideTargets*/,                                          true /*addPortalWindows*/);        std::vector newGestureMonitors = isDown                ? findTouchedGestureMonitorsLocked(displayId, mTempTouchState.portalWindows)                : std::vector{};        // Figure out whether splitting will be allowed for this window.        if (newTouchedWindowHandle != nullptr &&            newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {            // New window supports splitting.            isSplit = true;        } else if (isSplit) {            // New window does not support splitting but we have already split events.            // Ignore the new window.            newTouchedWindowHandle = nullptr;        }        // Handle the case where we did not find a window.        if (newTouchedWindowHandle == nullptr) {            // Try to assign the pointer to the first foreground window we find, if there is one.            newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle();        }        if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) {            ALOGI("Dropping event because there is no touchable window or gesture monitor at "                  "(%d, %d) in display %" PRId32 ".",                  x, y, displayId);            injectionResult = INPUT_EVENT_INJECTION_FAILED;            goto Failed;        }        if (newTouchedWindowHandle != nullptr) {            // Set target flags.            int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS;            if (isSplit) {                targetFlags |= InputTarget::FLAG_SPLIT;            }            if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {                targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;            } else if (isWindowObscuredLocked(newTouchedWindowHandle)) {                targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;            }            // Update hover state.            if (isHoverAction) {                newHoverWindowHandle = newTouchedWindowHandle;            } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) {                newHoverWindowHandle = mLastHoverWindowHandle;            }            // Update the temporary touch state.            BitSet32 pointerIds;            if (isSplit) {                uint32_t pointerId = entry->pointerProperties[pointerIndex].id;                pointerIds.markBit(pointerId);            }            mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);        }        mTempTouchState.addGestureMonitors(newGestureMonitors);    } else {        /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */        // If the pointer is not currently down, then ignore the event.        if (!mTempTouchState.down) {#if DEBUG_FOCUS            ALOGD("Dropping event because the pointer is not down or we previously "                  "dropped the pointer down event in display %" PRId32,                  displayId);#endif            injectionResult = INPUT_EVENT_INJECTION_FAILED;            goto Failed;        }        // Check whether touches should slip outside of the current foreground window.        if (maskedAction == AMOTION_EVENT_ACTION_MOVE && entry->pointerCount == 1 &&            mTempTouchState.isSlippery()) {            int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X));            int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y));            sp oldTouchedWindowHandle =                    mTempTouchState.getFirstForegroundWindowHandle();            sp newTouchedWindowHandle =                    findTouchedWindowAtLocked(displayId, x, y);            if (oldTouchedWindowHandle != newTouchedWindowHandle &&                oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) {#if DEBUG_FOCUS                ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32,                      oldTouchedWindowHandle->getName().c_str(),                      newTouchedWindowHandle->getName().c_str(), displayId);#endif                // Make a slippery exit from the old window.                mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,                                                  InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT,                                                  BitSet32(0));                // Make a slippery entrance into the new window.                if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {                    isSplit = true;                }                int32_t targetFlags =                        InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER;                if (isSplit) {                    targetFlags |= InputTarget::FLAG_SPLIT;                }                if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {                    targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;                }                BitSet32 pointerIds;                if (isSplit) {                    pointerIds.markBit(entry->pointerProperties[0].id);                }                mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds);            }        }    }    if (newHoverWindowHandle != mLastHoverWindowHandle) {        // Let the previous window know that the hover sequence is over.        if (mLastHoverWindowHandle != nullptr) {#if DEBUG_HOVER            ALOGD("Sending hover exit event to window %s.",                  mLastHoverWindowHandle->getName().c_str());#endif            mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle,                                              InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT,                                              BitSet32(0));        }        // Let the new window know that the hover sequence is starting.        if (newHoverWindowHandle != nullptr) {#if DEBUG_HOVER            ALOGD("Sending hover enter event to window %s.",                  newHoverWindowHandle->getName().c_str());#endif            mTempTouchState.addOrUpdateWindow(newHoverWindowHandle,                                              InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER,                                              BitSet32(0));        }    }    // Check permission to inject into all touched foreground windows and ensure there    // is at least one touched foreground window.    {        bool haveForegroundWindow = false;        for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {            if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {                haveForegroundWindow = true;                if (!checkInjectionPermission(touchedWindow.windowHandle, entry->injectionState)) {                    injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;                    injectionPermission = INJECTION_PERMISSION_DENIED;                    goto Failed;                }            }        }        bool hasGestureMonitor = !mTempTouchState.gestureMonitors.empty();        if (!haveForegroundWindow && !hasGestureMonitor) {#if DEBUG_FOCUS            ALOGD("Dropping event because there is no touched foreground window in display %" PRId32                  " or gesture monitor to receive it.",                  displayId);#endif            injectionResult = INPUT_EVENT_INJECTION_FAILED;            goto Failed;        }        // Permission granted to injection into all touched foreground windows.        injectionPermission = INJECTION_PERMISSION_GRANTED;    }    // Check whether windows listening for outside touches are owned by the same UID. If it is    // set the policy flag that we will not reveal coordinate information to this window.    if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {        sp foregroundWindowHandle =                mTempTouchState.getFirstForegroundWindowHandle();        if (foregroundWindowHandle) {            const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid;            for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {                if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {                    sp inputWindowHandle = touchedWindow.windowHandle;                    if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) {                        mTempTouchState.addOrUpdateWindow(inputWindowHandle,                                                          InputTarget::FLAG_ZERO_COORDS,                                                          BitSet32(0));                    }                }            }        }    }    // Ensure all touched foreground windows are ready for new input.    for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {        if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {            // Check whether the window is ready for more input.            std::string reason =                    checkWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle,                                                       entry, "touched");            if (!reason.empty()) {                injectionResult = handleTargetsNotReadyLocked(currentTime, entry, nullptr,                                                              touchedWindow.windowHandle,                                                              nextWakeupTime, reason.c_str());                goto Unresponsive;            }        }    }    // If this is the first pointer going down and the touched window has a wallpaper    // then also add the touched wallpaper windows so they are locked in for the duration    // of the touch gesture.    // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper    // engine only supports touch events.  We would need to add a mechanism similar    // to View.onGenericMotionEvent to enable wallpapers to handle these events.    if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {        sp foregroundWindowHandle =                mTempTouchState.getFirstForegroundWindowHandle();        if (foregroundWindowHandle && foregroundWindowHandle->getInfo()->hasWallpaper) {            const std::vector> windowHandles =                    getWindowHandlesLocked(displayId);            for (const sp& windowHandle : windowHandles) {                const InputWindowInfo* info = windowHandle->getInfo();                if (info->displayId == displayId &&                    windowHandle->getInfo()->layoutParamsType == InputWindowInfo::TYPE_WALLPAPER) {                    mTempTouchState                            .addOrUpdateWindow(windowHandle,                                               InputTarget::FLAG_WINDOW_IS_OBSCURED |                                                       InputTarget::                                                               FLAG_WINDOW_IS_PARTIALLY_OBSCURED |                                                       InputTarget::FLAG_DISPATCH_AS_IS,                                               BitSet32(0));                }            }        }    }    // Success!  Output targets.    injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED;    for (const TouchedWindow& touchedWindow : mTempTouchState.windows) {        addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,                              touchedWindow.pointerIds, inputTargets);    }    for (const TouchedMonitor& touchedMonitor : mTempTouchState.gestureMonitors) {        addMonitoringTargetLocked(touchedMonitor.monitor, touchedMonitor.xOffset,                                  touchedMonitor.yOffset, inputTargets);    }    // Drop the outside or hover touch windows since we will not care about them    // in the next iteration.    mTempTouchState.filterNonAsIsTouchWindows();Failed:    // Check injection permission once and for all.    if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {        if (checkInjectionPermission(nullptr, entry->injectionState)) {            injectionPermission = INJECTION_PERMISSION_GRANTED;        } else {            injectionPermission = INJECTION_PERMISSION_DENIED;        }    }    // Update final pieces of touch state if the injector had permission.    if (injectionPermission == INJECTION_PERMISSION_GRANTED) {        if (!wrongDevice) {            if (switchedDevice) {#if DEBUG_FOCUS                ALOGD("Conflicting pointer actions: Switched to a different device.");#endif                *outConflictingPointerActions = true;            }            if (isHoverAction) {                // Started hovering, therefore no longer down.                if (oldState && oldState->down) {#if DEBUG_FOCUS                    ALOGD("Conflicting pointer actions: Hover received while pointer was down.");#endif                    *outConflictingPointerActions = true;                }                mTempTouchState.reset();                if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||                    maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {                    mTempTouchState.deviceId = entry->deviceId;                    mTempTouchState.source = entry->source;                    mTempTouchState.displayId = displayId;                }            } else if (maskedAction == AMOTION_EVENT_ACTION_UP ||                       maskedAction == AMOTION_EVENT_ACTION_CANCEL) {                // All pointers up or canceled.                mTempTouchState.reset();            } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {                // First pointer went down.                if (oldState && oldState->down) {#if DEBUG_FOCUS                    ALOGD("Conflicting pointer actions: Down received while already down.");#endif                    *outConflictingPointerActions = true;                }            } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {                // One pointer went up.                if (isSplit) {                    int32_t pointerIndex = getMotionEventActionPointerIndex(action);                    uint32_t pointerId = entry->pointerProperties[pointerIndex].id;                    for (size_t i = 0; i < mTempTouchState.windows.size();) {                        TouchedWindow& touchedWindow = mTempTouchState.windows[i];                        if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) {                            touchedWindow.pointerIds.clearBit(pointerId);                            if (touchedWindow.pointerIds.isEmpty()) {                                mTempTouchState.windows.erase(mTempTouchState.windows.begin() + i);                                continue;                            }                        }                        i += 1;                    }                }            }            // Save changes unless the action was scroll in which case the temporary touch            // state was only valid for this one action.            if (maskedAction != AMOTION_EVENT_ACTION_SCROLL) {                if (mTempTouchState.displayId >= 0) {                    if (oldStateIndex >= 0) {                        mTouchStatesByDisplay.editValueAt(oldStateIndex).copyFrom(mTempTouchState);                    } else {                        mTouchStatesByDisplay.add(displayId, mTempTouchState);                    }                } else if (oldStateIndex >= 0) {                    mTouchStatesByDisplay.removeItemsAt(oldStateIndex);                }            }            // Update hover state.            mLastHoverWindowHandle = newHoverWindowHandle;        }    } else {#if DEBUG_FOCUS        ALOGD("Not updating touch focus because injection was denied.");#endif    }Unresponsive:    // Reset temporary touch state to ensure we release unnecessary references to input channels.    mTempTouchState.reset();    nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);    updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication);#if DEBUG_FOCUS    ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, "          "timeSpentWaitingForApplication=%0.1fms",          injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0);#endif    return injectionResult;}

 

sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, int32_t x,                                                                 int32_t y, bool addOutsideTargets,                                                                 bool addPortalWindows) {    // Traverse windows from front to back to find touched window.    //根据触摸点的信息,获取对应的显示屏的所有窗口    const std::vector> windowHandles = getWindowHandlesLocked(displayId);    for (const sp& windowHandle : windowHandles) {        const InputWindowInfo* windowInfo = windowHandle->getInfo();        if (windowInfo->displayId == displayId) {            int32_t flags = windowInfo->layoutParamsFlags;            if (windowInfo->visible) {                if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) {                    bool isTouchModal = (flags &                                         (InputWindowInfo::FLAG_NOT_FOCUSABLE |                                          InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0;                    if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) {                        int32_t portalToDisplayId = windowInfo->portalToDisplayId;                        if (portalToDisplayId != ADISPLAY_ID_NONE &&                            portalToDisplayId != displayId) {                            if (addPortalWindows) {                                // For the monitoring channels of the display.                                mTempTouchState.addPortalWindow(windowHandle);                            }                            return findTouchedWindowAtLocked(portalToDisplayId, x, y,                                                             addOutsideTargets, addPortalWindows);                        }                        // Found window.                        return windowHandle;                    }                }                if (addOutsideTargets && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) {                    mTempTouchState.addOrUpdateWindow(windowHandle,                                                      InputTarget::FLAG_DISPATCH_AS_OUTSIDE,                                                      BitSet32(0));                }            }        }    }    return nullptr;}

 

 

void InputDispatcher::addWindowTargetLocked(const sp& windowHandle,                                            int32_t targetFlags, BitSet32 pointerIds,                                            std::vector& inputTargets) {    sp inputChannel = getInputChannelLocked(windowHandle->getToken());    if (inputChannel == nullptr) {        ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());        return;    }    const InputWindowInfo* windowInfo = windowHandle->getInfo();    InputTarget target;    target.inputChannel = inputChannel;    target.flags = targetFlags;    target.xOffset = -windowInfo->frameLeft;    target.yOffset = -windowInfo->frameTop;    target.globalScaleFactor = windowInfo->globalScaleFactor;    target.windowXScale = windowInfo->windowXScale;    target.windowYScale = windowInfo->windowYScale;    target.pointerIds = pointerIds;    inputTargets.push_back(target);}

 

 

 

void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {    int32_t displayId = getTargetDisplayId(eventEntry);//更具事件获取到对应的屏幕设备    sp focusedWindowHandle =            getValueByKey(mFocusedWindowHandlesByDisplay, displayId);//获取该屏幕上的聚焦窗口    if (focusedWindowHandle != nullptr) {        const InputWindowInfo* info = focusedWindowHandle->getInfo();        if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) {#if DEBUG_DISPATCH_CYCLE            ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str());#endif            return;        }    }    int32_t eventType = USER_ACTIVITY_EVENT_OTHER;    switch (eventEntry->type) {        case EventEntry::TYPE_MOTION: {            const MotionEntry* motionEntry = static_cast(eventEntry);            if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) {                return;            }            if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) {                eventType = USER_ACTIVITY_EVENT_TOUCH;            }            break;        }        case EventEntry::TYPE_KEY: {            const KeyEntry* keyEntry = static_cast(eventEntry);            if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) {                return;            }            eventType = USER_ACTIVITY_EVENT_BUTTON;            break;        }    }    //此处发送一个命令来执行doPokeUserActivityLockedInterruptible方法    CommandEntry* commandEntry =            postCommandLocked(&InputDispatcher::doPokeUserActivityLockedInterruptible);    commandEntry->eventTime = eventEntry->eventTime;    commandEntry->userActivityEventType = eventType;}
void InputDispatcher::releasePendingEventLocked() {    if (mPendingEvent) {        resetANRTimeoutsLocked();        releaseInboundEventLocked(mPendingEvent);        mPendingEvent = nullptr;    }}

更多相关文章

  1. Android Debug Bridge命令介绍
  2. android cmd adb命令安装和删除apk应用
  3. Android命令Monkey压力测试,详解
  4. android按键焦点事件分析(应用开发篇)
  5. android全平台编译ffmpeg支持命令行实践
  6. Android:使用命令行工具adb、mksdcard等

随机推荐

  1. 开发随笔-移动开发小结
  2. Android中ListView通过ContextMenu删除当
  3. 关于lottie的那点事
  4. Android之Picasso
  5. 如何成功运行和导入别人的android studio
  6. android 隐藏手机底部虚拟按键
  7. android 2D skia库api简单应用
  8. 多种方式实现Android定时任务,哪一款是你
  9. android中布局 padding gravity margin的
  10. UI(一) 适应屏幕设备多样化