一张图带你掌握Android Q上InputDispatcher事件分发流程(系统层)
16lz
2021-01-23
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; }}
更多相关文章
- Android Debug Bridge命令介绍
- android cmd adb命令安装和删除apk应用
- Android命令Monkey压力测试,详解
- android按键焦点事件分析(应用开发篇)
- android全平台编译ffmpeg支持命令行实践
- Android:使用命令行工具adb、mksdcard等