Loading services/inputflinger/InputDispatcher.cpp +163 −46 Original line number Diff line number Diff line Loading @@ -235,6 +235,12 @@ static void dumpRegion(std::string& dump, const Region& region) { } } template<typename T, typename U> static T getValueByKey(std::unordered_map<U, T>& map, U key) { typename std::unordered_map<U, T>::const_iterator it = map.find(key); return it != map.end() ? it->second : T{}; } // --- InputDispatcher --- Loading @@ -244,6 +250,7 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), mNextUnblockedEvent(nullptr), mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), mFocusedDisplayId(ADISPLAY_ID_DEFAULT), mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { mLooper = new Looper(false); Loading Loading @@ -808,8 +815,10 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); if (mFocusedWindowHandle != nullptr) { commandEntry->inputWindowHandle = mFocusedWindowHandle; sp<InputWindowHandle> focusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry)); if (focusedWindowHandle != nullptr) { commandEntry->inputWindowHandle = focusedWindowHandle; } commandEntry->keyEntry = entry; entry->refCount += 1; Loading Loading @@ -1108,17 +1117,49 @@ void InputDispatcher::resetANRTimeoutsLocked() { mInputTargetWaitApplicationHandle.clear(); } /** * Get the display id that the given event should go to. If this event specifies a valid display id, * then it should be dispatched to that display. Otherwise, the event goes to the focused display. * Focused display is the display that the user most recently interacted with. */ int32_t InputDispatcher::getTargetDisplayId(const EventEntry* entry) { int32_t displayId; switch (entry->type) { case EventEntry::TYPE_KEY: { const KeyEntry* typedEntry = static_cast<const KeyEntry*>(entry); displayId = typedEntry->displayId; break; } case EventEntry::TYPE_MOTION: { const MotionEntry* typedEntry = static_cast<const MotionEntry*>(entry); displayId = typedEntry->displayId; break; } default: { ALOGE("Unsupported event type '%" PRId32 "' for target display.", entry->type); return ADISPLAY_ID_NONE; } } return displayId == ADISPLAY_ID_NONE ? mFocusedDisplayId : displayId; } int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) { int32_t injectionResult; std::string reason; int32_t displayId = getTargetDisplayId(entry); sp<InputWindowHandle> focusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, displayId); sp<InputApplicationHandle> focusedApplicationHandle = getValueByKey(mFocusedApplicationHandlesByDisplay, displayId); // If there is no currently focused window and no focused application // then drop the event. if (mFocusedWindowHandle == nullptr) { if (mFocusedApplicationHandle != nullptr) { if (focusedWindowHandle == nullptr) { if (focusedApplicationHandle != nullptr) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, nullptr, nextWakeupTime, focusedApplicationHandle, nullptr, nextWakeupTime, "Waiting because no window has focus but there is a " "focused application that may eventually add a window " "when it finishes starting up."); Loading @@ -1131,23 +1172,23 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, } // Check permissions. if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) { if (!checkInjectionPermission(focusedWindowHandle, entry->injectionState)) { injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; goto Failed; } // Check whether the window is ready for more input. reason = checkWindowReadyForMoreInputLocked(currentTime, mFocusedWindowHandle, entry, "focused"); focusedWindowHandle, entry, "focused"); if (!reason.empty()) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.c_str()); focusedApplicationHandle, focusedWindowHandle, nextWakeupTime, reason.c_str()); goto Unresponsive; } // Success! Output targets. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; addWindowTargetLocked(mFocusedWindowHandle, addWindowTargetLocked(focusedWindowHandle, InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0), inputTargets); Loading Loading @@ -1802,8 +1843,11 @@ std::string InputDispatcher::getApplicationWindowLabelLocked( } void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { if (mFocusedWindowHandle != nullptr) { const InputWindowInfo* info = mFocusedWindowHandle->getInfo(); int32_t displayId = getTargetDisplayId(eventEntry); sp<InputWindowHandle> 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()); Loading Loading @@ -2978,18 +3022,7 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& input // Copy old handles for release if they are no longer present. const Vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId); // TODO(b/111361570): multi-display focus, one focus window per display. sp<InputWindowHandle> newFocusedWindowHandle = mFocusedWindowHandle; // Reset newFocusedWindowHandle to nullptr if current display own the focus window, // that will be updated below when going through all window handles in current display. // And if list of window handles becomes empty then it will be updated by other display. if (mFocusedWindowHandle != nullptr) { const InputWindowInfo* info = mFocusedWindowHandle->getInfo(); if (info == nullptr || info->displayId == displayId) { newFocusedWindowHandle = nullptr; } } sp<InputWindowHandle> newFocusedWindowHandle = nullptr; bool foundHoveredWindow = false; if (inputWindowHandles.isEmpty()) { Loading Loading @@ -3026,28 +3059,31 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& input mLastHoverWindowHandle = nullptr; } // TODO(b/111361570): multi-display focus, one focus in all display in current. if (mFocusedWindowHandle != newFocusedWindowHandle) { if (mFocusedWindowHandle != nullptr) { sp<InputWindowHandle> oldFocusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, displayId); if (oldFocusedWindowHandle != newFocusedWindowHandle) { if (oldFocusedWindowHandle != nullptr) { #if DEBUG_FOCUS ALOGD("Focus left window: %s", mFocusedWindowHandle->getName().c_str()); oldFocusedWindowHandle->getName().c_str()); #endif sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel(); sp<InputChannel> focusedInputChannel = oldFocusedWindowHandle->getInputChannel(); if (focusedInputChannel != nullptr) { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, "focus left window"); synthesizeCancelationEventsForInputChannelLocked( focusedInputChannel, options); } mFocusedWindowHandlesByDisplay.erase(displayId); } if (newFocusedWindowHandle != nullptr) { #if DEBUG_FOCUS ALOGD("Focus entered window: %s", newFocusedWindowHandle->getName().c_str()); #endif mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle; } mFocusedWindowHandle = newFocusedWindowHandle; } ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId); Loading Loading @@ -3096,25 +3132,28 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& input } void InputDispatcher::setFocusedApplication( const sp<InputApplicationHandle>& inputApplicationHandle) { int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) { #if DEBUG_FOCUS ALOGD("setFocusedApplication"); #endif { // acquire lock AutoMutex _l(mLock); sp<InputApplicationHandle> oldFocusedApplicationHandle = getValueByKey(mFocusedApplicationHandlesByDisplay, displayId); if (inputApplicationHandle != nullptr && inputApplicationHandle->updateInfo()) { if (mFocusedApplicationHandle != inputApplicationHandle) { if (mFocusedApplicationHandle != nullptr) { if (oldFocusedApplicationHandle != inputApplicationHandle) { if (oldFocusedApplicationHandle != nullptr) { resetANRTimeoutsLocked(); mFocusedApplicationHandle->releaseInfo(); oldFocusedApplicationHandle->releaseInfo(); } mFocusedApplicationHandle = inputApplicationHandle; mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle; } } else if (mFocusedApplicationHandle != nullptr) { } else if (oldFocusedApplicationHandle != nullptr) { resetANRTimeoutsLocked(); mFocusedApplicationHandle->releaseInfo(); mFocusedApplicationHandle.clear(); oldFocusedApplicationHandle->releaseInfo(); oldFocusedApplicationHandle.clear(); mFocusedApplicationHandlesByDisplay.erase(displayId); } #if DEBUG_FOCUS Loading @@ -3126,6 +3165,62 @@ void InputDispatcher::setFocusedApplication( mLooper->wake(); } /** * Sets the focused display, which is responsible for receiving focus-dispatched input events where * the display not specified. * * We track any unreleased events for each window. If a window loses the ability to receive the * released event, we will send a cancel event to it. So when the focused display is changed, we * cancel all the unreleased display-unspecified events for the focused window on the old focused * display. The display-specified events won't be affected. */ void InputDispatcher::setFocusedDisplay(int32_t displayId) { #if DEBUG_FOCUS ALOGD("setFocusedDisplay displayId=%" PRId32, displayId); #endif { // acquire lock AutoMutex _l(mLock); if (mFocusedDisplayId != displayId) { sp<InputWindowHandle> oldFocusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId); if (oldFocusedWindowHandle != nullptr) { sp<InputChannel> inputChannel = oldFocusedWindowHandle->getInputChannel(); if (inputChannel != nullptr) { CancelationOptions options( CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS, "The display which contains this window no longer has focus."); synthesizeCancelationEventsForInputChannelLocked(inputChannel, options); } } mFocusedDisplayId = displayId; // Sanity check sp<InputWindowHandle> newFocusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, displayId); if (newFocusedWindowHandle == nullptr) { ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId); if (!mFocusedWindowHandlesByDisplay.empty()) { ALOGE("But another display has a focused window:"); for (auto& it : mFocusedWindowHandlesByDisplay) { const int32_t displayId = it.first; const sp<InputWindowHandle>& windowHandle = it.second; ALOGE("Display #%" PRId32 " has focused window: '%s'\n", displayId, windowHandle->getName().c_str()); } } } } #if DEBUG_FOCUS logDispatchStateLocked(); #endif } // release lock // Wake up poll loop since it may need to make new input dispatching choices. mLooper->wake(); } void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { #if DEBUG_FOCUS ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen); Loading @@ -3152,7 +3247,7 @@ void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { } #if DEBUG_FOCUS //logDispatchStateLocked(); logDispatchStateLocked(); #endif } // release lock Loading Loading @@ -3297,17 +3392,35 @@ void InputDispatcher::logDispatchStateLocked() { void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += StringPrintf(INDENT "DispatchEnabled: %d\n", mDispatchEnabled); dump += StringPrintf(INDENT "DispatchFrozen: %d\n", mDispatchFrozen); if (mFocusedApplicationHandle != nullptr) { dump += StringPrintf(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n", mFocusedApplicationHandle->getName().c_str(), mFocusedApplicationHandle->getDispatchingTimeout( dump += StringPrintf(INDENT "FocusedDisplayId: %" PRId32 "\n", mFocusedDisplayId); if (!mFocusedApplicationHandlesByDisplay.empty()) { dump += StringPrintf(INDENT "FocusedApplications:\n"); for (auto& it : mFocusedApplicationHandlesByDisplay) { const int32_t displayId = it.first; const sp<InputApplicationHandle>& applicationHandle = it.second; dump += StringPrintf( INDENT2 "displayId=%" PRId32 ", name='%s', dispatchingTimeout=%0.3fms\n", displayId, applicationHandle->getName().c_str(), applicationHandle->getDispatchingTimeout( DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0); } } else { dump += StringPrintf(INDENT "FocusedApplications: <none>\n"); } if (!mFocusedWindowHandlesByDisplay.empty()) { dump += StringPrintf(INDENT "FocusedWindows:\n"); for (auto& it : mFocusedWindowHandlesByDisplay) { const int32_t displayId = it.first; const sp<InputWindowHandle>& windowHandle = it.second; dump += StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n", displayId, windowHandle->getName().c_str()); } } else { dump += StringPrintf(INDENT "FocusedApplication: <null>\n"); dump += StringPrintf(INDENT "FocusedWindows: <none>\n"); } dump += StringPrintf(INDENT "FocusedWindow: name='%s'\n", mFocusedWindowHandle != nullptr ? mFocusedWindowHandle->getName().c_str() : "<null>"); if (!mTouchStatesByDisplay.isEmpty()) { dump += StringPrintf(INDENT "TouchStatesByDisplay:\n"); Loading Loading @@ -4527,6 +4640,8 @@ bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, return true; case CancelationOptions::CANCEL_FALLBACK_EVENTS: return memento.flags & AKEY_EVENT_FLAG_FALLBACK; case CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS: return memento.displayId == ADISPLAY_ID_NONE; default: return false; } Loading @@ -4545,6 +4660,8 @@ bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& mement return memento.source & AINPUT_SOURCE_CLASS_POINTER; case CancelationOptions::CANCEL_NON_POINTER_EVENTS: return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); case CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS: return memento.displayId == ADISPLAY_ID_NONE; default: return false; } Loading services/inputflinger/InputDispatcher.h +22 −6 Original line number Diff line number Diff line Loading @@ -311,12 +311,18 @@ public: virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles, int32_t displayId) = 0; /* Sets the focused application. /* Sets the focused application on the given display. * * This method may be called on any thread (usually by the input manager). */ virtual void setFocusedApplication( const sp<InputApplicationHandle>& inputApplicationHandle) = 0; int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) = 0; /* Sets the focused display. * * This method may be called on any thread (usually by the input manager). */ virtual void setFocusedDisplay(int32_t displayId) = 0; /* Sets the input dispatching mode. * Loading Loading @@ -391,7 +397,9 @@ public: virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles, int32_t displayId); virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle); virtual void setFocusedApplication(int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle); virtual void setFocusedDisplay(int32_t displayId); virtual void setInputDispatchMode(bool enabled, bool frozen); virtual void setInputFilterEnabled(bool enabled); Loading Loading @@ -686,6 +694,10 @@ private: CANCEL_POINTER_EVENTS = 1, CANCEL_NON_POINTER_EVENTS = 2, CANCEL_FALLBACK_EVENTS = 3, /* Cancel events where the display not specified. These events would go to the focused * display. */ CANCEL_DISPLAY_UNSPECIFIED_EVENTS = 4, }; // The criterion to use to determine which events should be canceled. Loading Loading @@ -966,7 +978,7 @@ private: bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const; // Focus tracking for keys, trackball, etc. sp<InputWindowHandle> mFocusedWindowHandle; std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay; // Focus tracking for touch. struct TouchedWindow { Loading Loading @@ -997,8 +1009,11 @@ private: KeyedVector<int32_t, TouchState> mTouchStatesByDisplay; TouchState mTempTouchState; // Focused application. sp<InputApplicationHandle> mFocusedApplicationHandle; // Focused applications. std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay; // Top focused display. int32_t mFocusedDisplayId; // Dispatcher state at time of last ANR. std::string mLastANRState; Loading Loading @@ -1046,6 +1061,7 @@ private: nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime); void resetANRTimeoutsLocked(); int32_t getTargetDisplayId(const EventEntry* entry); int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime); int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, Loading services/inputflinger/tests/InputDispatcher_test.cpp +20 −7 Original line number Diff line number Diff line Loading @@ -382,12 +382,13 @@ public: int32_t mDisplayId; }; static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher) { static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher, int32_t displayId = ADISPLAY_ID_NONE) { KeyEvent event; nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid key down event. event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId, AKEY_EVENT_ACTION_DOWN, /* flags */ 0, AKEYCODE_A, KEY_A, AMETA_NONE, /* repeatCount */ 0, currentTime, currentTime); Loading Loading @@ -466,7 +467,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_FocusedWindow) { sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second"); // Set focus application. mDispatcher->setFocusedApplication(application); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); // Expect one focus window exist in display. windowSecond->setFocus(); Loading Loading @@ -511,15 +512,21 @@ TEST_F(InputDispatcherTest, SetInputWindow_MultiDisplayTouch) { windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, SECOND_DISPLAY_ID); } // TODO(b/111361570): multi-display focus, one focus window per display. TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) { sp<FakeApplicationHandle> application = new FakeApplicationHandle(); sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1"); sp<FakeApplicationHandle> application2 = new FakeApplicationHandle(); sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2"); constexpr int32_t SECOND_DISPLAY_ID = 1; // Set focus to primary display window. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); windowInPrimary->setFocus(); // Set focus to second display window. mDispatcher->setFocusedApplication(application2); mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID); mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2); windowInSecondary->setFocus(); // Update all windows per displays. Loading @@ -527,13 +534,18 @@ TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) { inputWindowHandles.push(windowInPrimary); mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT); constexpr int32_t SECOND_DISPLAY_ID = 1; windowInSecondary->setDisplayId(SECOND_DISPLAY_ID); Vector<sp<InputWindowHandle>> inputWindowHandles_Second; inputWindowHandles_Second.push(windowInSecondary); mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID); // Test inject a key down. // Test inject a key down with display id specified. ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)) << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED"; windowInPrimary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_DEFAULT); windowInSecondary->assertNoEvents(); // Test inject a key down without display id specified. ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher)) << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED"; windowInPrimary->assertNoEvents(); Loading @@ -545,6 +557,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) { // Expect old focus should receive a cancel event. windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE); // TODO(b/111361570): Validate that the event here was marked as canceled. // Test inject a key down, should timeout because of no target window. ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher)) Loading Loading
services/inputflinger/InputDispatcher.cpp +163 −46 Original line number Diff line number Diff line Loading @@ -235,6 +235,12 @@ static void dumpRegion(std::string& dump, const Region& region) { } } template<typename T, typename U> static T getValueByKey(std::unordered_map<U, T>& map, U key) { typename std::unordered_map<U, T>::const_iterator it = map.find(key); return it != map.end() ? it->second : T{}; } // --- InputDispatcher --- Loading @@ -244,6 +250,7 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), mNextUnblockedEvent(nullptr), mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), mFocusedDisplayId(ADISPLAY_ID_DEFAULT), mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { mLooper = new Looper(false); Loading Loading @@ -808,8 +815,10 @@ bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { CommandEntry* commandEntry = postCommandLocked( & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); if (mFocusedWindowHandle != nullptr) { commandEntry->inputWindowHandle = mFocusedWindowHandle; sp<InputWindowHandle> focusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry)); if (focusedWindowHandle != nullptr) { commandEntry->inputWindowHandle = focusedWindowHandle; } commandEntry->keyEntry = entry; entry->refCount += 1; Loading Loading @@ -1108,17 +1117,49 @@ void InputDispatcher::resetANRTimeoutsLocked() { mInputTargetWaitApplicationHandle.clear(); } /** * Get the display id that the given event should go to. If this event specifies a valid display id, * then it should be dispatched to that display. Otherwise, the event goes to the focused display. * Focused display is the display that the user most recently interacted with. */ int32_t InputDispatcher::getTargetDisplayId(const EventEntry* entry) { int32_t displayId; switch (entry->type) { case EventEntry::TYPE_KEY: { const KeyEntry* typedEntry = static_cast<const KeyEntry*>(entry); displayId = typedEntry->displayId; break; } case EventEntry::TYPE_MOTION: { const MotionEntry* typedEntry = static_cast<const MotionEntry*>(entry); displayId = typedEntry->displayId; break; } default: { ALOGE("Unsupported event type '%" PRId32 "' for target display.", entry->type); return ADISPLAY_ID_NONE; } } return displayId == ADISPLAY_ID_NONE ? mFocusedDisplayId : displayId; } int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) { int32_t injectionResult; std::string reason; int32_t displayId = getTargetDisplayId(entry); sp<InputWindowHandle> focusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, displayId); sp<InputApplicationHandle> focusedApplicationHandle = getValueByKey(mFocusedApplicationHandlesByDisplay, displayId); // If there is no currently focused window and no focused application // then drop the event. if (mFocusedWindowHandle == nullptr) { if (mFocusedApplicationHandle != nullptr) { if (focusedWindowHandle == nullptr) { if (focusedApplicationHandle != nullptr) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, nullptr, nextWakeupTime, focusedApplicationHandle, nullptr, nextWakeupTime, "Waiting because no window has focus but there is a " "focused application that may eventually add a window " "when it finishes starting up."); Loading @@ -1131,23 +1172,23 @@ int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, } // Check permissions. if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) { if (!checkInjectionPermission(focusedWindowHandle, entry->injectionState)) { injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; goto Failed; } // Check whether the window is ready for more input. reason = checkWindowReadyForMoreInputLocked(currentTime, mFocusedWindowHandle, entry, "focused"); focusedWindowHandle, entry, "focused"); if (!reason.empty()) { injectionResult = handleTargetsNotReadyLocked(currentTime, entry, mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.c_str()); focusedApplicationHandle, focusedWindowHandle, nextWakeupTime, reason.c_str()); goto Unresponsive; } // Success! Output targets. injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; addWindowTargetLocked(mFocusedWindowHandle, addWindowTargetLocked(focusedWindowHandle, InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0), inputTargets); Loading Loading @@ -1802,8 +1843,11 @@ std::string InputDispatcher::getApplicationWindowLabelLocked( } void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { if (mFocusedWindowHandle != nullptr) { const InputWindowInfo* info = mFocusedWindowHandle->getInfo(); int32_t displayId = getTargetDisplayId(eventEntry); sp<InputWindowHandle> 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()); Loading Loading @@ -2978,18 +3022,7 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& input // Copy old handles for release if they are no longer present. const Vector<sp<InputWindowHandle>> oldWindowHandles = getWindowHandlesLocked(displayId); // TODO(b/111361570): multi-display focus, one focus window per display. sp<InputWindowHandle> newFocusedWindowHandle = mFocusedWindowHandle; // Reset newFocusedWindowHandle to nullptr if current display own the focus window, // that will be updated below when going through all window handles in current display. // And if list of window handles becomes empty then it will be updated by other display. if (mFocusedWindowHandle != nullptr) { const InputWindowInfo* info = mFocusedWindowHandle->getInfo(); if (info == nullptr || info->displayId == displayId) { newFocusedWindowHandle = nullptr; } } sp<InputWindowHandle> newFocusedWindowHandle = nullptr; bool foundHoveredWindow = false; if (inputWindowHandles.isEmpty()) { Loading Loading @@ -3026,28 +3059,31 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& input mLastHoverWindowHandle = nullptr; } // TODO(b/111361570): multi-display focus, one focus in all display in current. if (mFocusedWindowHandle != newFocusedWindowHandle) { if (mFocusedWindowHandle != nullptr) { sp<InputWindowHandle> oldFocusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, displayId); if (oldFocusedWindowHandle != newFocusedWindowHandle) { if (oldFocusedWindowHandle != nullptr) { #if DEBUG_FOCUS ALOGD("Focus left window: %s", mFocusedWindowHandle->getName().c_str()); oldFocusedWindowHandle->getName().c_str()); #endif sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel(); sp<InputChannel> focusedInputChannel = oldFocusedWindowHandle->getInputChannel(); if (focusedInputChannel != nullptr) { CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, "focus left window"); synthesizeCancelationEventsForInputChannelLocked( focusedInputChannel, options); } mFocusedWindowHandlesByDisplay.erase(displayId); } if (newFocusedWindowHandle != nullptr) { #if DEBUG_FOCUS ALOGD("Focus entered window: %s", newFocusedWindowHandle->getName().c_str()); #endif mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle; } mFocusedWindowHandle = newFocusedWindowHandle; } ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(displayId); Loading Loading @@ -3096,25 +3132,28 @@ void InputDispatcher::setInputWindows(const Vector<sp<InputWindowHandle>>& input } void InputDispatcher::setFocusedApplication( const sp<InputApplicationHandle>& inputApplicationHandle) { int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) { #if DEBUG_FOCUS ALOGD("setFocusedApplication"); #endif { // acquire lock AutoMutex _l(mLock); sp<InputApplicationHandle> oldFocusedApplicationHandle = getValueByKey(mFocusedApplicationHandlesByDisplay, displayId); if (inputApplicationHandle != nullptr && inputApplicationHandle->updateInfo()) { if (mFocusedApplicationHandle != inputApplicationHandle) { if (mFocusedApplicationHandle != nullptr) { if (oldFocusedApplicationHandle != inputApplicationHandle) { if (oldFocusedApplicationHandle != nullptr) { resetANRTimeoutsLocked(); mFocusedApplicationHandle->releaseInfo(); oldFocusedApplicationHandle->releaseInfo(); } mFocusedApplicationHandle = inputApplicationHandle; mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle; } } else if (mFocusedApplicationHandle != nullptr) { } else if (oldFocusedApplicationHandle != nullptr) { resetANRTimeoutsLocked(); mFocusedApplicationHandle->releaseInfo(); mFocusedApplicationHandle.clear(); oldFocusedApplicationHandle->releaseInfo(); oldFocusedApplicationHandle.clear(); mFocusedApplicationHandlesByDisplay.erase(displayId); } #if DEBUG_FOCUS Loading @@ -3126,6 +3165,62 @@ void InputDispatcher::setFocusedApplication( mLooper->wake(); } /** * Sets the focused display, which is responsible for receiving focus-dispatched input events where * the display not specified. * * We track any unreleased events for each window. If a window loses the ability to receive the * released event, we will send a cancel event to it. So when the focused display is changed, we * cancel all the unreleased display-unspecified events for the focused window on the old focused * display. The display-specified events won't be affected. */ void InputDispatcher::setFocusedDisplay(int32_t displayId) { #if DEBUG_FOCUS ALOGD("setFocusedDisplay displayId=%" PRId32, displayId); #endif { // acquire lock AutoMutex _l(mLock); if (mFocusedDisplayId != displayId) { sp<InputWindowHandle> oldFocusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, mFocusedDisplayId); if (oldFocusedWindowHandle != nullptr) { sp<InputChannel> inputChannel = oldFocusedWindowHandle->getInputChannel(); if (inputChannel != nullptr) { CancelationOptions options( CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS, "The display which contains this window no longer has focus."); synthesizeCancelationEventsForInputChannelLocked(inputChannel, options); } } mFocusedDisplayId = displayId; // Sanity check sp<InputWindowHandle> newFocusedWindowHandle = getValueByKey(mFocusedWindowHandlesByDisplay, displayId); if (newFocusedWindowHandle == nullptr) { ALOGW("Focused display #%" PRId32 " does not have a focused window.", displayId); if (!mFocusedWindowHandlesByDisplay.empty()) { ALOGE("But another display has a focused window:"); for (auto& it : mFocusedWindowHandlesByDisplay) { const int32_t displayId = it.first; const sp<InputWindowHandle>& windowHandle = it.second; ALOGE("Display #%" PRId32 " has focused window: '%s'\n", displayId, windowHandle->getName().c_str()); } } } } #if DEBUG_FOCUS logDispatchStateLocked(); #endif } // release lock // Wake up poll loop since it may need to make new input dispatching choices. mLooper->wake(); } void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { #if DEBUG_FOCUS ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen); Loading @@ -3152,7 +3247,7 @@ void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { } #if DEBUG_FOCUS //logDispatchStateLocked(); logDispatchStateLocked(); #endif } // release lock Loading Loading @@ -3297,17 +3392,35 @@ void InputDispatcher::logDispatchStateLocked() { void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += StringPrintf(INDENT "DispatchEnabled: %d\n", mDispatchEnabled); dump += StringPrintf(INDENT "DispatchFrozen: %d\n", mDispatchFrozen); if (mFocusedApplicationHandle != nullptr) { dump += StringPrintf(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n", mFocusedApplicationHandle->getName().c_str(), mFocusedApplicationHandle->getDispatchingTimeout( dump += StringPrintf(INDENT "FocusedDisplayId: %" PRId32 "\n", mFocusedDisplayId); if (!mFocusedApplicationHandlesByDisplay.empty()) { dump += StringPrintf(INDENT "FocusedApplications:\n"); for (auto& it : mFocusedApplicationHandlesByDisplay) { const int32_t displayId = it.first; const sp<InputApplicationHandle>& applicationHandle = it.second; dump += StringPrintf( INDENT2 "displayId=%" PRId32 ", name='%s', dispatchingTimeout=%0.3fms\n", displayId, applicationHandle->getName().c_str(), applicationHandle->getDispatchingTimeout( DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0); } } else { dump += StringPrintf(INDENT "FocusedApplications: <none>\n"); } if (!mFocusedWindowHandlesByDisplay.empty()) { dump += StringPrintf(INDENT "FocusedWindows:\n"); for (auto& it : mFocusedWindowHandlesByDisplay) { const int32_t displayId = it.first; const sp<InputWindowHandle>& windowHandle = it.second; dump += StringPrintf(INDENT2 "displayId=%" PRId32 ", name='%s'\n", displayId, windowHandle->getName().c_str()); } } else { dump += StringPrintf(INDENT "FocusedApplication: <null>\n"); dump += StringPrintf(INDENT "FocusedWindows: <none>\n"); } dump += StringPrintf(INDENT "FocusedWindow: name='%s'\n", mFocusedWindowHandle != nullptr ? mFocusedWindowHandle->getName().c_str() : "<null>"); if (!mTouchStatesByDisplay.isEmpty()) { dump += StringPrintf(INDENT "TouchStatesByDisplay:\n"); Loading Loading @@ -4527,6 +4640,8 @@ bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, return true; case CancelationOptions::CANCEL_FALLBACK_EVENTS: return memento.flags & AKEY_EVENT_FLAG_FALLBACK; case CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS: return memento.displayId == ADISPLAY_ID_NONE; default: return false; } Loading @@ -4545,6 +4660,8 @@ bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& mement return memento.source & AINPUT_SOURCE_CLASS_POINTER; case CancelationOptions::CANCEL_NON_POINTER_EVENTS: return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); case CancelationOptions::CANCEL_DISPLAY_UNSPECIFIED_EVENTS: return memento.displayId == ADISPLAY_ID_NONE; default: return false; } Loading
services/inputflinger/InputDispatcher.h +22 −6 Original line number Diff line number Diff line Loading @@ -311,12 +311,18 @@ public: virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles, int32_t displayId) = 0; /* Sets the focused application. /* Sets the focused application on the given display. * * This method may be called on any thread (usually by the input manager). */ virtual void setFocusedApplication( const sp<InputApplicationHandle>& inputApplicationHandle) = 0; int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) = 0; /* Sets the focused display. * * This method may be called on any thread (usually by the input manager). */ virtual void setFocusedDisplay(int32_t displayId) = 0; /* Sets the input dispatching mode. * Loading Loading @@ -391,7 +397,9 @@ public: virtual void setInputWindows(const Vector<sp<InputWindowHandle> >& inputWindowHandles, int32_t displayId); virtual void setFocusedApplication(const sp<InputApplicationHandle>& inputApplicationHandle); virtual void setFocusedApplication(int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle); virtual void setFocusedDisplay(int32_t displayId); virtual void setInputDispatchMode(bool enabled, bool frozen); virtual void setInputFilterEnabled(bool enabled); Loading Loading @@ -686,6 +694,10 @@ private: CANCEL_POINTER_EVENTS = 1, CANCEL_NON_POINTER_EVENTS = 2, CANCEL_FALLBACK_EVENTS = 3, /* Cancel events where the display not specified. These events would go to the focused * display. */ CANCEL_DISPLAY_UNSPECIFIED_EVENTS = 4, }; // The criterion to use to determine which events should be canceled. Loading Loading @@ -966,7 +978,7 @@ private: bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const; // Focus tracking for keys, trackball, etc. sp<InputWindowHandle> mFocusedWindowHandle; std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay; // Focus tracking for touch. struct TouchedWindow { Loading Loading @@ -997,8 +1009,11 @@ private: KeyedVector<int32_t, TouchState> mTouchStatesByDisplay; TouchState mTempTouchState; // Focused application. sp<InputApplicationHandle> mFocusedApplicationHandle; // Focused applications. std::unordered_map<int32_t, sp<InputApplicationHandle>> mFocusedApplicationHandlesByDisplay; // Top focused display. int32_t mFocusedDisplayId; // Dispatcher state at time of last ANR. std::string mLastANRState; Loading Loading @@ -1046,6 +1061,7 @@ private: nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime); void resetANRTimeoutsLocked(); int32_t getTargetDisplayId(const EventEntry* entry); int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime); int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, Loading
services/inputflinger/tests/InputDispatcher_test.cpp +20 −7 Original line number Diff line number Diff line Loading @@ -382,12 +382,13 @@ public: int32_t mDisplayId; }; static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher) { static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher, int32_t displayId = ADISPLAY_ID_NONE) { KeyEvent event; nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC); // Define a valid key down event. event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE, event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, displayId, AKEY_EVENT_ACTION_DOWN, /* flags */ 0, AKEYCODE_A, KEY_A, AMETA_NONE, /* repeatCount */ 0, currentTime, currentTime); Loading Loading @@ -466,7 +467,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_FocusedWindow) { sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second"); // Set focus application. mDispatcher->setFocusedApplication(application); mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); // Expect one focus window exist in display. windowSecond->setFocus(); Loading Loading @@ -511,15 +512,21 @@ TEST_F(InputDispatcherTest, SetInputWindow_MultiDisplayTouch) { windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_MOTION, SECOND_DISPLAY_ID); } // TODO(b/111361570): multi-display focus, one focus window per display. TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) { sp<FakeApplicationHandle> application = new FakeApplicationHandle(); sp<FakeWindowHandle> windowInPrimary = new FakeWindowHandle(application, mDispatcher, "D_1"); sp<FakeApplicationHandle> application2 = new FakeApplicationHandle(); sp<FakeWindowHandle> windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2"); constexpr int32_t SECOND_DISPLAY_ID = 1; // Set focus to primary display window. mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application); windowInPrimary->setFocus(); // Set focus to second display window. mDispatcher->setFocusedApplication(application2); mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID); mDispatcher->setFocusedApplication(SECOND_DISPLAY_ID, application2); windowInSecondary->setFocus(); // Update all windows per displays. Loading @@ -527,13 +534,18 @@ TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) { inputWindowHandles.push(windowInPrimary); mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT); constexpr int32_t SECOND_DISPLAY_ID = 1; windowInSecondary->setDisplayId(SECOND_DISPLAY_ID); Vector<sp<InputWindowHandle>> inputWindowHandles_Second; inputWindowHandles_Second.push(windowInSecondary); mDispatcher->setInputWindows(inputWindowHandles_Second, SECOND_DISPLAY_ID); // Test inject a key down. // Test inject a key down with display id specified. ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT)) << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED"; windowInPrimary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_DEFAULT); windowInSecondary->assertNoEvents(); // Test inject a key down without display id specified. ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher)) << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED"; windowInPrimary->assertNoEvents(); Loading @@ -545,6 +557,7 @@ TEST_F(InputDispatcherTest, SetInputWindow_FocusedInMultiDisplay) { // Expect old focus should receive a cancel event. windowInSecondary->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE); // TODO(b/111361570): Validate that the event here was marked as canceled. // Test inject a key down, should timeout because of no target window. ASSERT_EQ(INPUT_EVENT_INJECTION_TIMED_OUT, injectKeyDown(mDispatcher)) Loading