Refactor PointerChoreographer lock
Pointer choreographer and WindowInfoListener use separate locks which
is problematic. As WindowInfosUpdate callback is triggered from the
display thread, a deadlock might occur due to race between display and
reader thread. Both trying to acquire both the locks.
This becomes much more likely when we have multiple displays connected.
Test: Verify pointer indicators are hidden on screenshots of secure windows
Test: atest inputflinger_tests
Bug: 367660694
Flag: EXEMPT refactor
Change-Id: I7417c0071322a093643734432f8f0236bd89a317
diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h
index 635487b..85f51e0 100644
--- a/services/inputflinger/PointerChoreographer.h
+++ b/services/inputflinger/PointerChoreographer.h
@@ -118,31 +118,38 @@
private:
using PointerDisplayChange = std::optional<
std::tuple<ui::LogicalDisplayId /*displayId*/, FloatPoint /*cursorPosition*/>>;
- [[nodiscard]] PointerDisplayChange updatePointerControllersLocked() REQUIRES(mLock);
- [[nodiscard]] PointerDisplayChange calculatePointerDisplayChangeToNotify() REQUIRES(mLock);
+
+ // PointerChoreographer's DisplayInfoListener can outlive the PointerChoreographer because when
+ // the listener is registered and called from display thread, a strong pointer to the listener
+ // (which can extend its lifecycle) is given away.
+ // If we use two locks it can also cause deadlocks due to race in acquiring them between the
+ // display and reader thread.
+ // To avoid these problems we use DisplayInfoListener's lock in PointerChoreographer.
+ std::mutex& getLock() const;
+
+ [[nodiscard]] PointerDisplayChange updatePointerControllersLocked() REQUIRES(getLock());
+ [[nodiscard]] PointerDisplayChange calculatePointerDisplayChangeToNotify() REQUIRES(getLock());
const DisplayViewport* findViewportByIdLocked(ui::LogicalDisplayId displayId) const
- REQUIRES(mLock);
+ REQUIRES(getLock());
ui::LogicalDisplayId getTargetMouseDisplayLocked(ui::LogicalDisplayId associatedDisplayId) const
- REQUIRES(mLock);
+ REQUIRES(getLock());
std::pair<ui::LogicalDisplayId /*displayId*/, PointerControllerInterface&>
- ensureMouseControllerLocked(ui::LogicalDisplayId associatedDisplayId) REQUIRES(mLock);
- InputDeviceInfo* findInputDeviceLocked(DeviceId deviceId) REQUIRES(mLock);
- bool canUnfadeOnDisplay(ui::LogicalDisplayId displayId) REQUIRES(mLock);
+ ensureMouseControllerLocked(ui::LogicalDisplayId associatedDisplayId) REQUIRES(getLock());
+ InputDeviceInfo* findInputDeviceLocked(DeviceId deviceId) REQUIRES(getLock());
+ bool canUnfadeOnDisplay(ui::LogicalDisplayId displayId) REQUIRES(getLock());
void fadeMouseCursorOnKeyPress(const NotifyKeyArgs& args);
NotifyMotionArgs processMotion(const NotifyMotionArgs& args);
- NotifyMotionArgs processMouseEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
- NotifyMotionArgs processTouchpadEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
- void processDrawingTabletEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
- void processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
- void processStylusHoverEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
+ NotifyMotionArgs processMouseEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
+ NotifyMotionArgs processTouchpadEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
+ void processDrawingTabletEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
+ void processTouchscreenAndStylusEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
+ void processStylusHoverEventLocked(const NotifyMotionArgs& args) REQUIRES(getLock());
void processDeviceReset(const NotifyDeviceResetArgs& args);
- void onControllerAddedOrRemovedLocked() REQUIRES(mLock);
+ void onControllerAddedOrRemovedLocked() REQUIRES(getLock());
void onPrivacySensitiveDisplaysChangedLocked(
const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays)
- REQUIRES(mLock);
- void onPrivacySensitiveDisplaysChanged(
- const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays);
+ REQUIRES(getLock());
/* This listener keeps tracks of visible privacy sensitive displays and updates the
* choreographer if there are any changes.
@@ -156,49 +163,50 @@
explicit PointerChoreographerDisplayInfoListener(PointerChoreographer* pc)
: mPointerChoreographer(pc){};
void onWindowInfosChanged(const gui::WindowInfosUpdate&) override;
- void setInitialDisplayInfos(const std::vector<gui::WindowInfo>& windowInfos);
- std::unordered_set<ui::LogicalDisplayId /*displayId*/> getPrivacySensitiveDisplays();
+ void setInitialDisplayInfosLocked(const std::vector<gui::WindowInfo>& windowInfos)
+ REQUIRES(mLock);
+ std::unordered_set<ui::LogicalDisplayId> getPrivacySensitiveDisplaysLocked()
+ REQUIRES(mLock);
void onPointerChoreographerDestroyed();
+ // This lock is also used by PointerChoreographer. See PointerChoreographer::getLock().
+ std::mutex mLock;
+
private:
- std::mutex mListenerLock;
- PointerChoreographer* mPointerChoreographer GUARDED_BY(mListenerLock);
+ PointerChoreographer* mPointerChoreographer GUARDED_BY(mLock);
std::unordered_set<ui::LogicalDisplayId /*displayId*/> mPrivacySensitiveDisplays
- GUARDED_BY(mListenerLock);
+ GUARDED_BY(mLock);
};
- sp<PointerChoreographerDisplayInfoListener> mWindowInfoListener GUARDED_BY(mLock);
using ControllerConstructor =
ConstructorDelegate<std::function<std::shared_ptr<PointerControllerInterface>()>>;
- ControllerConstructor mTouchControllerConstructor GUARDED_BY(mLock);
+ ControllerConstructor mTouchControllerConstructor GUARDED_BY(getLock());
ControllerConstructor getMouseControllerConstructor(ui::LogicalDisplayId displayId)
- REQUIRES(mLock);
+ REQUIRES(getLock());
ControllerConstructor getStylusControllerConstructor(ui::LogicalDisplayId displayId)
- REQUIRES(mLock);
-
- std::mutex mLock;
+ REQUIRES(getLock());
InputListenerInterface& mNextListener;
PointerChoreographerPolicyInterface& mPolicy;
std::map<ui::LogicalDisplayId, std::shared_ptr<PointerControllerInterface>>
- mMousePointersByDisplay GUARDED_BY(mLock);
+ mMousePointersByDisplay GUARDED_BY(getLock());
std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mTouchPointersByDevice
- GUARDED_BY(mLock);
+ GUARDED_BY(getLock());
std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mStylusPointersByDevice
- GUARDED_BY(mLock);
+ GUARDED_BY(getLock());
std::map<DeviceId, std::shared_ptr<PointerControllerInterface>> mDrawingTabletPointersByDevice
- GUARDED_BY(mLock);
+ GUARDED_BY(getLock());
- ui::LogicalDisplayId mDefaultMouseDisplayId GUARDED_BY(mLock);
- ui::LogicalDisplayId mNotifiedPointerDisplayId GUARDED_BY(mLock);
- std::vector<InputDeviceInfo> mInputDeviceInfos GUARDED_BY(mLock);
- std::set<DeviceId> mMouseDevices GUARDED_BY(mLock);
- std::vector<DisplayViewport> mViewports GUARDED_BY(mLock);
- bool mShowTouchesEnabled GUARDED_BY(mLock);
- bool mStylusPointerIconEnabled GUARDED_BY(mLock);
+ ui::LogicalDisplayId mDefaultMouseDisplayId GUARDED_BY(getLock());
+ ui::LogicalDisplayId mNotifiedPointerDisplayId GUARDED_BY(getLock());
+ std::vector<InputDeviceInfo> mInputDeviceInfos GUARDED_BY(getLock());
+ std::set<DeviceId> mMouseDevices GUARDED_BY(getLock());
+ std::vector<DisplayViewport> mViewports GUARDED_BY(getLock());
+ bool mShowTouchesEnabled GUARDED_BY(getLock());
+ bool mStylusPointerIconEnabled GUARDED_BY(getLock());
std::set<ui::LogicalDisplayId /*displayId*/> mDisplaysWithPointersHidden;
- ui::LogicalDisplayId mCurrentFocusedDisplay GUARDED_BY(mLock);
+ ui::LogicalDisplayId mCurrentFocusedDisplay GUARDED_BY(getLock());
protected:
using WindowListenerRegisterConsumer = std::function<std::vector<gui::WindowInfo>(
@@ -211,6 +219,10 @@
const WindowListenerUnregisterConsumer& unregisterListener);
private:
+ // WindowInfoListener object should always exist while PointerChoreographer exists, because we
+ // need to use the lock from it. But we don't always need to register the listener.
+ bool mIsWindowInfoListenerRegistered GUARDED_BY(getLock());
+ const sp<PointerChoreographerDisplayInfoListener> mWindowInfoListener;
const WindowListenerRegisterConsumer mRegisterListener;
const WindowListenerUnregisterConsumer mUnregisterListener;
};