FocusResolver: Clean up focus requests and results when a display is removed
Prevents FocusResolver from leaking focus requests and results as
displays are added and removed.
Test: atest inputflinger_tests
Fixes: 188008394
Change-Id: I635b9becf91056fd540ab9d9546dd67a09324fc6
diff --git a/services/inputflinger/dispatcher/FocusResolver.cpp b/services/inputflinger/dispatcher/FocusResolver.cpp
index 2db8c13..fb19435 100644
--- a/services/inputflinger/dispatcher/FocusResolver.cpp
+++ b/services/inputflinger/dispatcher/FocusResolver.cpp
@@ -216,4 +216,9 @@
return dump;
}
+void FocusResolver::displayRemoved(int32_t displayId) {
+ mFocusRequestByDisplay.erase(displayId);
+ mLastFocusResultByDisplay.erase(displayId);
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/FocusResolver.h b/services/inputflinger/dispatcher/FocusResolver.h
index dc5eeeb..afe16b3 100644
--- a/services/inputflinger/dispatcher/FocusResolver.h
+++ b/services/inputflinger/dispatcher/FocusResolver.h
@@ -62,6 +62,9 @@
std::optional<FocusResolver::FocusChanges> setFocusedWindow(
const FocusRequest& request, const std::vector<sp<InputWindowHandle>>& windows);
+ // Display has been removed from the system, clean up old references.
+ void displayRemoved(int32_t displayId);
+
// exposed for debugging
bool hasFocusedWindowTokens() const { return !mFocusedWindowTokenByDisplay.empty(); }
std::string dumpFocusedWindows() const;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index d2b8739..c0010ab 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -4613,30 +4613,34 @@
}
{ // acquire lock
std::scoped_lock _l(mLock);
-
- std::shared_ptr<InputApplicationHandle> oldFocusedApplicationHandle =
- getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
-
- if (sharedPointersEqual(oldFocusedApplicationHandle, inputApplicationHandle)) {
- return; // This application is already focused. No need to wake up or change anything.
- }
-
- // Set the new application handle.
- if (inputApplicationHandle != nullptr) {
- mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
- } else {
- mFocusedApplicationHandlesByDisplay.erase(displayId);
- }
-
- // No matter what the old focused application was, stop waiting on it because it is
- // no longer focused.
- resetNoFocusedWindowTimeoutLocked();
+ setFocusedApplicationLocked(displayId, inputApplicationHandle);
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
mLooper->wake();
}
+void InputDispatcher::setFocusedApplicationLocked(
+ int32_t displayId, const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) {
+ std::shared_ptr<InputApplicationHandle> oldFocusedApplicationHandle =
+ getValueByKey(mFocusedApplicationHandlesByDisplay, displayId);
+
+ if (sharedPointersEqual(oldFocusedApplicationHandle, inputApplicationHandle)) {
+ return; // This application is already focused. No need to wake up or change anything.
+ }
+
+ // Set the new application handle.
+ if (inputApplicationHandle != nullptr) {
+ mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
+ } else {
+ mFocusedApplicationHandlesByDisplay.erase(displayId);
+ }
+
+ // No matter what the old focused application was, stop waiting on it because it is
+ // no longer focused.
+ resetNoFocusedWindowTimeoutLocked();
+}
+
/**
* Sets the focused display, which is responsible for receiving focus-dispatched input events where
* the display not specified.
@@ -6208,4 +6212,19 @@
mLock.lock();
}
+void InputDispatcher::displayRemoved(int32_t displayId) {
+ { // acquire lock
+ std::scoped_lock _l(mLock);
+ // Set an empty list to remove all handles from the specific display.
+ setInputWindowsLocked(/* window handles */ {}, displayId);
+ setFocusedApplicationLocked(displayId, nullptr);
+ // Call focus resolver to clean up stale requests. This must be called after input windows
+ // have been removed for the removed display.
+ mFocusResolver.displayRemoved(displayId);
+ } // release lock
+
+ // Wake up poll loop since it may need to make new input dispatching choices.
+ mLooper->wake();
+}
+
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index bb3f3e6..9edf41c 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -139,6 +139,8 @@
std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;
+ void displayRemoved(int32_t displayId) override;
+
private:
enum class DropReason {
NOT_DROPPED,
@@ -343,6 +345,9 @@
std::unordered_map<int32_t, TouchState> mTouchStatesByDisplay GUARDED_BY(mLock);
std::unique_ptr<DragState> mDragState GUARDED_BY(mLock);
+ void setFocusedApplicationLocked(
+ int32_t displayId,
+ const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle) REQUIRES(mLock);
// Focused applications.
std::unordered_map<int32_t, std::shared_ptr<InputApplicationHandle>>
mFocusedApplicationHandlesByDisplay GUARDED_BY(mLock);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 7f85e53..43428a0 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -209,6 +209,11 @@
* Returns true on success.
*/
virtual bool flushSensor(int deviceId, InputDeviceSensorType sensorType) = 0;
+
+ /**
+ * Called when a display has been removed from the system.
+ */
+ virtual void displayRemoved(int32_t displayId) = 0;
};
} // namespace android