Merge changes from topic "vulkan-1.4" into main

* changes:
  Update libvulkan linker map for 1.4
  Add feature xml for Vulkan version 1.4
  Add support for Vulkan 1.4 core entrypoints to nulldrv
  Allow vkjson to report on 1.4 instances
  Add support for vulkan api level 1.4 in loader
  Regenerate vulkan-loader for 1.4
diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h
index 917d9a7..203623d 100644
--- a/include/audiomanager/AudioManager.h
+++ b/include/audiomanager/AudioManager.h
@@ -22,6 +22,7 @@
 // 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 @@
     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 @@
     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 @@
         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 3da59ab..1a58d6b 100644
--- a/libs/binder/rust/src/system_only.rs
+++ b/libs/binder/rust/src/system_only.rs
@@ -91,6 +91,32 @@
         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 0e793e5..da4f128 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -1038,6 +1038,34 @@
         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 2c0f77a..cd85821 100644
--- a/libs/input/InputConsumerNoResampling.cpp
+++ b/libs/input/InputConsumerNoResampling.cpp
@@ -169,6 +169,12 @@
     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 @@
             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 39bb841..1dadae9 100644
--- a/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumerNoResampling_test.cpp
@@ -319,6 +319,8 @@
 
 protected:
     // Interaction with the looper thread
+    void blockLooper();
+    void unblockLooper();
     enum class LooperMessage : int {
         CALL_PROBABLY_HAS_INPUT,
         CREATE_CONSUMER,
@@ -389,6 +391,26 @@
     };
 };
 
+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 @@
     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 @@
 
     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 @@
     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 006d507..38e5974 100644
--- a/services/inputflinger/PointerChoreographer.cpp
+++ b/services/inputflinger/PointerChoreographer.cpp
@@ -139,23 +139,24 @@
         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 @@
         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 @@
 }
 
 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 @@
         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 @@
     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 @@
         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::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 @@
     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::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 @@
     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 @@
     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 @@
     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 @@
     PointerDisplayChange pointerDisplayChange;
 
     { // acquire lock
-        std::scoped_lock _l(mLock);
+        std::scoped_lock _l(getLock());
 
         mDefaultMouseDisplayId = displayId;
         pointerDisplayChange = updatePointerControllersLocked();
@@ -690,7 +688,7 @@
     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 @@
 
 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 @@
 }
 
 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 @@
     PointerDisplayChange pointerDisplayChange;
 
     { // acquire lock
-        std::scoped_lock _l(mLock);
+        std::scoped_lock _l(getLock());
         if (mShowTouchesEnabled == enabled) {
             return;
         }
@@ -756,7 +754,7 @@
     PointerDisplayChange pointerDisplayChange;
 
     { // acquire lock
-        std::scoped_lock _l(mLock);
+        std::scoped_lock _l(getLock());
         if (mStylusPointerIconEnabled == enabled) {
             return;
         }
@@ -770,7 +768,7 @@
 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 @@
 }
 
 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::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::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 @@
     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 @@
             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 635487b..fba1aef 100644
--- a/services/inputflinger/PointerChoreographer.h
+++ b/services/inputflinger/PointerChoreographer.h
@@ -118,31 +118,40 @@
 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 @@
         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 +221,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;
 };
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index a040c88..143c192 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -589,28 +589,30 @@
 
 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;
-
-    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);
+    // 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);
+        }
+
+
+        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 dbffe80..034c768 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -901,6 +901,7 @@
         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 2c4fcf5..f9e59b9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -9177,26 +9177,46 @@
 }
 
 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();
 }