diff options
-rw-r--r-- | include/audiomanager/AudioManager.h | 5 | ||||
-rw-r--r-- | libs/binder/rust/src/system_only.rs | 26 | ||||
-rw-r--r-- | libs/binder/rust/tests/integration.rs | 28 | ||||
-rw-r--r-- | libs/input/InputConsumerNoResampling.cpp | 15 | ||||
-rw-r--r-- | libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp | 48 | ||||
-rw-r--r-- | services/inputflinger/PointerChoreographer.cpp | 134 | ||||
-rw-r--r-- | services/inputflinger/PointerChoreographer.h | 94 | ||||
-rw-r--r-- | services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp | 42 | ||||
-rw-r--r-- | services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp | 1 | ||||
-rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 20 |
10 files changed, 271 insertions, 142 deletions
diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h index 917d9a74db..203623dea7 100644 --- a/include/audiomanager/AudioManager.h +++ b/include/audiomanager/AudioManager.h @@ -22,6 +22,7 @@ namespace android { // must be kept in sync with definitions in AudioPlaybackConfiguration.java #define PLAYER_PIID_INVALID -1 +// TODO (b/309532236) remove manual IAudioManager impl in favor of AIDL. typedef enum { PLAYER_TYPE_SLES_AUDIOPLAYER_BUFFERQUEUE = 11, PLAYER_TYPE_SLES_AUDIOPLAYER_URI_FD = 12, @@ -60,6 +61,7 @@ enum { PLAYER_MUTE_CLIENT_VOLUME = (1 << 4), PLAYER_MUTE_VOLUME_SHAPER = (1 << 5), PLAYER_MUTE_PORT_VOLUME = (1 << 6), + PLAYER_MUTE_OP_AUDIO_CONTROL = (1 << 7), }; struct mute_state_t { @@ -77,6 +79,8 @@ struct mute_state_t { bool muteFromVolumeShaper = false; /** Flag used when volume is muted by port volume. */ bool muteFromPortVolume = false; + /** Flag used when volume is muted by audio control op. */ + bool muteFromOpAudioControl = false; explicit operator int() const { @@ -87,6 +91,7 @@ struct mute_state_t { result |= muteFromClientVolume * PLAYER_MUTE_CLIENT_VOLUME; result |= muteFromVolumeShaper * PLAYER_MUTE_VOLUME_SHAPER; result |= muteFromPortVolume * PLAYER_MUTE_PORT_VOLUME; + result |= muteFromOpAudioControl * PLAYER_MUTE_OP_AUDIO_CONTROL; return result; } diff --git a/libs/binder/rust/src/system_only.rs b/libs/binder/rust/src/system_only.rs index 3da59ab811..1a58d6b44d 100644 --- a/libs/binder/rust/src/system_only.rs +++ b/libs/binder/rust/src/system_only.rs @@ -91,6 +91,32 @@ impl Accessor { Accessor { accessor } } + /// Creates a new Accessor instance based on an existing Accessor's binder. + /// This is useful when the Accessor instance is hosted in another process + /// that has the permissions to create the socket connection FD. + /// + /// The `instance` argument must match the instance that the original Accessor + /// is responsible for. + /// `instance` must not contain null bytes and is used to create a CString to + /// pass through FFI. + /// The `binder` argument must be a valid binder from an Accessor + pub fn from_binder(instance: &str, binder: SpIBinder) -> Option<Accessor> { + let inst = CString::new(instance).unwrap(); + + // Safety: All `SpIBinder` objects (the `binder` argument) hold a valid pointer + // to an `AIBinder` that is guaranteed to remain valid for the lifetime of the + // SpIBinder. `ABinderRpc_Accessor_fromBinder` creates a new pointer to that binder + // that it is responsible for. + // The `inst` argument is a new CString that will copied by + // `ABinderRpc_Accessor_fromBinder` and not modified. + let accessor = + unsafe { sys::ABinderRpc_Accessor_fromBinder(inst.as_ptr(), binder.as_raw()) }; + if accessor.is_null() { + return None; + } + Some(Accessor { accessor }) + } + /// Get the underlying binder for this Accessor for when it needs to be either /// registered with service manager or sent to another process. pub fn as_binder(&self) -> Option<SpIBinder> { diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs index 0e793e5761..da4f128e67 100644 --- a/libs/binder/rust/tests/integration.rs +++ b/libs/binder/rust/tests/integration.rs @@ -1038,6 +1038,34 @@ mod tests { assert!(deleted.load(Ordering::Relaxed)); } + #[test] + fn test_accessor_from_accessor_binder() { + let get_connection_info = move |_instance: &str| None; + let accessor = Accessor::new("foo.service", get_connection_info); + let accessor2 = + Accessor::from_binder("foo.service", accessor.as_binder().unwrap()).unwrap(); + assert_eq!(accessor.as_binder(), accessor2.as_binder()); + } + + #[test] + fn test_accessor_from_non_accessor_binder() { + let service_name = "rust_test_ibinder"; + let _process = ScopedServiceProcess::new(service_name); + let binder = binder::get_service(service_name).unwrap(); + assert!(binder.is_binder_alive()); + + let accessor = Accessor::from_binder("rust_test_ibinder", binder); + assert!(accessor.is_none()); + } + + #[test] + fn test_accessor_from_wrong_accessor_binder() { + let get_connection_info = move |_instance: &str| None; + let accessor = Accessor::new("foo.service", get_connection_info); + let accessor2 = Accessor::from_binder("NOT.foo.service", accessor.as_binder().unwrap()); + assert!(accessor2.is_none()); + } + #[tokio::test] async fn reassociate_rust_binder_async() { let service_name = "testing_service"; diff --git a/libs/input/InputConsumerNoResampling.cpp b/libs/input/InputConsumerNoResampling.cpp index 2c0f77a814..cd8582182a 100644 --- a/libs/input/InputConsumerNoResampling.cpp +++ b/libs/input/InputConsumerNoResampling.cpp @@ -169,6 +169,12 @@ InputMessage createTimelineMessage(int32_t inputEventId, nsecs_t gpuCompletedTim msg.body.timeline.graphicsTimeline[GraphicsTimeline::PRESENT_TIME] = presentTime; return msg; } + +std::ostream& operator<<(std::ostream& out, const InputMessage& msg) { + out << ftl::enum_string(msg.header.type); + return out; +} + } // namespace // --- InputConsumerNoResampling --- @@ -272,6 +278,15 @@ void InputConsumerNoResampling::processOutboundEvents() { return; // try again later } + if (result == DEAD_OBJECT) { + // If there's no one to receive events in the channel, there's no point in sending them. + // Drop all outbound events. + LOG(INFO) << "Channel " << mChannel->getName() << " died. Dropping outbound event " + << outboundMsg; + mOutboundQueue.pop(); + setFdEvents(0); + continue; + } // Some other error. Give up LOG(FATAL) << "Failed to send outbound event on channel '" << mChannel->getName() << "'. status=" << statusToString(result) << "(" << result << ")"; diff --git a/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp b/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp index 39bb841c0a..1dadae98e4 100644 --- a/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp +++ b/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp @@ -319,6 +319,8 @@ protected: protected: // Interaction with the looper thread + void blockLooper(); + void unblockLooper(); enum class LooperMessage : int { CALL_PROBABLY_HAS_INPUT, CREATE_CONSUMER, @@ -389,6 +391,26 @@ private: }; }; +void InputPublisherAndConsumerNoResamplingTest::blockLooper() { + { + std::scoped_lock l(mLock); + mLooperMayProceed = false; + } + sendMessage(LooperMessage::BLOCK_LOOPER); + { + std::unique_lock l(mLock); + mNotifyLooperWaiting.wait(l, [this] { return mLooperIsBlocked; }); + } +} + +void InputPublisherAndConsumerNoResamplingTest::unblockLooper() { + { + std::scoped_lock l(mLock); + mLooperMayProceed = true; + } + mNotifyLooperMayProceed.notify_all(); +} + void InputPublisherAndConsumerNoResamplingTest::sendMessage(LooperMessage message) { Message msg{ftl::to_underlying(message)}; mLooper->sendMessage(mMessageHandler, msg); @@ -600,15 +622,7 @@ void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeSinglePointerMu std::queue<uint32_t> publishedSequenceNumbers; // Block Looper to increase the chance of batching events - { - std::scoped_lock l(mLock); - mLooperMayProceed = false; - } - sendMessage(LooperMessage::BLOCK_LOOPER); - { - std::unique_lock l(mLock); - mNotifyLooperWaiting.wait(l, [this] { return mLooperIsBlocked; }); - } + blockLooper(); uint32_t firstSampleId; for (size_t i = 0; i < nSamples; ++i) { @@ -629,12 +643,7 @@ void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeSinglePointerMu std::vector<MotionEvent> singleSampledMotionEvents; - // Unblock Looper - { - std::scoped_lock l(mLock); - mLooperMayProceed = true; - } - mNotifyLooperMayProceed.notify_all(); + unblockLooper(); // We have no control over the socket behavior, so the consumer can receive // the motion as a batched event, or as a sequence of multiple single-sample MotionEvents (or a @@ -809,6 +818,15 @@ void InputPublisherAndConsumerNoResamplingTest::publishAndConsumeTouchModeEvent( verifyFinishedSignal(*mPublisher, seq, publishTime); } +/** + * If the publisher has died, consumer should not crash when trying to send an outgoing message. + */ +TEST_F(InputPublisherAndConsumerNoResamplingTest, ConsumerWritesAfterPublisherDies) { + mPublisher.reset(); // The publisher has died + mReportTimelineArgs.emplace(/*inputEventId=*/10, /*gpuCompletedTime=*/20, /*presentTime=*/30); + sendMessage(LooperMessage::CALL_REPORT_TIMELINE); +} + TEST_F(InputPublisherAndConsumerNoResamplingTest, SendTimeline) { const int32_t inputEventId = 20; const nsecs_t gpuCompletedTime = 30; diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp index 006d507a40..38e5974c3f 100644 --- a/services/inputflinger/PointerChoreographer.cpp +++ b/services/inputflinger/PointerChoreographer.cpp @@ -139,23 +139,24 @@ PointerChoreographer::PointerChoreographer( mShowTouchesEnabled(false), mStylusPointerIconEnabled(false), mCurrentFocusedDisplay(ui::LogicalDisplayId::DEFAULT), + mIsWindowInfoListenerRegistered(false), + mWindowInfoListener(sp<PointerChoreographerDisplayInfoListener>::make(this)), mRegisterListener(registerListener), mUnregisterListener(unregisterListener) {} PointerChoreographer::~PointerChoreographer() { - std::scoped_lock _l(mLock); - if (mWindowInfoListener == nullptr) { - return; + if (mIsWindowInfoListenerRegistered) { + mUnregisterListener(mWindowInfoListener); + mIsWindowInfoListenerRegistered = false; } mWindowInfoListener->onPointerChoreographerDestroyed(); - mUnregisterListener(mWindowInfoListener); } void PointerChoreographer::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) { PointerDisplayChange pointerDisplayChange; { // acquire lock - std::scoped_lock _l(mLock); + std::scoped_lock _l(getLock()); mInputDeviceInfos = args.inputDeviceInfos; pointerDisplayChange = updatePointerControllersLocked(); @@ -191,7 +192,7 @@ void PointerChoreographer::fadeMouseCursorOnKeyPress(const android::NotifyKeyArg return; } - std::scoped_lock _l(mLock); + std::scoped_lock _l(getLock()); ui::LogicalDisplayId targetDisplay = args.displayId; if (targetDisplay == ui::LogicalDisplayId::INVALID) { targetDisplay = mCurrentFocusedDisplay; @@ -204,7 +205,7 @@ void PointerChoreographer::fadeMouseCursorOnKeyPress(const android::NotifyKeyArg } NotifyMotionArgs PointerChoreographer::processMotion(const NotifyMotionArgs& args) { - std::scoped_lock _l(mLock); + std::scoped_lock _l(getLock()); if (isFromMouse(args)) { return processMouseEventLocked(args); @@ -242,14 +243,7 @@ NotifyMotionArgs PointerChoreographer::processMouseEventLocked(const NotifyMotio pc.setPosition(args.xCursorPosition, args.yCursorPosition); } else { // This is a relative mouse, so move the cursor by the specified amount. - const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); - const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); - pc.move(deltaX, deltaY); - const auto [x, y] = pc.getPosition(); - newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); - newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - newArgs.xCursorPosition = x; - newArgs.yCursorPosition = y; + processPointerDeviceMotionEventLocked(/*byref*/ newArgs, /*byref*/ pc); } if (canUnfadeOnDisplay(displayId)) { pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); @@ -265,24 +259,9 @@ NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMo newArgs.displayId = displayId; if (args.getPointerCount() == 1 && args.classification == MotionClassification::NONE) { // This is a movement of the mouse pointer. - const float deltaX = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); - const float deltaY = args.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); - pc.move(deltaX, deltaY); - if (canUnfadeOnDisplay(displayId)) { - pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); - } - - const auto [x, y] = pc.getPosition(); - newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); - newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - newArgs.xCursorPosition = x; - newArgs.yCursorPosition = y; + processPointerDeviceMotionEventLocked(/*byref*/ newArgs, /*byref*/ pc); } else { // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer. - if (canUnfadeOnDisplay(displayId)) { - pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); - } - const auto [x, y] = pc.getPosition(); for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) { newArgs.pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_X, @@ -293,9 +272,25 @@ NotifyMotionArgs PointerChoreographer::processTouchpadEventLocked(const NotifyMo newArgs.xCursorPosition = x; newArgs.yCursorPosition = y; } + if (canUnfadeOnDisplay(displayId)) { + pc.unfade(PointerControllerInterface::Transition::IMMEDIATE); + } return newArgs; } +void PointerChoreographer::processPointerDeviceMotionEventLocked(NotifyMotionArgs& newArgs, + PointerControllerInterface& pc) { + const float deltaX = newArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X); + const float deltaY = newArgs.pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y); + + pc.move(deltaX, deltaY); + const auto [x, y] = pc.getPosition(); + newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); + newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); + newArgs.xCursorPosition = x; + newArgs.yCursorPosition = y; +} + void PointerChoreographer::processDrawingTabletEventLocked(const android::NotifyMotionArgs& args) { if (args.displayId == ui::LogicalDisplayId::INVALID) { return; @@ -433,7 +428,7 @@ void PointerChoreographer::notifyDeviceReset(const NotifyDeviceResetArgs& args) } void PointerChoreographer::processDeviceReset(const NotifyDeviceResetArgs& args) { - std::scoped_lock _l(mLock); + std::scoped_lock _l(getLock()); mTouchPointersByDevice.erase(args.deviceId); mStylusPointersByDevice.erase(args.deviceId); mDrawingTabletPointersByDevice.erase(args.deviceId); @@ -447,17 +442,22 @@ void PointerChoreographer::onControllerAddedOrRemovedLocked() { bool requireListener = !mTouchPointersByDevice.empty() || !mMousePointersByDisplay.empty() || !mDrawingTabletPointersByDevice.empty() || !mStylusPointersByDevice.empty(); - if (requireListener && mWindowInfoListener == nullptr) { - mWindowInfoListener = sp<PointerChoreographerDisplayInfoListener>::make(this); - mWindowInfoListener->setInitialDisplayInfos(mRegisterListener(mWindowInfoListener)); - onPrivacySensitiveDisplaysChangedLocked(mWindowInfoListener->getPrivacySensitiveDisplays()); - } else if (!requireListener && mWindowInfoListener != nullptr) { + // PointerChoreographer uses Listener's lock which is already held by caller + base::ScopedLockAssertion assumeLocked(mWindowInfoListener->mLock); + + if (requireListener && !mIsWindowInfoListenerRegistered) { + mIsWindowInfoListenerRegistered = true; + mWindowInfoListener->setInitialDisplayInfosLocked(mRegisterListener(mWindowInfoListener)); + onPrivacySensitiveDisplaysChangedLocked( + mWindowInfoListener->getPrivacySensitiveDisplaysLocked()); + } else if (!requireListener && mIsWindowInfoListenerRegistered) { + mIsWindowInfoListenerRegistered = false; mUnregisterListener(mWindowInfoListener); - mWindowInfoListener = nullptr; - } else if (requireListener && mWindowInfoListener != nullptr) { + } else if (requireListener) { // controller may have been added to an existing privacy sensitive display, we need to // update all controllers again - onPrivacySensitiveDisplaysChangedLocked(mWindowInfoListener->getPrivacySensitiveDisplays()); + onPrivacySensitiveDisplaysChangedLocked( + mWindowInfoListener->getPrivacySensitiveDisplaysLocked()); } } @@ -494,7 +494,7 @@ void PointerChoreographer::onPrivacySensitiveDisplaysChangedLocked( void PointerChoreographer::notifyPointerCaptureChanged( const NotifyPointerCaptureChangedArgs& args) { if (args.request.isEnable()) { - std::scoped_lock _l(mLock); + std::scoped_lock _l(getLock()); for (const auto& [_, mousePointerController] : mMousePointersByDisplay) { mousePointerController->fade(PointerControllerInterface::Transition::IMMEDIATE); } @@ -502,14 +502,8 @@ void PointerChoreographer::notifyPointerCaptureChanged( mNextListener.notify(args); } -void PointerChoreographer::onPrivacySensitiveDisplaysChanged( - const std::unordered_set<ui::LogicalDisplayId>& privacySensitiveDisplays) { - std::scoped_lock _l(mLock); - onPrivacySensitiveDisplaysChangedLocked(privacySensitiveDisplays); -} - void PointerChoreographer::dump(std::string& dump) { - std::scoped_lock _l(mLock); + std::scoped_lock _l(getLock()); dump += "PointerChoreographer:\n"; dump += StringPrintf(INDENT "Show Touches Enabled: %s\n", @@ -579,6 +573,10 @@ bool PointerChoreographer::canUnfadeOnDisplay(ui::LogicalDisplayId displayId) { return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end(); } +std::mutex& PointerChoreographer::getLock() const { + return mWindowInfoListener->mLock; +} + PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerControllersLocked() { std::set<ui::LogicalDisplayId /*displayId*/> mouseDisplaysToKeep; std::set<DeviceId> touchDevicesToKeep; @@ -641,7 +639,7 @@ PointerChoreographer::PointerDisplayChange PointerChoreographer::updatePointerCo std::erase_if(mDrawingTabletPointersByDevice, [&drawingTabletDevicesToKeep](const auto& pair) { return drawingTabletDevicesToKeep.find(pair.first) == drawingTabletDevicesToKeep.end(); }); - std::erase_if(mMouseDevices, [&](DeviceId id) REQUIRES(mLock) { + std::erase_if(mMouseDevices, [&](DeviceId id) REQUIRES(getLock()) { return std::find_if(mInputDeviceInfos.begin(), mInputDeviceInfos.end(), [id](const auto& info) { return info.getId() == id; }) == mInputDeviceInfos.end(); @@ -677,7 +675,7 @@ void PointerChoreographer::setDefaultMouseDisplayId(ui::LogicalDisplayId display PointerDisplayChange pointerDisplayChange; { // acquire lock - std::scoped_lock _l(mLock); + std::scoped_lock _l(getLock()); mDefaultMouseDisplayId = displayId; pointerDisplayChange = updatePointerControllersLocked(); @@ -690,7 +688,7 @@ void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport PointerDisplayChange pointerDisplayChange; { // acquire lock - std::scoped_lock _l(mLock); + std::scoped_lock _l(getLock()); for (const auto& viewport : viewports) { const ui::LogicalDisplayId displayId = viewport.displayId; if (const auto it = mMousePointersByDisplay.find(displayId); @@ -719,7 +717,7 @@ void PointerChoreographer::setDisplayViewports(const std::vector<DisplayViewport std::optional<DisplayViewport> PointerChoreographer::getViewportForPointerDevice( ui::LogicalDisplayId associatedDisplayId) { - std::scoped_lock _l(mLock); + std::scoped_lock _l(getLock()); const ui::LogicalDisplayId resolvedDisplayId = getTargetMouseDisplayLocked(associatedDisplayId); if (const auto viewport = findViewportByIdLocked(resolvedDisplayId); viewport) { return *viewport; @@ -728,7 +726,7 @@ std::optional<DisplayViewport> PointerChoreographer::getViewportForPointerDevice } FloatPoint PointerChoreographer::getMouseCursorPosition(ui::LogicalDisplayId displayId) { - std::scoped_lock _l(mLock); + std::scoped_lock _l(getLock()); const ui::LogicalDisplayId resolvedDisplayId = getTargetMouseDisplayLocked(displayId); if (auto it = mMousePointersByDisplay.find(resolvedDisplayId); it != mMousePointersByDisplay.end()) { @@ -741,7 +739,7 @@ void PointerChoreographer::setShowTouchesEnabled(bool enabled) { PointerDisplayChange pointerDisplayChange; { // acquire lock - std::scoped_lock _l(mLock); + std::scoped_lock _l(getLock()); if (mShowTouchesEnabled == enabled) { return; } @@ -756,7 +754,7 @@ void PointerChoreographer::setStylusPointerIconEnabled(bool enabled) { PointerDisplayChange pointerDisplayChange; { // acquire lock - std::scoped_lock _l(mLock); + std::scoped_lock _l(getLock()); if (mStylusPointerIconEnabled == enabled) { return; } @@ -770,7 +768,7 @@ void PointerChoreographer::setStylusPointerIconEnabled(bool enabled) { bool PointerChoreographer::setPointerIcon( std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon, ui::LogicalDisplayId displayId, DeviceId deviceId) { - std::scoped_lock _l(mLock); + std::scoped_lock _l(getLock()); if (deviceId < 0) { LOG(WARNING) << "Invalid device id " << deviceId << ". Cannot set pointer icon."; return false; @@ -821,7 +819,7 @@ bool PointerChoreographer::setPointerIcon( } void PointerChoreographer::setPointerIconVisibility(ui::LogicalDisplayId displayId, bool visible) { - std::scoped_lock lock(mLock); + std::scoped_lock lock(getLock()); if (visible) { mDisplaysWithPointersHidden.erase(displayId); // We do not unfade the icons here, because we don't know when the last event happened. @@ -843,14 +841,14 @@ void PointerChoreographer::setPointerIconVisibility(ui::LogicalDisplayId display } void PointerChoreographer::setFocusedDisplay(ui::LogicalDisplayId displayId) { - std::scoped_lock lock(mLock); + std::scoped_lock lock(getLock()); mCurrentFocusedDisplay = displayId; } PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor( ui::LogicalDisplayId displayId) { std::function<std::shared_ptr<PointerControllerInterface>()> ctor = - [this, displayId]() REQUIRES(mLock) { + [this, displayId]() REQUIRES(getLock()) { auto pc = mPolicy.createPointerController( PointerControllerInterface::ControllerType::MOUSE); if (const auto viewport = findViewportByIdLocked(displayId); viewport) { @@ -864,7 +862,7 @@ PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseContro PointerChoreographer::ControllerConstructor PointerChoreographer::getStylusControllerConstructor( ui::LogicalDisplayId displayId) { std::function<std::shared_ptr<PointerControllerInterface>()> ctor = - [this, displayId]() REQUIRES(mLock) { + [this, displayId]() REQUIRES(getLock()) { auto pc = mPolicy.createPointerController( PointerControllerInterface::ControllerType::STYLUS); if (const auto viewport = findViewportByIdLocked(displayId); viewport) { @@ -875,9 +873,11 @@ PointerChoreographer::ControllerConstructor PointerChoreographer::getStylusContr return ConstructorDelegate(std::move(ctor)); } +// --- PointerChoreographer::PointerChoreographerDisplayInfoListener --- + void PointerChoreographer::PointerChoreographerDisplayInfoListener::onWindowInfosChanged( const gui::WindowInfosUpdate& windowInfosUpdate) { - std::scoped_lock _l(mListenerLock); + std::scoped_lock _l(mLock); if (mPointerChoreographer == nullptr) { return; } @@ -885,25 +885,25 @@ void PointerChoreographer::PointerChoreographerDisplayInfoListener::onWindowInfo getPrivacySensitiveDisplaysFromWindowInfos(windowInfosUpdate.windowInfos); if (newPrivacySensitiveDisplays != mPrivacySensitiveDisplays) { mPrivacySensitiveDisplays = std::move(newPrivacySensitiveDisplays); - mPointerChoreographer->onPrivacySensitiveDisplaysChanged(mPrivacySensitiveDisplays); + // PointerChoreographer uses Listener's lock. + base::ScopedLockAssertion assumeLocked(mPointerChoreographer->getLock()); + mPointerChoreographer->onPrivacySensitiveDisplaysChangedLocked(mPrivacySensitiveDisplays); } } -void PointerChoreographer::PointerChoreographerDisplayInfoListener::setInitialDisplayInfos( +void PointerChoreographer::PointerChoreographerDisplayInfoListener::setInitialDisplayInfosLocked( const std::vector<gui::WindowInfo>& windowInfos) { - std::scoped_lock _l(mListenerLock); mPrivacySensitiveDisplays = getPrivacySensitiveDisplaysFromWindowInfos(windowInfos); } std::unordered_set<ui::LogicalDisplayId /*displayId*/> -PointerChoreographer::PointerChoreographerDisplayInfoListener::getPrivacySensitiveDisplays() { - std::scoped_lock _l(mListenerLock); +PointerChoreographer::PointerChoreographerDisplayInfoListener::getPrivacySensitiveDisplaysLocked() { return mPrivacySensitiveDisplays; } void PointerChoreographer::PointerChoreographerDisplayInfoListener:: onPointerChoreographerDestroyed() { - std::scoped_lock _l(mListenerLock); + std::scoped_lock _l(mLock); mPointerChoreographer = nullptr; } diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h index 635487be6b..fba1aef260 100644 --- a/services/inputflinger/PointerChoreographer.h +++ b/services/inputflinger/PointerChoreographer.h @@ -118,31 +118,40 @@ public: 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 processPointerDeviceMotionEventLocked(NotifyMotionArgs& newArgs, + PointerControllerInterface& pc) 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 +165,50 @@ private: 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); - - 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); + GUARDED_BY(getLock()); + + 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 +221,10 @@ protected: 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; }; diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp index a040c88e78..143c192686 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp @@ -589,28 +589,30 @@ void OutputLayer::writeOutputIndependentGeometryStateToHWC( void OutputLayer::writeLutToHWC(HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) { - if (!outputIndependentState.luts) { - return; - } - auto& lutFileDescriptor = outputIndependentState.luts->getLutFileDescriptor(); - auto lutOffsets = outputIndependentState.luts->offsets; - auto& lutProperties = outputIndependentState.luts->lutProperties; + Luts luts; + // if outputIndependentState.luts is nullptr, it means we want to clear the LUTs + // and we pass an empty Luts object to the HWC. + if (outputIndependentState.luts) { + auto& lutFileDescriptor = outputIndependentState.luts->getLutFileDescriptor(); + auto lutOffsets = outputIndependentState.luts->offsets; + auto& lutProperties = outputIndependentState.luts->lutProperties; + + std::vector<LutProperties> aidlProperties; + aidlProperties.reserve(lutProperties.size()); + for (size_t i = 0; i < lutOffsets.size(); i++) { + LutProperties properties; + properties.dimension = static_cast<LutProperties::Dimension>(lutProperties[i].dimension); + properties.size = lutProperties[i].size; + properties.samplingKeys = { + static_cast<LutProperties::SamplingKey>(lutProperties[i].samplingKey)}; + aidlProperties.emplace_back(properties); + } - std::vector<LutProperties> aidlProperties; - aidlProperties.reserve(lutProperties.size()); - for (size_t i = 0; i < lutOffsets.size(); i++) { - LutProperties properties; - properties.dimension = static_cast<LutProperties::Dimension>(lutProperties[i].dimension); - properties.size = lutProperties[i].size; - properties.samplingKeys = { - static_cast<LutProperties::SamplingKey>(lutProperties[i].samplingKey)}; - aidlProperties.emplace_back(properties); - } - Luts luts; - luts.pfd = ndk::ScopedFileDescriptor(dup(lutFileDescriptor.get())); - luts.offsets = lutOffsets; - luts.lutProperties = std::move(aidlProperties); + luts.pfd = ndk::ScopedFileDescriptor(dup(lutFileDescriptor.get())); + luts.offsets = lutOffsets; + luts.lutProperties = std::move(aidlProperties); + } switch (auto error = hwcLayer->setLuts(luts)) { case hal::Error::NONE: diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp index dbffe80a3a..034c768ff3 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp @@ -901,6 +901,7 @@ struct OutputLayerWriteStateToHWCTest : public OutputLayerTest { EXPECT_CALL(*mHwcLayer, setSurfaceDamage(RegionEq(surfaceDamage))).WillOnce(Return(kError)); EXPECT_CALL(*mHwcLayer, setBlockingRegion(RegionEq(blockingRegion))) .WillOnce(Return(kError)); + EXPECT_CALL(*mHwcLayer, setLuts(_)).WillOnce(Return(kError)); } void expectSetCompositionTypeCall(Composition compositionType) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 2c4fcf546b..f9e59b914c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -9177,26 +9177,46 @@ binder::Status SurfaceComposerAIDL::setGameDefaultFrameRateOverride(int32_t uid, } binder::Status SurfaceComposerAIDL::enableRefreshRateOverlay(bool active) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->sfdo_enableRefreshRateOverlay(active); return binder::Status::ok(); } binder::Status SurfaceComposerAIDL::setDebugFlash(int delay) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->sfdo_setDebugFlash(delay); return binder::Status::ok(); } binder::Status SurfaceComposerAIDL::scheduleComposite() { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->sfdo_scheduleComposite(); return binder::Status::ok(); } binder::Status SurfaceComposerAIDL::scheduleCommit() { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->sfdo_scheduleCommit(); return binder::Status::ok(); } binder::Status SurfaceComposerAIDL::forceClientComposition(bool enabled) { + status_t status = checkAccessPermission(); + if (status != OK) { + return binderStatusFromStatusT(status); + } mFlinger->sfdo_forceClientComposition(enabled); return binder::Status::ok(); } |