Loading services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -96,6 +96,8 @@ private: void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {} void setPointerCapture(bool enabled) override {} InputDispatcherConfiguration mConfig; }; Loading services/inputflinger/dispatcher/Entry.cpp +16 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,22 @@ std::string FocusEntry::getDescription() const { return StringPrintf("FocusEvent(hasFocus=%s)", hasFocus ? "true" : "false"); } // --- PointerCaptureChangedEntry --- // PointerCaptureChanged notifications always go to apps, so set the flag POLICY_FLAG_PASS_TO_USER // for all entries. PointerCaptureChangedEntry::PointerCaptureChangedEntry(int32_t id, nsecs_t eventTime, bool hasPointerCapture) : EventEntry(id, Type::POINTER_CAPTURE_CHANGED, eventTime, POLICY_FLAG_PASS_TO_USER), pointerCaptureEnabled(hasPointerCapture) {} PointerCaptureChangedEntry::~PointerCaptureChangedEntry() {} std::string PointerCaptureChangedEntry::getDescription() const { return StringPrintf("PointerCaptureChangedEvent(pointerCaptureEnabled=%s)", pointerCaptureEnabled ? "true" : "false"); } // --- KeyEntry --- KeyEntry::KeyEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, Loading services/inputflinger/dispatcher/Entry.h +13 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ struct EventEntry { FOCUS, KEY, MOTION, POINTER_CAPTURE_CHANGED, }; static const char* typeToString(Type type) { Loading @@ -50,6 +51,8 @@ struct EventEntry { return "KEY"; case Type::MOTION: return "MOTION"; case Type::POINTER_CAPTURE_CHANGED: return "POINTER_CAPTURE_CHANGED"; } } Loading Loading @@ -115,6 +118,15 @@ struct FocusEntry : EventEntry { virtual ~FocusEntry(); }; struct PointerCaptureChangedEntry : EventEntry { bool pointerCaptureEnabled; PointerCaptureChangedEntry(int32_t id, nsecs_t eventTime, bool hasPointerCapture); std::string getDescription() const override; virtual ~PointerCaptureChangedEntry(); }; struct KeyEntry : EventEntry { int32_t deviceId; uint32_t source; Loading Loading @@ -254,6 +266,7 @@ struct CommandEntry { sp<IBinder> oldToken; sp<IBinder> newToken; std::string obscuringPackage; bool enabled; }; } // namespace android::inputdispatcher Loading services/inputflinger/dispatcher/InputDispatcher.cpp +212 −9 Original line number Diff line number Diff line Loading @@ -454,6 +454,8 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mInTouchMode(true), mMaximumObscuringOpacityForTouch(1.0f), mFocusedDisplayId(ADISPLAY_ID_DEFAULT), mFocusedWindowRequestedPointerCapture(false), mWindowTokenWithPointerCapture(nullptr), mCompatService(getCompatService()) { mLooper = new Looper(false); mReporter = createInputReporter(); Loading Loading @@ -713,6 +715,14 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { break; } case EventEntry::Type::POINTER_CAPTURE_CHANGED: { const auto typedEntry = std::static_pointer_cast<PointerCaptureChangedEntry>(mPendingEvent); dispatchPointerCaptureChangedLocked(currentTime, typedEntry, dropReason); done = true; break; } case EventEntry::Type::KEY: { std::shared_ptr<KeyEntry> keyEntry = std::static_pointer_cast<KeyEntry>(mPendingEvent); if (isAppSwitchDue) { Loading Loading @@ -862,7 +872,8 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE break; } case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { case EventEntry::Type::DEVICE_RESET: case EventEntry::Type::POINTER_CAPTURE_CHANGED: { // nothing to do break; } Loading Loading @@ -968,6 +979,10 @@ void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason ALOGI("Dropped event because it is stale."); reason = "inbound event was dropped because it is stale"; break; case DropReason::NO_POINTER_CAPTURE: ALOGI("Dropped event because there is no window with Pointer Capture."); reason = "inbound event was dropped because there is no window with Pointer Capture"; break; case DropReason::NOT_DROPPED: { LOG_ALWAYS_FATAL("Should not be dropping a NOT_DROPPED event"); return; Loading @@ -991,6 +1006,9 @@ void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason } break; } case EventEntry::Type::POINTER_CAPTURE_CHANGED: { break; } case EventEntry::Type::FOCUS: case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { Loading Loading @@ -1176,6 +1194,55 @@ void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime, std::shared_ptr<F dispatchEventLocked(currentTime, entry, {target}); } void InputDispatcher::dispatchPointerCaptureChangedLocked( nsecs_t currentTime, const std::shared_ptr<PointerCaptureChangedEntry>& entry, DropReason& dropReason) { const bool haveWindowWithPointerCapture = mWindowTokenWithPointerCapture != nullptr; if (entry->pointerCaptureEnabled == haveWindowWithPointerCapture) { LOG_ALWAYS_FATAL_IF(mFocusedWindowRequestedPointerCapture, "The Pointer Capture state has already been dispatched to the window."); // Pointer capture was already forcefully disabled because of focus change. dropReason = DropReason::NOT_DROPPED; return; } // Set drop reason for early returns dropReason = DropReason::NO_POINTER_CAPTURE; sp<IBinder> token; if (entry->pointerCaptureEnabled) { // Enable Pointer Capture if (!mFocusedWindowRequestedPointerCapture) { // This can happen if a window requests capture and immediately releases capture. ALOGW("No window requested Pointer Capture."); return; } token = getValueByKey(mFocusedWindowTokenByDisplay, mFocusedDisplayId); LOG_ALWAYS_FATAL_IF(!token, "Cannot find focused window for Pointer Capture."); mWindowTokenWithPointerCapture = token; } else { // Disable Pointer Capture token = mWindowTokenWithPointerCapture; mWindowTokenWithPointerCapture = nullptr; mFocusedWindowRequestedPointerCapture = false; } auto channel = getInputChannelLocked(token); if (channel == nullptr) { // Window has gone away, clean up Pointer Capture state. mWindowTokenWithPointerCapture = nullptr; mFocusedWindowRequestedPointerCapture = false; return; } InputTarget target; target.inputChannel = channel; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; entry->dispatchInProgress = true; dispatchEventLocked(currentTime, entry, {target}); dropReason = DropReason::NOT_DROPPED; } bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { // Preprocessing. Loading Loading @@ -1483,6 +1550,7 @@ int32_t InputDispatcher::getTargetDisplayId(const EventEntry& entry) { displayId = motionEntry.displayId; break; } case EventEntry::Type::POINTER_CAPTURE_CHANGED: case EventEntry::Type::FOCUS: case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { Loading Loading @@ -2366,8 +2434,10 @@ std::string InputDispatcher::getApplicationWindowLabel( } void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { if (eventEntry.type == EventEntry::Type::FOCUS) { // Focus events are passed to apps, but do not represent user activity. if (eventEntry.type == EventEntry::Type::FOCUS || eventEntry.type == EventEntry::Type::POINTER_CAPTURE_CHANGED) { // Focus or pointer capture changed events are passed to apps, but do not represent user // activity. return; } int32_t displayId = getTargetDisplayId(eventEntry); Loading Loading @@ -2405,7 +2475,8 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { } case EventEntry::Type::FOCUS: case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { case EventEntry::Type::DEVICE_RESET: case EventEntry::Type::POINTER_CAPTURE_CHANGED: { LOG_ALWAYS_FATAL("%s events are not user activity", EventEntry::typeToString(eventEntry.type)); break; Loading Loading @@ -2617,7 +2688,8 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connectio break; } case EventEntry::Type::FOCUS: { case EventEntry::Type::FOCUS: case EventEntry::Type::POINTER_CAPTURE_CHANGED: { break; } case EventEntry::Type::CONFIGURATION_CHANGED: Loading Loading @@ -2821,6 +2893,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, reportTouchEventForStatistics(motionEntry); break; } case EventEntry::Type::FOCUS: { const FocusEntry& focusEntry = static_cast<const FocusEntry&>(eventEntry); status = connection->inputPublisher.publishFocusEvent(dispatchEntry->seq, Loading @@ -2830,6 +2903,15 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, break; } case EventEntry::Type::POINTER_CAPTURE_CHANGED: { const auto& captureEntry = static_cast<const PointerCaptureChangedEntry&>(eventEntry); status = connection->inputPublisher .publishCaptureEvent(dispatchEntry->seq, captureEntry.id, captureEntry.pointerCaptureEnabled); break; } case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { LOG_ALWAYS_FATAL("Should never start dispatch cycles for %s events", Loading Loading @@ -3124,8 +3206,10 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( static_cast<const MotionEntry&>(*cancelationEventEntry)); break; } case EventEntry::Type::FOCUS: { LOG_ALWAYS_FATAL("Canceling focus events is not supported"); case EventEntry::Type::FOCUS: case EventEntry::Type::POINTER_CAPTURE_CHANGED: { LOG_ALWAYS_FATAL("Canceling %s events is not supported", EventEntry::typeToString(cancelationEventEntry->type)); break; } case EventEntry::Type::CONFIGURATION_CHANGED: Loading Loading @@ -3185,7 +3269,8 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( case EventEntry::Type::KEY: case EventEntry::Type::FOCUS: case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { case EventEntry::Type::DEVICE_RESET: case EventEntry::Type::POINTER_CAPTURE_CHANGED: { LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue", EventEntry::typeToString(downEventEntry->type)); break; Loading Loading @@ -3562,7 +3647,17 @@ void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChan args->enabled ? "true" : "false"); #endif // TODO(prabirmsp): Implement. bool needWake; { // acquire lock std::scoped_lock _l(mLock); auto entry = std::make_unique<PointerCaptureChangedEntry>(args->id, args->eventTime, args->enabled); needWake = enqueueInboundEventLocked(std::move(entry)); } // release lock if (needWake) { mLooper->wake(); } } InputEventInjectionResult InputDispatcher::injectInputEvent( Loading Loading @@ -4456,6 +4551,24 @@ std::string InputDispatcher::dumpPendingFocusRequestsLocked() { return dump; } std::string InputDispatcher::dumpPointerCaptureStateLocked() { std::string dump; dump += StringPrintf(INDENT "FocusedWindowRequestedPointerCapture: %s\n", toString(mFocusedWindowRequestedPointerCapture)); std::string windowName = "None"; if (mWindowTokenWithPointerCapture) { const sp<InputWindowHandle> captureWindowHandle = getWindowHandleLocked(mWindowTokenWithPointerCapture); windowName = captureWindowHandle ? captureWindowHandle->getName().c_str() : "token has capture without window"; } dump += StringPrintf(INDENT "CurrentWindowWithPointerCapture: %s\n", windowName.c_str()); return dump; } void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += StringPrintf(INDENT "DispatchEnabled: %s\n", toString(mDispatchEnabled)); dump += StringPrintf(INDENT "DispatchFrozen: %s\n", toString(mDispatchFrozen)); Loading @@ -4479,6 +4592,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += dumpFocusedWindowsLocked(); dump += dumpPendingFocusRequestsLocked(); dump += dumpPointerCaptureStateLocked(); if (!mTouchStatesByDisplay.empty()) { dump += StringPrintf(INDENT "TouchStatesByDisplay:\n"); Loading Loading @@ -4860,6 +4974,39 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { return OK; } void InputDispatcher::requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) { { // acquire lock std::scoped_lock _l(mLock); if (DEBUG_FOCUS) { const sp<InputWindowHandle> windowHandle = getWindowHandleLocked(windowToken); ALOGI("Request to %s Pointer Capture from: %s.", enabled ? "enable" : "disable", windowHandle != nullptr ? windowHandle->getName().c_str() : "token without window"); } const sp<IBinder> focusedToken = getValueByKey(mFocusedWindowTokenByDisplay, mFocusedDisplayId); if (focusedToken != windowToken) { ALOGW("Ignoring request to %s Pointer Capture: window does not have focus.", enabled ? "enable" : "disable"); return; } if (enabled == mFocusedWindowRequestedPointerCapture) { ALOGW("Ignoring request to %s Pointer Capture: " "window has %s requested pointer capture.", enabled ? "enable" : "disable", enabled ? "already" : "not"); return; } mFocusedWindowRequestedPointerCapture = enabled; setPointerCaptureLocked(enabled); } // release lock // Wake the thread to process command entries. mLooper->wake(); } std::optional<int32_t> InputDispatcher::findGestureMonitorDisplayByTokenLocked( const sp<IBinder>& token) { for (const auto& it : mGestureMonitorsByDisplay) { Loading Loading @@ -5578,11 +5725,50 @@ void InputDispatcher::onFocusChangedLocked(const sp<IBinder>& oldFocusedToken, enqueueFocusEventLocked(newFocusedToken, true /*hasFocus*/, reason); } // If a window has pointer capture, then it must have focus. We need to ensure that this // contract is upheld when pointer capture is being disabled due to a loss of window focus. // If the window loses focus before it loses pointer capture, then the window can be in a state // where it has pointer capture but not focus, violating the contract. Therefore we must // dispatch the pointer capture event before the focus event. Since focus events are added to // the front of the queue (above), we add the pointer capture event to the front of the queue // after the focus events are added. This ensures the pointer capture event ends up at the // front. disablePointerCaptureForcedLocked(); if (mFocusedDisplayId == displayId) { notifyFocusChangedLocked(oldFocusedToken, newFocusedToken); } } void InputDispatcher::disablePointerCaptureForcedLocked() { if (!mFocusedWindowRequestedPointerCapture && !mWindowTokenWithPointerCapture) { return; } ALOGD_IF(DEBUG_FOCUS, "Disabling Pointer Capture because the window lost focus."); if (mFocusedWindowRequestedPointerCapture) { mFocusedWindowRequestedPointerCapture = false; setPointerCaptureLocked(false); } if (!mWindowTokenWithPointerCapture) { // No need to send capture changes because no window has capture. return; } if (mPendingEvent != nullptr) { // Move the pending event to the front of the queue. This will give the chance // for the pending event to be dropped if it is a captured event. mInboundQueue.push_front(mPendingEvent); mPendingEvent = nullptr; } auto entry = std::make_unique<PointerCaptureChangedEntry>(mIdGenerator.nextId(), now(), false /* hasCapture */); mInboundQueue.push_front(std::move(entry)); } /** * Checks if the window token can be focused on a display. The token can be focused if there is * at least one window handle that is visible with the same token and all window handles with the Loading Loading @@ -5626,4 +5812,21 @@ InputDispatcher::FocusResult InputDispatcher::checkTokenFocusableLocked(const sp return FocusResult::OK; } void InputDispatcher::setPointerCaptureLocked(bool enabled) { std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>( &InputDispatcher::doSetPointerCaptureLockedInterruptible); commandEntry->enabled = enabled; postCommandLocked(std::move(commandEntry)); } void InputDispatcher::doSetPointerCaptureLockedInterruptible( android::inputdispatcher::CommandEntry* commandEntry) { mLock.unlock(); mPolicy->setPointerCapture(commandEntry->enabled); mLock.lock(); } } // namespace android::inputdispatcher services/inputflinger/dispatcher/InputDispatcher.h +22 −0 Original line number Diff line number Diff line Loading @@ -127,6 +127,7 @@ public: int32_t displayId, bool isGestureMonitor, const std::string& name) override; virtual status_t removeInputChannel(const sp<IBinder>& connectionToken) override; virtual status_t pilferPointers(const sp<IBinder>& token) override; virtual void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) override; std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const; Loading @@ -138,6 +139,7 @@ private: DISABLED, BLOCKED, STALE, NO_POINTER_CAPTURE, }; enum class FocusResult { Loading Loading @@ -351,6 +353,21 @@ private: // Top focused display. int32_t mFocusedDisplayId GUARDED_BY(mLock); // Whether the focused window on the focused display has requested Pointer Capture. // The state of this variable should always be in sync with the state of Pointer Capture in the // policy, which is updated through setPointerCaptureLocked(enabled). bool mFocusedWindowRequestedPointerCapture GUARDED_BY(mLock); // The window token that has Pointer Capture. // This should be in sync with PointerCaptureChangedEvents dispatched to the input channel. sp<IBinder> mWindowTokenWithPointerCapture GUARDED_BY(mLock); // Disable Pointer Capture as a result of loss of window focus. void disablePointerCaptureForcedLocked() REQUIRES(mLock); // Set the Pointer Capture state in the Policy. void setPointerCaptureLocked(bool enabled) REQUIRES(mLock); // Dispatcher state at time of last ANR. std::string mLastAnrState GUARDED_BY(mLock); Loading @@ -370,6 +387,9 @@ private: DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock); void dispatchFocusLocked(nsecs_t currentTime, std::shared_ptr<FocusEntry> entry) REQUIRES(mLock); void dispatchPointerCaptureChangedLocked( nsecs_t currentTime, const std::shared_ptr<PointerCaptureChangedEntry>& entry, DropReason& dropReason) REQUIRES(mLock); void dispatchEventLocked(nsecs_t currentTime, std::shared_ptr<EventEntry> entry, const std::vector<InputTarget>& inputTargets) REQUIRES(mLock); Loading Loading @@ -533,6 +553,7 @@ private: void logDispatchStateLocked() REQUIRES(mLock); std::string dumpFocusedWindowsLocked() REQUIRES(mLock); std::string dumpPendingFocusRequestsLocked() REQUIRES(mLock); std::string dumpPointerCaptureStateLocked() REQUIRES(mLock); // Registration. void removeMonitorChannelLocked(const sp<IBinder>& connectionToken) REQUIRES(mLock); Loading Loading @@ -575,6 +596,7 @@ private: void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); void doSetPointerCaptureLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); bool afterKeyEventLockedInterruptible(const sp<Connection>& connection, DispatchEntry* dispatchEntry, KeyEntry& keyEntry, bool handled) REQUIRES(mLock); Loading Loading
services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -96,6 +96,8 @@ private: void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {} void setPointerCapture(bool enabled) override {} InputDispatcherConfiguration mConfig; }; Loading
services/inputflinger/dispatcher/Entry.cpp +16 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,22 @@ std::string FocusEntry::getDescription() const { return StringPrintf("FocusEvent(hasFocus=%s)", hasFocus ? "true" : "false"); } // --- PointerCaptureChangedEntry --- // PointerCaptureChanged notifications always go to apps, so set the flag POLICY_FLAG_PASS_TO_USER // for all entries. PointerCaptureChangedEntry::PointerCaptureChangedEntry(int32_t id, nsecs_t eventTime, bool hasPointerCapture) : EventEntry(id, Type::POINTER_CAPTURE_CHANGED, eventTime, POLICY_FLAG_PASS_TO_USER), pointerCaptureEnabled(hasPointerCapture) {} PointerCaptureChangedEntry::~PointerCaptureChangedEntry() {} std::string PointerCaptureChangedEntry::getDescription() const { return StringPrintf("PointerCaptureChangedEvent(pointerCaptureEnabled=%s)", pointerCaptureEnabled ? "true" : "false"); } // --- KeyEntry --- KeyEntry::KeyEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source, Loading
services/inputflinger/dispatcher/Entry.h +13 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ struct EventEntry { FOCUS, KEY, MOTION, POINTER_CAPTURE_CHANGED, }; static const char* typeToString(Type type) { Loading @@ -50,6 +51,8 @@ struct EventEntry { return "KEY"; case Type::MOTION: return "MOTION"; case Type::POINTER_CAPTURE_CHANGED: return "POINTER_CAPTURE_CHANGED"; } } Loading Loading @@ -115,6 +118,15 @@ struct FocusEntry : EventEntry { virtual ~FocusEntry(); }; struct PointerCaptureChangedEntry : EventEntry { bool pointerCaptureEnabled; PointerCaptureChangedEntry(int32_t id, nsecs_t eventTime, bool hasPointerCapture); std::string getDescription() const override; virtual ~PointerCaptureChangedEntry(); }; struct KeyEntry : EventEntry { int32_t deviceId; uint32_t source; Loading Loading @@ -254,6 +266,7 @@ struct CommandEntry { sp<IBinder> oldToken; sp<IBinder> newToken; std::string obscuringPackage; bool enabled; }; } // namespace android::inputdispatcher Loading
services/inputflinger/dispatcher/InputDispatcher.cpp +212 −9 Original line number Diff line number Diff line Loading @@ -454,6 +454,8 @@ InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& polic mInTouchMode(true), mMaximumObscuringOpacityForTouch(1.0f), mFocusedDisplayId(ADISPLAY_ID_DEFAULT), mFocusedWindowRequestedPointerCapture(false), mWindowTokenWithPointerCapture(nullptr), mCompatService(getCompatService()) { mLooper = new Looper(false); mReporter = createInputReporter(); Loading Loading @@ -713,6 +715,14 @@ void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { break; } case EventEntry::Type::POINTER_CAPTURE_CHANGED: { const auto typedEntry = std::static_pointer_cast<PointerCaptureChangedEntry>(mPendingEvent); dispatchPointerCaptureChangedLocked(currentTime, typedEntry, dropReason); done = true; break; } case EventEntry::Type::KEY: { std::shared_ptr<KeyEntry> keyEntry = std::static_pointer_cast<KeyEntry>(mPendingEvent); if (isAppSwitchDue) { Loading Loading @@ -862,7 +872,8 @@ bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newE break; } case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { case EventEntry::Type::DEVICE_RESET: case EventEntry::Type::POINTER_CAPTURE_CHANGED: { // nothing to do break; } Loading Loading @@ -968,6 +979,10 @@ void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason ALOGI("Dropped event because it is stale."); reason = "inbound event was dropped because it is stale"; break; case DropReason::NO_POINTER_CAPTURE: ALOGI("Dropped event because there is no window with Pointer Capture."); reason = "inbound event was dropped because there is no window with Pointer Capture"; break; case DropReason::NOT_DROPPED: { LOG_ALWAYS_FATAL("Should not be dropping a NOT_DROPPED event"); return; Loading @@ -991,6 +1006,9 @@ void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason } break; } case EventEntry::Type::POINTER_CAPTURE_CHANGED: { break; } case EventEntry::Type::FOCUS: case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { Loading Loading @@ -1176,6 +1194,55 @@ void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime, std::shared_ptr<F dispatchEventLocked(currentTime, entry, {target}); } void InputDispatcher::dispatchPointerCaptureChangedLocked( nsecs_t currentTime, const std::shared_ptr<PointerCaptureChangedEntry>& entry, DropReason& dropReason) { const bool haveWindowWithPointerCapture = mWindowTokenWithPointerCapture != nullptr; if (entry->pointerCaptureEnabled == haveWindowWithPointerCapture) { LOG_ALWAYS_FATAL_IF(mFocusedWindowRequestedPointerCapture, "The Pointer Capture state has already been dispatched to the window."); // Pointer capture was already forcefully disabled because of focus change. dropReason = DropReason::NOT_DROPPED; return; } // Set drop reason for early returns dropReason = DropReason::NO_POINTER_CAPTURE; sp<IBinder> token; if (entry->pointerCaptureEnabled) { // Enable Pointer Capture if (!mFocusedWindowRequestedPointerCapture) { // This can happen if a window requests capture and immediately releases capture. ALOGW("No window requested Pointer Capture."); return; } token = getValueByKey(mFocusedWindowTokenByDisplay, mFocusedDisplayId); LOG_ALWAYS_FATAL_IF(!token, "Cannot find focused window for Pointer Capture."); mWindowTokenWithPointerCapture = token; } else { // Disable Pointer Capture token = mWindowTokenWithPointerCapture; mWindowTokenWithPointerCapture = nullptr; mFocusedWindowRequestedPointerCapture = false; } auto channel = getInputChannelLocked(token); if (channel == nullptr) { // Window has gone away, clean up Pointer Capture state. mWindowTokenWithPointerCapture = nullptr; mFocusedWindowRequestedPointerCapture = false; return; } InputTarget target; target.inputChannel = channel; target.flags = InputTarget::FLAG_DISPATCH_AS_IS; entry->dispatchInProgress = true; dispatchEventLocked(currentTime, entry, {target}); dropReason = DropReason::NOT_DROPPED; } bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { // Preprocessing. Loading Loading @@ -1483,6 +1550,7 @@ int32_t InputDispatcher::getTargetDisplayId(const EventEntry& entry) { displayId = motionEntry.displayId; break; } case EventEntry::Type::POINTER_CAPTURE_CHANGED: case EventEntry::Type::FOCUS: case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { Loading Loading @@ -2366,8 +2434,10 @@ std::string InputDispatcher::getApplicationWindowLabel( } void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { if (eventEntry.type == EventEntry::Type::FOCUS) { // Focus events are passed to apps, but do not represent user activity. if (eventEntry.type == EventEntry::Type::FOCUS || eventEntry.type == EventEntry::Type::POINTER_CAPTURE_CHANGED) { // Focus or pointer capture changed events are passed to apps, but do not represent user // activity. return; } int32_t displayId = getTargetDisplayId(eventEntry); Loading Loading @@ -2405,7 +2475,8 @@ void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) { } case EventEntry::Type::FOCUS: case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { case EventEntry::Type::DEVICE_RESET: case EventEntry::Type::POINTER_CAPTURE_CHANGED: { LOG_ALWAYS_FATAL("%s events are not user activity", EventEntry::typeToString(eventEntry.type)); break; Loading Loading @@ -2617,7 +2688,8 @@ void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connectio break; } case EventEntry::Type::FOCUS: { case EventEntry::Type::FOCUS: case EventEntry::Type::POINTER_CAPTURE_CHANGED: { break; } case EventEntry::Type::CONFIGURATION_CHANGED: Loading Loading @@ -2821,6 +2893,7 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, reportTouchEventForStatistics(motionEntry); break; } case EventEntry::Type::FOCUS: { const FocusEntry& focusEntry = static_cast<const FocusEntry&>(eventEntry); status = connection->inputPublisher.publishFocusEvent(dispatchEntry->seq, Loading @@ -2830,6 +2903,15 @@ void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, break; } case EventEntry::Type::POINTER_CAPTURE_CHANGED: { const auto& captureEntry = static_cast<const PointerCaptureChangedEntry&>(eventEntry); status = connection->inputPublisher .publishCaptureEvent(dispatchEntry->seq, captureEntry.id, captureEntry.pointerCaptureEnabled); break; } case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { LOG_ALWAYS_FATAL("Should never start dispatch cycles for %s events", Loading Loading @@ -3124,8 +3206,10 @@ void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( static_cast<const MotionEntry&>(*cancelationEventEntry)); break; } case EventEntry::Type::FOCUS: { LOG_ALWAYS_FATAL("Canceling focus events is not supported"); case EventEntry::Type::FOCUS: case EventEntry::Type::POINTER_CAPTURE_CHANGED: { LOG_ALWAYS_FATAL("Canceling %s events is not supported", EventEntry::typeToString(cancelationEventEntry->type)); break; } case EventEntry::Type::CONFIGURATION_CHANGED: Loading Loading @@ -3185,7 +3269,8 @@ void InputDispatcher::synthesizePointerDownEventsForConnectionLocked( case EventEntry::Type::KEY: case EventEntry::Type::FOCUS: case EventEntry::Type::CONFIGURATION_CHANGED: case EventEntry::Type::DEVICE_RESET: { case EventEntry::Type::DEVICE_RESET: case EventEntry::Type::POINTER_CAPTURE_CHANGED: { LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue", EventEntry::typeToString(downEventEntry->type)); break; Loading Loading @@ -3562,7 +3647,17 @@ void InputDispatcher::notifyPointerCaptureChanged(const NotifyPointerCaptureChan args->enabled ? "true" : "false"); #endif // TODO(prabirmsp): Implement. bool needWake; { // acquire lock std::scoped_lock _l(mLock); auto entry = std::make_unique<PointerCaptureChangedEntry>(args->id, args->eventTime, args->enabled); needWake = enqueueInboundEventLocked(std::move(entry)); } // release lock if (needWake) { mLooper->wake(); } } InputEventInjectionResult InputDispatcher::injectInputEvent( Loading Loading @@ -4456,6 +4551,24 @@ std::string InputDispatcher::dumpPendingFocusRequestsLocked() { return dump; } std::string InputDispatcher::dumpPointerCaptureStateLocked() { std::string dump; dump += StringPrintf(INDENT "FocusedWindowRequestedPointerCapture: %s\n", toString(mFocusedWindowRequestedPointerCapture)); std::string windowName = "None"; if (mWindowTokenWithPointerCapture) { const sp<InputWindowHandle> captureWindowHandle = getWindowHandleLocked(mWindowTokenWithPointerCapture); windowName = captureWindowHandle ? captureWindowHandle->getName().c_str() : "token has capture without window"; } dump += StringPrintf(INDENT "CurrentWindowWithPointerCapture: %s\n", windowName.c_str()); return dump; } void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += StringPrintf(INDENT "DispatchEnabled: %s\n", toString(mDispatchEnabled)); dump += StringPrintf(INDENT "DispatchFrozen: %s\n", toString(mDispatchFrozen)); Loading @@ -4479,6 +4592,7 @@ void InputDispatcher::dumpDispatchStateLocked(std::string& dump) { dump += dumpFocusedWindowsLocked(); dump += dumpPendingFocusRequestsLocked(); dump += dumpPointerCaptureStateLocked(); if (!mTouchStatesByDisplay.empty()) { dump += StringPrintf(INDENT "TouchStatesByDisplay:\n"); Loading Loading @@ -4860,6 +4974,39 @@ status_t InputDispatcher::pilferPointers(const sp<IBinder>& token) { return OK; } void InputDispatcher::requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) { { // acquire lock std::scoped_lock _l(mLock); if (DEBUG_FOCUS) { const sp<InputWindowHandle> windowHandle = getWindowHandleLocked(windowToken); ALOGI("Request to %s Pointer Capture from: %s.", enabled ? "enable" : "disable", windowHandle != nullptr ? windowHandle->getName().c_str() : "token without window"); } const sp<IBinder> focusedToken = getValueByKey(mFocusedWindowTokenByDisplay, mFocusedDisplayId); if (focusedToken != windowToken) { ALOGW("Ignoring request to %s Pointer Capture: window does not have focus.", enabled ? "enable" : "disable"); return; } if (enabled == mFocusedWindowRequestedPointerCapture) { ALOGW("Ignoring request to %s Pointer Capture: " "window has %s requested pointer capture.", enabled ? "enable" : "disable", enabled ? "already" : "not"); return; } mFocusedWindowRequestedPointerCapture = enabled; setPointerCaptureLocked(enabled); } // release lock // Wake the thread to process command entries. mLooper->wake(); } std::optional<int32_t> InputDispatcher::findGestureMonitorDisplayByTokenLocked( const sp<IBinder>& token) { for (const auto& it : mGestureMonitorsByDisplay) { Loading Loading @@ -5578,11 +5725,50 @@ void InputDispatcher::onFocusChangedLocked(const sp<IBinder>& oldFocusedToken, enqueueFocusEventLocked(newFocusedToken, true /*hasFocus*/, reason); } // If a window has pointer capture, then it must have focus. We need to ensure that this // contract is upheld when pointer capture is being disabled due to a loss of window focus. // If the window loses focus before it loses pointer capture, then the window can be in a state // where it has pointer capture but not focus, violating the contract. Therefore we must // dispatch the pointer capture event before the focus event. Since focus events are added to // the front of the queue (above), we add the pointer capture event to the front of the queue // after the focus events are added. This ensures the pointer capture event ends up at the // front. disablePointerCaptureForcedLocked(); if (mFocusedDisplayId == displayId) { notifyFocusChangedLocked(oldFocusedToken, newFocusedToken); } } void InputDispatcher::disablePointerCaptureForcedLocked() { if (!mFocusedWindowRequestedPointerCapture && !mWindowTokenWithPointerCapture) { return; } ALOGD_IF(DEBUG_FOCUS, "Disabling Pointer Capture because the window lost focus."); if (mFocusedWindowRequestedPointerCapture) { mFocusedWindowRequestedPointerCapture = false; setPointerCaptureLocked(false); } if (!mWindowTokenWithPointerCapture) { // No need to send capture changes because no window has capture. return; } if (mPendingEvent != nullptr) { // Move the pending event to the front of the queue. This will give the chance // for the pending event to be dropped if it is a captured event. mInboundQueue.push_front(mPendingEvent); mPendingEvent = nullptr; } auto entry = std::make_unique<PointerCaptureChangedEntry>(mIdGenerator.nextId(), now(), false /* hasCapture */); mInboundQueue.push_front(std::move(entry)); } /** * Checks if the window token can be focused on a display. The token can be focused if there is * at least one window handle that is visible with the same token and all window handles with the Loading Loading @@ -5626,4 +5812,21 @@ InputDispatcher::FocusResult InputDispatcher::checkTokenFocusableLocked(const sp return FocusResult::OK; } void InputDispatcher::setPointerCaptureLocked(bool enabled) { std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>( &InputDispatcher::doSetPointerCaptureLockedInterruptible); commandEntry->enabled = enabled; postCommandLocked(std::move(commandEntry)); } void InputDispatcher::doSetPointerCaptureLockedInterruptible( android::inputdispatcher::CommandEntry* commandEntry) { mLock.unlock(); mPolicy->setPointerCapture(commandEntry->enabled); mLock.lock(); } } // namespace android::inputdispatcher
services/inputflinger/dispatcher/InputDispatcher.h +22 −0 Original line number Diff line number Diff line Loading @@ -127,6 +127,7 @@ public: int32_t displayId, bool isGestureMonitor, const std::string& name) override; virtual status_t removeInputChannel(const sp<IBinder>& connectionToken) override; virtual status_t pilferPointers(const sp<IBinder>& token) override; virtual void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) override; std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const; Loading @@ -138,6 +139,7 @@ private: DISABLED, BLOCKED, STALE, NO_POINTER_CAPTURE, }; enum class FocusResult { Loading Loading @@ -351,6 +353,21 @@ private: // Top focused display. int32_t mFocusedDisplayId GUARDED_BY(mLock); // Whether the focused window on the focused display has requested Pointer Capture. // The state of this variable should always be in sync with the state of Pointer Capture in the // policy, which is updated through setPointerCaptureLocked(enabled). bool mFocusedWindowRequestedPointerCapture GUARDED_BY(mLock); // The window token that has Pointer Capture. // This should be in sync with PointerCaptureChangedEvents dispatched to the input channel. sp<IBinder> mWindowTokenWithPointerCapture GUARDED_BY(mLock); // Disable Pointer Capture as a result of loss of window focus. void disablePointerCaptureForcedLocked() REQUIRES(mLock); // Set the Pointer Capture state in the Policy. void setPointerCaptureLocked(bool enabled) REQUIRES(mLock); // Dispatcher state at time of last ANR. std::string mLastAnrState GUARDED_BY(mLock); Loading @@ -370,6 +387,9 @@ private: DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock); void dispatchFocusLocked(nsecs_t currentTime, std::shared_ptr<FocusEntry> entry) REQUIRES(mLock); void dispatchPointerCaptureChangedLocked( nsecs_t currentTime, const std::shared_ptr<PointerCaptureChangedEntry>& entry, DropReason& dropReason) REQUIRES(mLock); void dispatchEventLocked(nsecs_t currentTime, std::shared_ptr<EventEntry> entry, const std::vector<InputTarget>& inputTargets) REQUIRES(mLock); Loading Loading @@ -533,6 +553,7 @@ private: void logDispatchStateLocked() REQUIRES(mLock); std::string dumpFocusedWindowsLocked() REQUIRES(mLock); std::string dumpPendingFocusRequestsLocked() REQUIRES(mLock); std::string dumpPointerCaptureStateLocked() REQUIRES(mLock); // Registration. void removeMonitorChannelLocked(const sp<IBinder>& connectionToken) REQUIRES(mLock); Loading Loading @@ -575,6 +596,7 @@ private: void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); void doSetPointerCaptureLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock); bool afterKeyEventLockedInterruptible(const sp<Connection>& connection, DispatchEntry* dispatchEntry, KeyEntry& keyEntry, bool handled) REQUIRES(mLock); Loading