Merge "Rate limit user activity pokes in InputDispatcher" into main
diff --git a/include/android/asset_manager.h b/include/android/asset_manager.h
index 2ac7d4d..6420cd0 100644
--- a/include/android/asset_manager.h
+++ b/include/android/asset_manager.h
@@ -29,6 +29,10 @@
 #include <sys/cdefs.h>
 #include <sys/types.h>
 
+#if defined(__APPLE__)
+typedef off_t off64_t; // Mac OSX does not define off64_t
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/include/android/performance_hint.h b/include/android/performance_hint.h
index 30200c7..08d339b 100644
--- a/include/android/performance_hint.h
+++ b/include/android/performance_hint.h
@@ -240,7 +240,7 @@
  *     the actual GPU duration is not measured.
  *
  * @return 0 on success.
- *         EINVAL if session is nullptr or any duration is an invalid number.
+ *         EINVAL if any duration is an invalid number.
  *         EPIPE if communication with the system service has failed.
  */
 int APerformanceHint_reportActualWorkDuration2(
@@ -269,7 +269,7 @@
  *
  * @param aWorkDuration The {@link AWorkDuration} created by calling {@link AWorkDuration_create()}
  * @param workPeriodStartTimestampNanos The work period start timestamp in nanoseconds based on
- *        CLOCK_MONOTONIC about when the work starts, the timestamp must be positive.
+ *        CLOCK_MONOTONIC about when the work starts. This timestamp must be greater than zero.
  */
 void AWorkDuration_setWorkPeriodStartTimestampNanos(AWorkDuration* _Nonnull aWorkDuration,
         int64_t workPeriodStartTimestampNanos) __INTRODUCED_IN(__ANDROID_API_V__);
@@ -278,8 +278,8 @@
  * Sets the actual total work duration in nanoseconds.
  *
  * @param aWorkDuration The {@link AWorkDuration} created by calling {@link AWorkDuration_create()}
- * @param actualTotalDurationNanos The actual total work duration in nanoseconds, the number must be
- *        positive.
+ * @param actualTotalDurationNanos The actual total work duration in nanoseconds. This number must
+ *        be greater than zero.
  */
 void AWorkDuration_setActualTotalDurationNanos(AWorkDuration* _Nonnull aWorkDuration,
         int64_t actualTotalDurationNanos) __INTRODUCED_IN(__ANDROID_API_V__);
@@ -288,8 +288,8 @@
  * Sets the actual CPU work duration in nanoseconds.
  *
  * @param aWorkDuration The {@link AWorkDuration} created by calling {@link AWorkDuration_create()}
- * @param actualCpuDurationNanos The actual CPU work duration in nanoseconds, the number must be
- *        positive.
+ * @param actualCpuDurationNanos The actual CPU work duration in nanoseconds. This number must be
+ *        greater than zero.
  */
 void AWorkDuration_setActualCpuDurationNanos(AWorkDuration* _Nonnull aWorkDuration,
         int64_t actualCpuDurationNanos) __INTRODUCED_IN(__ANDROID_API_V__);
diff --git a/include/powermanager/PowerHalController.h b/include/powermanager/PowerHalController.h
index 9e426d3..c50bc4a 100644
--- a/include/powermanager/PowerHalController.h
+++ b/include/powermanager/PowerHalController.h
@@ -62,7 +62,15 @@
     virtual HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>>
     createHintSession(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
                       int64_t durationNanos) override;
+    virtual HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>>
+    createHintSessionWithConfig(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
+                                int64_t durationNanos,
+                                aidl::android::hardware::power::SessionTag tag,
+                                aidl::android::hardware::power::SessionConfig* config) override;
     virtual HalResult<int64_t> getHintSessionPreferredRate() override;
+    virtual HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(
+            int tgid, int uid) override;
+    virtual HalResult<void> closeSessionChannel(int tgid, int uid) override;
 
 private:
     std::mutex mConnectedHalMutex;
@@ -75,7 +83,7 @@
 
     std::shared_ptr<HalWrapper> initHal();
     template <typename T>
-    HalResult<T> processHalResult(HalResult<T> result, const char* functionName);
+    HalResult<T> processHalResult(HalResult<T>&& result, const char* functionName);
 };
 
 // -------------------------------------------------------------------------------------------------
diff --git a/include/powermanager/PowerHalWrapper.h b/include/powermanager/PowerHalWrapper.h
index 4e4a1b0..e2da014 100644
--- a/include/powermanager/PowerHalWrapper.h
+++ b/include/powermanager/PowerHalWrapper.h
@@ -14,19 +14,22 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_POWERHALWRAPPER_H
-#define ANDROID_POWERHALWRAPPER_H
+#pragma once
 
 #include <aidl/android/hardware/power/Boost.h>
+#include <aidl/android/hardware/power/ChannelConfig.h>
 #include <aidl/android/hardware/power/IPower.h>
 #include <aidl/android/hardware/power/IPowerHintSession.h>
 #include <aidl/android/hardware/power/Mode.h>
+#include <aidl/android/hardware/power/SessionConfig.h>
 #include <android-base/thread_annotations.h>
 #include <android/hardware/power/1.1/IPower.h>
 #include <android/hardware/power/1.2/IPower.h>
 #include <android/hardware/power/1.3/IPower.h>
 #include <binder/Status.h>
 
+#include <utility>
+
 namespace android {
 
 namespace power {
@@ -42,44 +45,63 @@
 template <typename T>
 class HalResult {
 public:
-    static HalResult<T> ok(T value) { return HalResult(value); }
-    static HalResult<T> failed(std::string msg) {
-        return HalResult(std::move(msg), /* unsupported= */ false);
-    }
+    static HalResult<T> ok(T&& value) { return HalResult(std::forward<T>(value)); }
+    static HalResult<T> ok(T& value) { return HalResult<T>::ok(T{value}); }
+    static HalResult<T> failed(std::string msg) { return HalResult(msg, /* unsupported= */ false); }
     static HalResult<T> unsupported() { return HalResult("", /* unsupported= */ true); }
 
-    static HalResult<T> fromStatus(const binder::Status& status, T data) {
+    static HalResult<T> fromStatus(const binder::Status& status, T&& data) {
         if (status.exceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
             return HalResult<T>::unsupported();
         }
         if (status.isOk()) {
-            return HalResult<T>::ok(data);
+            return HalResult<T>::ok(std::forward<T>(data));
         }
         return HalResult<T>::failed(std::string(status.toString8().c_str()));
     }
 
-    static HalResult<T> fromStatus(const ndk::ScopedAStatus& status, T data) {
+    static HalResult<T> fromStatus(const binder::Status& status, T& data) {
+        return HalResult<T>::fromStatus(status, T{data});
+    }
+
+    static HalResult<T> fromStatus(const ndk::ScopedAStatus& status, T&& data) {
         if (status.getExceptionCode() == binder::Status::EX_UNSUPPORTED_OPERATION) {
             return HalResult<T>::unsupported();
         }
         if (status.isOk()) {
-            return HalResult<T>::ok(data);
+            return HalResult<T>::ok(std::forward<T>(data));
         }
         return HalResult<T>::failed(std::string(status.getDescription()));
     }
 
+    static HalResult<T> fromStatus(const ndk::ScopedAStatus& status, T& data) {
+        return HalResult<T>::fromStatus(status, T{data});
+    }
+
     template <typename R>
-    static HalResult<T> fromReturn(hardware::Return<R>& ret, T data) {
-        return ret.isOk() ? HalResult<T>::ok(data) : HalResult<T>::failed(ret.description());
+    static HalResult<T> fromReturn(hardware::Return<R>& ret, T&& data) {
+        return ret.isOk() ? HalResult<T>::ok(std::forward<T>(data))
+                          : HalResult<T>::failed(ret.description());
+    }
+
+    template <typename R>
+    static HalResult<T> fromReturn(hardware::Return<R>& ret, T& data) {
+        return HalResult<T>::fromReturn(ret, T{data});
     }
 
     template <typename R>
     static HalResult<T> fromReturn(hardware::Return<R>& ret, hardware::power::V1_0::Status status,
-                                   T data) {
-        return ret.isOk() ? HalResult<T>::fromStatus(status, data)
+                                   T&& data) {
+        return ret.isOk() ? HalResult<T>::fromStatus(status, std::forward<T>(data))
                           : HalResult<T>::failed(ret.description());
     }
 
+    template <typename R>
+    static HalResult<T> fromReturn(hardware::Return<R>& ret, hardware::power::V1_0::Status status,
+                                   T& data) {
+        return HalResult<T>::fromReturn(ret, status, T{data});
+    }
+
     // This will throw std::bad_optional_access if this result is not ok.
     const T& value() const { return mValue.value(); }
     bool isOk() const { return !mUnsupported && mValue.has_value(); }
@@ -92,8 +114,8 @@
     std::string mErrorMessage;
     bool mUnsupported;
 
-    explicit HalResult(T value)
-          : mValue(std::make_optional(value)), mErrorMessage(), mUnsupported(false) {}
+    explicit HalResult(T&& value)
+          : mValue{std::move(value)}, mErrorMessage(), mUnsupported(false) {}
     explicit HalResult(std::string errorMessage, bool unsupported)
           : mValue(), mErrorMessage(std::move(errorMessage)), mUnsupported(unsupported) {}
 };
@@ -158,7 +180,15 @@
     virtual HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>>
     createHintSession(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
                       int64_t durationNanos) = 0;
+    virtual HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>>
+    createHintSessionWithConfig(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
+                                int64_t durationNanos,
+                                aidl::android::hardware::power::SessionTag tag,
+                                aidl::android::hardware::power::SessionConfig* config) = 0;
     virtual HalResult<int64_t> getHintSessionPreferredRate() = 0;
+    virtual HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid,
+                                                                                       int uid) = 0;
+    virtual HalResult<void> closeSessionChannel(int tgid, int uid) = 0;
 };
 
 // Empty Power HAL wrapper that ignores all api calls.
@@ -173,11 +203,22 @@
     HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> createHintSession(
             int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
             int64_t durationNanos) override;
+    HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>>
+    createHintSessionWithConfig(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
+                                int64_t durationNanos,
+                                aidl::android::hardware::power::SessionTag tag,
+                                aidl::android::hardware::power::SessionConfig* config) override;
     HalResult<int64_t> getHintSessionPreferredRate() override;
+    HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid,
+                                                                               int uid) override;
+    HalResult<void> closeSessionChannel(int tgid, int uid) override;
+
+protected:
+    virtual const char* getUnsupportedMessage();
 };
 
 // Wrapper for the HIDL Power HAL v1.0.
-class HidlHalWrapperV1_0 : public HalWrapper {
+class HidlHalWrapperV1_0 : public EmptyHalWrapper {
 public:
     explicit HidlHalWrapperV1_0(sp<hardware::power::V1_0::IPower> handleV1_0)
           : mHandleV1_0(std::move(handleV1_0)) {}
@@ -186,14 +227,11 @@
     HalResult<void> setBoost(aidl::android::hardware::power::Boost boost,
                              int32_t durationMs) override;
     HalResult<void> setMode(aidl::android::hardware::power::Mode mode, bool enabled) override;
-    HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> createHintSession(
-            int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
-            int64_t durationNanos) override;
-    HalResult<int64_t> getHintSessionPreferredRate() override;
 
 protected:
     const sp<hardware::power::V1_0::IPower> mHandleV1_0;
     virtual HalResult<void> sendPowerHint(hardware::power::V1_3::PowerHint hintId, uint32_t data);
+    const char* getUnsupportedMessage();
 
 private:
     HalResult<void> setInteractive(bool enabled);
@@ -238,7 +276,7 @@
 };
 
 // Wrapper for the AIDL Power HAL.
-class AidlHalWrapper : public HalWrapper {
+class AidlHalWrapper : public EmptyHalWrapper {
 public:
     explicit AidlHalWrapper(std::shared_ptr<aidl::android::hardware::power::IPower> handle)
           : mHandle(std::move(handle)) {}
@@ -250,7 +288,19 @@
     HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>> createHintSession(
             int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
             int64_t durationNanos) override;
+    HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>>
+    createHintSessionWithConfig(int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
+                                int64_t durationNanos,
+                                aidl::android::hardware::power::SessionTag tag,
+                                aidl::android::hardware::power::SessionConfig* config) override;
+
     HalResult<int64_t> getHintSessionPreferredRate() override;
+    HalResult<aidl::android::hardware::power::ChannelConfig> getSessionChannel(int tgid,
+                                                                               int uid) override;
+    HalResult<void> closeSessionChannel(int tgid, int uid) override;
+
+protected:
+    const char* getUnsupportedMessage() override;
 
 private:
     // Control access to the boost and mode supported arrays.
@@ -274,5 +324,3 @@
 }; // namespace power
 
 }; // namespace android
-
-#endif // ANDROID_POWERHALWRAPPER_H
diff --git a/services/inputflinger/PointerChoreographer.cpp b/services/inputflinger/PointerChoreographer.cpp
index 4571ef4..3ac4285 100644
--- a/services/inputflinger/PointerChoreographer.cpp
+++ b/services/inputflinger/PointerChoreographer.cpp
@@ -109,7 +109,9 @@
     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);
-    pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
+    if (canUnfadeOnDisplay(displayId)) {
+        pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
+    }
 
     const auto [x, y] = pc.getPosition();
     NotifyMotionArgs newArgs(args);
@@ -131,7 +133,9 @@
         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);
-        pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
+        if (canUnfadeOnDisplay(displayId)) {
+            pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
+        }
 
         const auto [x, y] = pc.getPosition();
         newArgs.pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
@@ -140,7 +144,9 @@
         newArgs.yCursorPosition = y;
     } else {
         // This is a trackpad gesture with fake finger(s) that should not move the mouse pointer.
-        pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
+        if (canUnfadeOnDisplay(displayId)) {
+            pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
+        }
 
         const auto [x, y] = pc.getPosition();
         for (uint32_t i = 0; i < newArgs.getPointerCount(); i++) {
@@ -223,7 +229,7 @@
     if (args.action == AMOTION_EVENT_ACTION_HOVER_EXIT) {
         pc.fade(PointerControllerInterface::Transition::IMMEDIATE);
         pc.updatePointerIcon(PointerIconStyle::TYPE_NOT_SPECIFIED);
-    } else {
+    } else if (canUnfadeOnDisplay(args.displayId)) {
         pc.unfade(PointerControllerInterface::Transition::IMMEDIATE);
     }
 }
@@ -323,6 +329,10 @@
     return it != mInputDeviceInfos.end() ? &(*it) : nullptr;
 }
 
+bool PointerChoreographer::canUnfadeOnDisplay(int32_t displayId) {
+    return mDisplaysWithPointersHidden.find(displayId) == mDisplaysWithPointersHidden.end();
+}
+
 void PointerChoreographer::updatePointerControllersLocked() {
     std::set<int32_t /*displayId*/> mouseDisplaysToKeep;
     std::set<DeviceId> touchDevicesToKeep;
@@ -342,7 +352,7 @@
                     mMousePointersByDisplay.try_emplace(displayId,
                                                         getMouseControllerConstructor(displayId));
             auto [_, isNewMouseDevice] = mMouseDevices.emplace(info.getId());
-            if (isNewMouseDevice || isNewMousePointer) {
+            if ((isNewMouseDevice || isNewMousePointer) && canUnfadeOnDisplay(displayId)) {
                 mousePointerIt->second->unfade(PointerControllerInterface::Transition::IMMEDIATE);
             }
         }
@@ -513,6 +523,28 @@
     return true;
 }
 
+void PointerChoreographer::setPointerIconVisibility(int32_t displayId, bool visible) {
+    std::scoped_lock lock(mLock);
+    if (visible) {
+        mDisplaysWithPointersHidden.erase(displayId);
+        // We do not unfade the icons here, because we don't know when the last event happened.
+        return;
+    }
+
+    mDisplaysWithPointersHidden.emplace(displayId);
+
+    // Hide any icons that are currently visible on the display.
+    if (auto it = mMousePointersByDisplay.find(displayId); it != mMousePointersByDisplay.end()) {
+        const auto& [_, controller] = *it;
+        controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
+    }
+    for (const auto& [_, controller] : mStylusPointersByDevice) {
+        if (controller->getDisplayId() == displayId) {
+            controller->fade(PointerControllerInterface::Transition::IMMEDIATE);
+        }
+    }
+}
+
 PointerChoreographer::ControllerConstructor PointerChoreographer::getMouseControllerConstructor(
         int32_t displayId) {
     std::function<std::shared_ptr<PointerControllerInterface>()> ctor =
diff --git a/services/inputflinger/PointerChoreographer.h b/services/inputflinger/PointerChoreographer.h
index f46419e..6aab3aa 100644
--- a/services/inputflinger/PointerChoreographer.h
+++ b/services/inputflinger/PointerChoreographer.h
@@ -67,6 +67,11 @@
      */
     virtual bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
                                 int32_t displayId, DeviceId deviceId) = 0;
+    /**
+     * Set whether pointer icons for mice, touchpads, and styluses should be visible on the
+     * given display.
+     */
+    virtual void setPointerIconVisibility(int32_t displayId, bool visible) = 0;
 
     /**
      * This method may be called on any thread (usually by the input manager on a binder thread).
@@ -89,6 +94,7 @@
     void setStylusPointerIconEnabled(bool enabled) override;
     bool setPointerIcon(std::variant<std::unique_ptr<SpriteIcon>, PointerIconStyle> icon,
                         int32_t displayId, DeviceId deviceId) override;
+    void setPointerIconVisibility(int32_t displayId, bool visible) override;
 
     void notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& args) override;
     void notifyConfigurationChanged(const NotifyConfigurationChangedArgs& args) override;
@@ -110,6 +116,7 @@
     std::pair<int32_t, PointerControllerInterface&> getDisplayIdAndMouseControllerLocked(
             int32_t associatedDisplayId) REQUIRES(mLock);
     InputDeviceInfo* findInputDeviceLocked(DeviceId deviceId) REQUIRES(mLock);
+    bool canUnfadeOnDisplay(int32_t displayId) REQUIRES(mLock);
 
     NotifyMotionArgs processMotion(const NotifyMotionArgs& args);
     NotifyMotionArgs processMouseEventLocked(const NotifyMotionArgs& args) REQUIRES(mLock);
@@ -143,6 +150,7 @@
     std::vector<DisplayViewport> mViewports GUARDED_BY(mLock);
     bool mShowTouchesEnabled GUARDED_BY(mLock);
     bool mStylusPointerIconEnabled GUARDED_BY(mLock);
+    std::set<int32_t /*displayId*/> mDisplaysWithPointersHidden;
 };
 
 } // namespace android
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 40359a4..9abfef1 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -131,10 +131,10 @@
     // Currently only used when the enable_new_mouse_pointer_ballistics flag is enabled.
     int32_t mousePointerSpeed;
 
-    // Whether to apply an acceleration curve to pointer movements from mice.
+    // Displays on which an acceleration curve shouldn't be applied for pointer movements from mice.
     //
     // Currently only used when the enable_new_mouse_pointer_ballistics flag is enabled.
-    bool mousePointerAccelerationEnabled;
+    std::set<int32_t> displaysWithMousePointerAccelerationDisabled;
 
     // Velocity control parameters for mouse pointer movements.
     //
@@ -243,7 +243,7 @@
     InputReaderConfiguration()
           : virtualKeyQuietTime(0),
             mousePointerSpeed(0),
-            mousePointerAccelerationEnabled(true),
+            displaysWithMousePointerAccelerationDisabled(),
             pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f,
                                              static_cast<float>(
                                                      android::os::IInputConstants::
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index 4cebd64..d207ed1 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -159,15 +159,15 @@
         out.push_back(NotifyDeviceResetArgs(getContext()->getNextId(), when, getDeviceId()));
     }
 
-    if (!changes.any() || changes.test(InputReaderConfiguration::Change::POINTER_SPEED) ||
-        configurePointerCapture) {
-        configureOnChangePointerSpeed(readerConfig);
-    }
-
     if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO) ||
         configurePointerCapture) {
         configureOnChangeDisplayInfo(readerConfig);
     }
+
+    if (!changes.any() || changes.test(InputReaderConfiguration::Change::POINTER_SPEED) ||
+        configurePointerCapture) {
+        configureOnChangePointerSpeed(readerConfig);
+    }
     return out;
 }
 
@@ -510,7 +510,8 @@
     } else {
         if (mEnableNewMousePointerBallistics) {
             mNewPointerVelocityControl.setAccelerationEnabled(
-                    config.mousePointerAccelerationEnabled);
+                    config.displaysWithMousePointerAccelerationDisabled.count(
+                            mDisplayId.value_or(ADISPLAY_ID_NONE)) == 0);
             mNewPointerVelocityControl.setCurve(
                     createAccelerationCurveForPointerSensitivity(config.mousePointerSpeed));
         } else {
diff --git a/services/inputflinger/reader/mapper/SlopController.cpp b/services/inputflinger/reader/mapper/SlopController.cpp
index f79219f..9ec02a6 100644
--- a/services/inputflinger/reader/mapper/SlopController.cpp
+++ b/services/inputflinger/reader/mapper/SlopController.cpp
@@ -54,11 +54,13 @@
     mCumulativeValue += value;
 
     if (abs(mCumulativeValue) >= mSlopThreshold) {
+        ALOGD("SlopController: did not drop event with value .%3f", value);
         mHasSlopBeenMet = true;
         // Return the amount of value that exceeds the slop.
         return signOf(value) * (abs(mCumulativeValue) - mSlopThreshold);
     }
 
+    ALOGD("SlopController: dropping event with value .%3f", value);
     return 0;
 }
 
diff --git a/services/inputflinger/tests/CursorInputMapper_test.cpp b/services/inputflinger/tests/CursorInputMapper_test.cpp
index e104543..7b793d8 100644
--- a/services/inputflinger/tests/CursorInputMapper_test.cpp
+++ b/services/inputflinger/tests/CursorInputMapper_test.cpp
@@ -1324,6 +1324,42 @@
     ASSERT_EQ(20, relY2);
 }
 
+TEST_F(CursorInputMapperUnitTestWithNewBallistics, ConfigureAccelerationWithAssociatedViewport) {
+    mPropertyMap.addProperty("cursor.mode", "pointer");
+    DisplayViewport primaryViewport = createPrimaryViewport(ui::Rotation::Rotation0);
+    mReaderConfiguration.setDisplayViewports({primaryViewport});
+    createDevice();
+    ViewportFakingInputDeviceContext deviceContext(*mDevice, EVENTHUB_ID, primaryViewport);
+    mMapper = createInputMapper<CursorInputMapper>(deviceContext, mReaderConfiguration);
+
+    std::list<NotifyArgs> args;
+
+    // Verify that acceleration is being applied by default by checking that the movement is scaled.
+    args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
+    args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
+    args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+    ASSERT_THAT(args,
+                ElementsAre(VariantWith<NotifyMotionArgs>(
+                        AllOf(WithMotionAction(HOVER_MOVE), WithDisplayId(DISPLAY_ID)))));
+    const auto& coords = get<NotifyMotionArgs>(args.back()).pointerCoords[0];
+    ASSERT_GT(coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X), 10.f);
+    ASSERT_GT(coords.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y), 20.f);
+
+    // Disable acceleration for the display, and verify that acceleration is no longer applied.
+    mReaderConfiguration.displaysWithMousePointerAccelerationDisabled.emplace(DISPLAY_ID);
+    args += mMapper->reconfigure(ARBITRARY_TIME, mReaderConfiguration,
+                                 InputReaderConfiguration::Change::POINTER_SPEED);
+    args.clear();
+
+    args += process(ARBITRARY_TIME, EV_REL, REL_X, 10);
+    args += process(ARBITRARY_TIME, EV_REL, REL_Y, 20);
+    args += process(ARBITRARY_TIME, EV_SYN, SYN_REPORT, 0);
+    ASSERT_THAT(args,
+                ElementsAre(VariantWith<NotifyMotionArgs>(
+                        AllOf(WithMotionAction(HOVER_MOVE), WithDisplayId(DISPLAY_ID),
+                              WithRelativeMotion(10, 20)))));
+}
+
 namespace {
 
 // Minimum timestamp separation between subsequent input events from a Bluetooth device.
diff --git a/services/inputflinger/tests/PointerChoreographer_test.cpp b/services/inputflinger/tests/PointerChoreographer_test.cpp
index 1ac043c..e9e5061 100644
--- a/services/inputflinger/tests/PointerChoreographer_test.cpp
+++ b/services/inputflinger/tests/PointerChoreographer_test.cpp
@@ -1557,4 +1557,122 @@
     mousePc->assertPointerIconNotSet();
 }
 
+TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerOnDisplay) {
+    // Make sure there are two PointerControllers on different displays.
+    mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID, ANOTHER_DISPLAY_ID}));
+    mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+    mChoreographer.notifyInputDevicesChanged(
+            {/*id=*/0,
+             {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE),
+              generateTestDeviceInfo(SECOND_DEVICE_ID, AINPUT_SOURCE_MOUSE, ANOTHER_DISPLAY_ID)}});
+    auto firstMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
+    ASSERT_EQ(DISPLAY_ID, firstMousePc->getDisplayId());
+    auto secondMousePc = assertPointerControllerCreated(ControllerType::MOUSE);
+    ASSERT_EQ(ANOTHER_DISPLAY_ID, secondMousePc->getDisplayId());
+
+    // Both pointers should be visible.
+    ASSERT_TRUE(firstMousePc->isPointerShown());
+    ASSERT_TRUE(secondMousePc->isPointerShown());
+
+    // Hide the icon on the second display.
+    mChoreographer.setPointerIconVisibility(ANOTHER_DISPLAY_ID, false);
+    ASSERT_TRUE(firstMousePc->isPointerShown());
+    ASSERT_FALSE(secondMousePc->isPointerShown());
+
+    // Move and set pointer icons for both mice. The second pointer should still be hidden.
+    mChoreographer.notifyMotion(
+            MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
+                    .pointer(MOUSE_POINTER)
+                    .deviceId(DEVICE_ID)
+                    .displayId(DISPLAY_ID)
+                    .build());
+    mChoreographer.notifyMotion(
+            MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
+                    .pointer(MOUSE_POINTER)
+                    .deviceId(SECOND_DEVICE_ID)
+                    .displayId(ANOTHER_DISPLAY_ID)
+                    .build());
+    ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
+    ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, ANOTHER_DISPLAY_ID,
+                                              SECOND_DEVICE_ID));
+    firstMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+    secondMousePc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+    ASSERT_TRUE(firstMousePc->isPointerShown());
+    ASSERT_FALSE(secondMousePc->isPointerShown());
+
+    // Allow the icon to be visible on the second display, and move the mouse.
+    mChoreographer.setPointerIconVisibility(ANOTHER_DISPLAY_ID, true);
+    mChoreographer.notifyMotion(
+            MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_MOUSE)
+                    .pointer(MOUSE_POINTER)
+                    .deviceId(SECOND_DEVICE_ID)
+                    .displayId(ANOTHER_DISPLAY_ID)
+                    .build());
+    ASSERT_TRUE(firstMousePc->isPointerShown());
+    ASSERT_TRUE(secondMousePc->isPointerShown());
+}
+
+TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerWhenDeviceConnected) {
+    mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+    mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+
+    // Hide the pointer on the display, and then connect the mouse.
+    mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);
+    mChoreographer.notifyInputDevicesChanged(
+            {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_NONE)}});
+    auto mousePc = assertPointerControllerCreated(ControllerType::MOUSE);
+    ASSERT_EQ(DISPLAY_ID, mousePc->getDisplayId());
+
+    // The pointer should not be visible.
+    ASSERT_FALSE(mousePc->isPointerShown());
+}
+
+TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForTouchpad) {
+    mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+    mChoreographer.setDefaultMouseDisplayId(DISPLAY_ID);
+
+    // Hide the pointer on the display.
+    mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);
+
+    mChoreographer.notifyInputDevicesChanged(
+            {/*id=*/0,
+             {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD,
+                                     ADISPLAY_ID_NONE)}});
+    auto touchpadPc = assertPointerControllerCreated(ControllerType::MOUSE);
+    ASSERT_EQ(DISPLAY_ID, touchpadPc->getDisplayId());
+
+    mChoreographer.notifyMotion(MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER,
+                                                  AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_TOUCHPAD)
+                                        .pointer(TOUCHPAD_POINTER)
+                                        .deviceId(DEVICE_ID)
+                                        .displayId(DISPLAY_ID)
+                                        .build());
+
+    // The pointer should not be visible.
+    ASSERT_FALSE(touchpadPc->isPointerShown());
+}
+
+TEST_F(PointerChoreographerTest, SetPointerIconVisibilityHidesPointerForStylus) {
+    mChoreographer.setDisplayViewports(createViewports({DISPLAY_ID}));
+    mChoreographer.setStylusPointerIconEnabled(true);
+
+    // Hide the pointer on the display.
+    mChoreographer.setPointerIconVisibility(DISPLAY_ID, false);
+
+    mChoreographer.notifyInputDevicesChanged(
+            {/*id=*/0, {generateTestDeviceInfo(DEVICE_ID, AINPUT_SOURCE_STYLUS, DISPLAY_ID)}});
+    mChoreographer.notifyMotion(
+            MotionArgsBuilder(AMOTION_EVENT_ACTION_HOVER_ENTER, AINPUT_SOURCE_STYLUS)
+                    .pointer(STYLUS_POINTER)
+                    .deviceId(DEVICE_ID)
+                    .displayId(DISPLAY_ID)
+                    .build());
+    ASSERT_TRUE(mChoreographer.setPointerIcon(PointerIconStyle::TYPE_TEXT, DISPLAY_ID, DEVICE_ID));
+    auto pc = assertPointerControllerCreated(ControllerType::STYLUS);
+    pc->assertPointerIconSet(PointerIconStyle::TYPE_TEXT);
+
+    // The pointer should not be visible.
+    ASSERT_FALSE(pc->isPointerShown());
+}
+
 } // namespace android
diff --git a/services/powermanager/PowerHalController.cpp b/services/powermanager/PowerHalController.cpp
index 9a23c84..c049d7d 100644
--- a/services/powermanager/PowerHalController.cpp
+++ b/services/powermanager/PowerHalController.cpp
@@ -80,7 +80,7 @@
 // Check if a call to Power HAL function failed; if so, log the failure and
 // invalidate the current Power HAL handle.
 template <typename T>
-HalResult<T> PowerHalController::processHalResult(HalResult<T> result, const char* fnName) {
+HalResult<T> PowerHalController::processHalResult(HalResult<T>&& result, const char* fnName) {
     if (result.isFailed()) {
         ALOGE("%s failed: %s", fnName, result.errorMessage());
         std::lock_guard<std::mutex> lock(mConnectedHalMutex);
@@ -94,15 +94,13 @@
 HalResult<void> PowerHalController::setBoost(aidl::android::hardware::power::Boost boost,
                                              int32_t durationMs) {
     std::shared_ptr<HalWrapper> handle = initHal();
-    auto result = handle->setBoost(boost, durationMs);
-    return processHalResult(result, "setBoost");
+    return processHalResult(handle->setBoost(boost, durationMs), "setBoost");
 }
 
 HalResult<void> PowerHalController::setMode(aidl::android::hardware::power::Mode mode,
                                             bool enabled) {
     std::shared_ptr<HalWrapper> handle = initHal();
-    auto result = handle->setMode(mode, enabled);
-    return processHalResult(result, "setMode");
+    return processHalResult(handle->setMode(mode, enabled), "setMode");
 }
 
 HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>>
@@ -110,14 +108,35 @@
                                       const std::vector<int32_t>& threadIds,
                                       int64_t durationNanos) {
     std::shared_ptr<HalWrapper> handle = initHal();
-    auto result = handle->createHintSession(tgid, uid, threadIds, durationNanos);
-    return processHalResult(result, "createHintSession");
+    return processHalResult(handle->createHintSession(tgid, uid, threadIds, durationNanos),
+                            "createHintSession");
+}
+
+HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>>
+PowerHalController::createHintSessionWithConfig(
+        int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos,
+        aidl::android::hardware::power::SessionTag tag,
+        aidl::android::hardware::power::SessionConfig* config) {
+    std::shared_ptr<HalWrapper> handle = initHal();
+    return processHalResult(handle->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos,
+                                                                tag, config),
+                            "createHintSessionWithConfig");
 }
 
 HalResult<int64_t> PowerHalController::getHintSessionPreferredRate() {
     std::shared_ptr<HalWrapper> handle = initHal();
-    auto result = handle->getHintSessionPreferredRate();
-    return processHalResult(result, "getHintSessionPreferredRate");
+    return processHalResult(handle->getHintSessionPreferredRate(), "getHintSessionPreferredRate");
+}
+
+HalResult<aidl::android::hardware::power::ChannelConfig> PowerHalController::getSessionChannel(
+        int tgid, int uid) {
+    std::shared_ptr<HalWrapper> handle = initHal();
+    return processHalResult(handle->getSessionChannel(tgid, uid), "getSessionChannel");
+}
+
+HalResult<void> PowerHalController::closeSessionChannel(int tgid, int uid) {
+    std::shared_ptr<HalWrapper> handle = initHal();
+    return processHalResult(handle->closeSessionChannel(tgid, uid), "closeSessionChannel");
 }
 
 } // namespace power
diff --git a/services/powermanager/PowerHalWrapper.cpp b/services/powermanager/PowerHalWrapper.cpp
index 76afbfc..1009100 100644
--- a/services/powermanager/PowerHalWrapper.cpp
+++ b/services/powermanager/PowerHalWrapper.cpp
@@ -42,37 +42,58 @@
 // -------------------------------------------------------------------------------------------------
 
 HalResult<void> EmptyHalWrapper::setBoost(Aidl::Boost boost, int32_t durationMs) {
-    ALOGV("Skipped setBoost %s with duration %dms because Power HAL not available",
-          toString(boost).c_str(), durationMs);
+    ALOGV("Skipped setBoost %s with duration %dms because %s", toString(boost).c_str(), durationMs,
+          getUnsupportedMessage());
     return HalResult<void>::unsupported();
 }
 
 HalResult<void> EmptyHalWrapper::setMode(Aidl::Mode mode, bool enabled) {
-    ALOGV("Skipped setMode %s to %s because Power HAL not available", toString(mode).c_str(),
-          enabled ? "true" : "false");
+    ALOGV("Skipped setMode %s to %s because %s", toString(mode).c_str(), enabled ? "true" : "false",
+          getUnsupportedMessage());
     return HalResult<void>::unsupported();
 }
 
 HalResult<std::shared_ptr<Aidl::IPowerHintSession>> EmptyHalWrapper::createHintSession(
         int32_t, int32_t, const std::vector<int32_t>& threadIds, int64_t) {
-    ALOGV("Skipped createHintSession(task num=%zu) because Power HAL not available",
-          threadIds.size());
+    ALOGV("Skipped createHintSession(task num=%zu) because %s", threadIds.size(),
+          getUnsupportedMessage());
+    return HalResult<std::shared_ptr<Aidl::IPowerHintSession>>::unsupported();
+}
+
+HalResult<std::shared_ptr<Aidl::IPowerHintSession>> EmptyHalWrapper::createHintSessionWithConfig(
+        int32_t, int32_t, const std::vector<int32_t>& threadIds, int64_t, Aidl::SessionTag,
+        Aidl::SessionConfig*) {
+    ALOGV("Skipped createHintSessionWithConfig(task num=%zu) because %s", threadIds.size(),
+          getUnsupportedMessage());
     return HalResult<std::shared_ptr<Aidl::IPowerHintSession>>::unsupported();
 }
 
 HalResult<int64_t> EmptyHalWrapper::getHintSessionPreferredRate() {
-    ALOGV("Skipped getHintSessionPreferredRate because Power HAL not available");
+    ALOGV("Skipped getHintSessionPreferredRate because %s", getUnsupportedMessage());
     return HalResult<int64_t>::unsupported();
 }
 
+HalResult<Aidl::ChannelConfig> EmptyHalWrapper::getSessionChannel(int, int) {
+    ALOGV("Skipped getSessionChannel because %s", getUnsupportedMessage());
+    return HalResult<Aidl::ChannelConfig>::unsupported();
+}
+
+HalResult<void> EmptyHalWrapper::closeSessionChannel(int, int) {
+    ALOGV("Skipped closeSessionChannel because %s", getUnsupportedMessage());
+    return HalResult<void>::unsupported();
+}
+
+const char* EmptyHalWrapper::getUnsupportedMessage() {
+    return "Power HAL is not supported";
+}
+
 // -------------------------------------------------------------------------------------------------
 
 HalResult<void> HidlHalWrapperV1_0::setBoost(Aidl::Boost boost, int32_t durationMs) {
     if (boost == Aidl::Boost::INTERACTION) {
         return sendPowerHint(V1_3::PowerHint::INTERACTION, durationMs);
     } else {
-        ALOGV("Skipped setBoost %s because Power HAL AIDL not available", toString(boost).c_str());
-        return HalResult<void>::unsupported();
+        return EmptyHalWrapper::setBoost(boost, durationMs);
     }
 }
 
@@ -92,9 +113,7 @@
         case Aidl::Mode::DOUBLE_TAP_TO_WAKE:
             return setFeature(V1_0::Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, enabled);
         default:
-            ALOGV("Skipped setMode %s because Power HAL AIDL not available",
-                  toString(mode).c_str());
-            return HalResult<void>::unsupported();
+            return EmptyHalWrapper::setMode(mode, enabled);
     }
 }
 
@@ -113,16 +132,8 @@
     return HalResult<void>::fromReturn(ret);
 }
 
-HalResult<std::shared_ptr<Aidl::IPowerHintSession>> HidlHalWrapperV1_0::createHintSession(
-        int32_t, int32_t, const std::vector<int32_t>& threadIds, int64_t) {
-    ALOGV("Skipped createHintSession(task num=%zu) because Power HAL not available",
-          threadIds.size());
-    return HalResult<std::shared_ptr<Aidl::IPowerHintSession>>::unsupported();
-}
-
-HalResult<int64_t> HidlHalWrapperV1_0::getHintSessionPreferredRate() {
-    ALOGV("Skipped getHintSessionPreferredRate because Power HAL not available");
-    return HalResult<int64_t>::unsupported();
+const char* HidlHalWrapperV1_0::getUnsupportedMessage() {
+    return "Power HAL AIDL is not supported";
 }
 
 // -------------------------------------------------------------------------------------------------
@@ -191,7 +202,7 @@
 
     // Quick return if boost is not supported by HAL
     if (idx >= mBoostSupportedArray.size() || mBoostSupportedArray[idx] == HalSupport::OFF) {
-        ALOGV("Skipped setBoost %s because Power HAL doesn't support it", toString(boost).c_str());
+        ALOGV("Skipped setBoost %s because %s", toString(boost).c_str(), getUnsupportedMessage());
         return HalResult<void>::unsupported();
     }
 
@@ -207,8 +218,8 @@
 
         mBoostSupportedArray[idx] = isSupported ? HalSupport::ON : HalSupport::OFF;
         if (!isSupported) {
-            ALOGV("Skipped setBoost %s because Power HAL doesn't support it",
-                  toString(boost).c_str());
+            ALOGV("Skipped setBoost %s because %s", toString(boost).c_str(),
+                  getUnsupportedMessage());
             return HalResult<void>::unsupported();
         }
     }
@@ -223,7 +234,7 @@
 
     // Quick return if mode is not supported by HAL
     if (idx >= mModeSupportedArray.size() || mModeSupportedArray[idx] == HalSupport::OFF) {
-        ALOGV("Skipped setMode %s because Power HAL doesn't support it", toString(mode).c_str());
+        ALOGV("Skipped setMode %s because %s", toString(mode).c_str(), getUnsupportedMessage());
         return HalResult<void>::unsupported();
     }
 
@@ -236,8 +247,7 @@
 
         mModeSupportedArray[idx] = isSupported ? HalSupport::ON : HalSupport::OFF;
         if (!isSupported) {
-            ALOGV("Skipped setMode %s because Power HAL doesn't support it",
-                  toString(mode).c_str());
+            ALOGV("Skipped setMode %s because %s", toString(mode).c_str(), getUnsupportedMessage());
             return HalResult<void>::unsupported();
         }
     }
@@ -251,7 +261,17 @@
     std::shared_ptr<Aidl::IPowerHintSession> appSession;
     return HalResult<std::shared_ptr<Aidl::IPowerHintSession>>::
             fromStatus(mHandle->createHintSession(tgid, uid, threadIds, durationNanos, &appSession),
-                       appSession);
+                       std::move(appSession));
+}
+
+HalResult<std::shared_ptr<Aidl::IPowerHintSession>> AidlHalWrapper::createHintSessionWithConfig(
+        int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds, int64_t durationNanos,
+        Aidl::SessionTag tag, Aidl::SessionConfig* config) {
+    std::shared_ptr<Aidl::IPowerHintSession> appSession;
+    return HalResult<std::shared_ptr<Aidl::IPowerHintSession>>::
+            fromStatus(mHandle->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos,
+                                                            tag, config, &appSession),
+                       std::move(appSession));
 }
 
 HalResult<int64_t> AidlHalWrapper::getHintSessionPreferredRate() {
@@ -260,6 +280,20 @@
     return HalResult<int64_t>::fromStatus(result, rate);
 }
 
+HalResult<Aidl::ChannelConfig> AidlHalWrapper::getSessionChannel(int tgid, int uid) {
+    Aidl::ChannelConfig config;
+    auto result = mHandle->getSessionChannel(tgid, uid, &config);
+    return HalResult<Aidl::ChannelConfig>::fromStatus(result, std::move(config));
+}
+
+HalResult<void> AidlHalWrapper::closeSessionChannel(int tgid, int uid) {
+    return toHalResult(mHandle->closeSessionChannel(tgid, uid));
+}
+
+const char* AidlHalWrapper::getUnsupportedMessage() {
+    return "Power HAL doesn't support it";
+}
+
 // -------------------------------------------------------------------------------------------------
 
 } // namespace power
diff --git a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
index 3d2cf29..a720296 100644
--- a/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
+++ b/services/powermanager/tests/PowerHalWrapperAidlTest.cpp
@@ -256,6 +256,23 @@
     ASSERT_TRUE(result.isOk());
 }
 
+TEST_F(PowerHalWrapperAidlTest, TestCreateHintSessionWithConfigSuccessful) {
+    std::vector<int> threadIds{gettid()};
+    int32_t tgid = 999;
+    int32_t uid = 1001;
+    int64_t durationNanos = 16666666L;
+    SessionTag tag = SessionTag::OTHER;
+    SessionConfig out;
+    EXPECT_CALL(*mMockHal.get(),
+                createHintSessionWithConfig(Eq(tgid), Eq(uid), Eq(threadIds), Eq(durationNanos),
+                                            Eq(tag), _, _))
+            .Times(Exactly(1))
+            .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok())));
+    auto result =
+            mWrapper->createHintSessionWithConfig(tgid, uid, threadIds, durationNanos, tag, &out);
+    ASSERT_TRUE(result.isOk());
+}
+
 TEST_F(PowerHalWrapperAidlTest, TestCreateHintSessionFailed) {
     int32_t tgid = 999;
     int32_t uid = 1001;
@@ -279,3 +296,18 @@
     int64_t rate = result.value();
     ASSERT_GE(0, rate);
 }
+
+TEST_F(PowerHalWrapperAidlTest, TestSessionChannel) {
+    int32_t tgid = 999;
+    int32_t uid = 1001;
+    EXPECT_CALL(*mMockHal.get(), getSessionChannel(Eq(tgid), Eq(uid), _))
+            .Times(Exactly(1))
+            .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok())));
+    EXPECT_CALL(*mMockHal.get(), closeSessionChannel(Eq(tgid), Eq(uid)))
+            .Times(Exactly(1))
+            .WillOnce(Return(testing::ByMove(ndk::ScopedAStatus::ok())));
+    auto createResult = mWrapper->getSessionChannel(tgid, uid);
+    ASSERT_TRUE(createResult.isOk());
+    auto closeResult = mWrapper->closeSessionChannel(tgid, uid);
+    ASSERT_TRUE(closeResult.isOk());
+}
diff --git a/services/surfaceflinger/Display/DisplayModeRequest.h b/services/surfaceflinger/Display/DisplayModeRequest.h
index c0e77bb..d07cdf5 100644
--- a/services/surfaceflinger/Display/DisplayModeRequest.h
+++ b/services/surfaceflinger/Display/DisplayModeRequest.h
@@ -27,9 +27,6 @@
 
     // Whether to emit DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE.
     bool emitEvent = false;
-
-    // Whether to force the request to be applied, even if the mode is unchanged.
-    bool force = false;
 };
 
 inline bool operator==(const DisplayModeRequest& lhs, const DisplayModeRequest& rhs) {
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b96264b..799d62c 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -24,7 +24,6 @@
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include <common/FlagManager.h>
 #include <compositionengine/CompositionEngine.h>
 #include <compositionengine/Display.h>
 #include <compositionengine/DisplayColorProfile.h>
@@ -222,17 +221,6 @@
 bool DisplayDevice::initiateModeChange(display::DisplayModeRequest&& desiredMode,
                                        const hal::VsyncPeriodChangeConstraints& constraints,
                                        hal::VsyncPeriodChangeTimeline& outTimeline) {
-    // TODO(b/255635711): Flow the DisplayModeRequest through the desired/pending/active states. For
-    // now, `desiredMode` and `mDesiredModeOpt` are one and the same, but the latter is not cleared
-    // until the next `SF::initiateDisplayModeChanges`. However, the desired mode has been consumed
-    // at this point, so clear the `force` flag to prevent an endless loop of `initiateModeChange`.
-    if (FlagManager::getInstance().connected_display()) {
-        std::scoped_lock lock(mDesiredModeLock);
-        if (mDesiredModeOpt) {
-            mDesiredModeOpt->force = false;
-        }
-    }
-
     mPendingModeOpt = std::move(desiredMode);
     mIsModeSetPending = true;
 
@@ -538,7 +526,8 @@
     }
 }
 
-auto DisplayDevice::setDesiredMode(display::DisplayModeRequest&& desiredMode) -> DesiredModeAction {
+auto DisplayDevice::setDesiredMode(display::DisplayModeRequest&& desiredMode, bool force)
+        -> DesiredModeAction {
     ATRACE_CALL();
 
     const auto& desiredModePtr = desiredMode.mode.modePtr;
@@ -546,26 +535,20 @@
     LOG_ALWAYS_FATAL_IF(getPhysicalId() != desiredModePtr->getPhysicalDisplayId(),
                         "DisplayId mismatch");
 
-    // TODO (b/318533819): Stringize DisplayModeRequest.
-    ALOGD("%s(%s, force=%s)", __func__, to_string(*desiredModePtr).c_str(),
-          desiredMode.force ? "true" : "false");
+    ALOGV("%s(%s)", __func__, to_string(*desiredModePtr).c_str());
 
     std::scoped_lock lock(mDesiredModeLock);
     if (mDesiredModeOpt) {
         // A mode transition was already scheduled, so just override the desired mode.
         const bool emitEvent = mDesiredModeOpt->emitEvent;
-        const bool force = mDesiredModeOpt->force;
         mDesiredModeOpt = std::move(desiredMode);
         mDesiredModeOpt->emitEvent |= emitEvent;
-        if (FlagManager::getInstance().connected_display()) {
-            mDesiredModeOpt->force |= force;
-        }
         return DesiredModeAction::None;
     }
 
     // If the desired mode is already active...
     const auto activeMode = refreshRateSelector().getActiveMode();
-    if (!desiredMode.force && activeMode.modePtr->getId() == desiredModePtr->getId()) {
+    if (!force && activeMode.modePtr->getId() == desiredModePtr->getId()) {
         if (activeMode == desiredMode.mode) {
             return DesiredModeAction::None;
         }
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 46534de..97b56a2 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -189,7 +189,8 @@
 
     enum class DesiredModeAction { None, InitiateDisplayModeSwitch, InitiateRenderRateSwitch };
 
-    DesiredModeAction setDesiredMode(display::DisplayModeRequest&&) EXCLUDES(mDesiredModeLock);
+    DesiredModeAction setDesiredMode(display::DisplayModeRequest&&, bool force = false)
+            EXCLUDES(mDesiredModeLock);
 
     using DisplayModeRequestOpt = ftl::Optional<display::DisplayModeRequest>;
 
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index db66f5b..704ece5 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -27,7 +27,6 @@
 #include "HWC2.h"
 
 #include <android/configuration.h>
-#include <common/FlagManager.h>
 #include <ui/Fence.h>
 #include <ui/FloatRect.h>
 #include <ui/GraphicBuffer.h>
@@ -417,19 +416,7 @@
                                               VsyncPeriodChangeTimeline* outTimeline) {
     ALOGV("[%" PRIu64 "] setActiveConfigWithConstraints", mId);
 
-    // FIXME (b/319505580): At least the first config set on an external display must be
-    // `setActiveConfig`, so skip over the block that calls `setActiveConfigWithConstraints`
-    // for simplicity.
-    ui::DisplayConnectionType type = ui::DisplayConnectionType::Internal;
-    const bool connected_display = FlagManager::getInstance().connected_display();
-    if (connected_display) {
-        if (auto err = getConnectionType(&type); err != Error::NONE) {
-            return err;
-        }
-    }
-
-    if (isVsyncPeriodSwitchSupported() &&
-        (!connected_display || type != ui::DisplayConnectionType::External)) {
+    if (isVsyncPeriodSwitchSupported()) {
         Hwc2::IComposerClient::VsyncPeriodChangeConstraints hwc2Constraints;
         hwc2Constraints.desiredTimeNanos = constraints.desiredTimeNanos;
         hwc2Constraints.seamlessRequired = constraints.seamlessRequired;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index bb32afa..8df5d8c 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -587,8 +587,8 @@
 bool LayerSnapshotBuilder::sortSnapshotsByZ(const Args& args) {
     if (!mResortSnapshots && args.forceUpdate == ForceUpdateFlags::NONE &&
         !args.layerLifecycleManager.getGlobalChanges().any(
-                RequestedLayerState::Changes::Hierarchy |
-                RequestedLayerState::Changes::Visibility)) {
+                RequestedLayerState::Changes::Hierarchy | RequestedLayerState::Changes::Visibility |
+                RequestedLayerState::Changes::Input)) {
         // We are not force updating and there are no hierarchy or visibility changes. Avoid sorting
         // the snapshots.
         return false;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index cf8b3bf..a145e59 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -75,9 +75,9 @@
     mHandler->dispatchFrame(vsyncId, expectedVsyncTime);
 }
 
-void MessageQueue::initVsync(std::shared_ptr<scheduler::VSyncDispatch> dispatch,
-                             frametimeline::TokenManager& tokenManager,
-                             std::chrono::nanoseconds workDuration) {
+void MessageQueue::initVsyncInternal(std::shared_ptr<scheduler::VSyncDispatch> dispatch,
+                                     frametimeline::TokenManager& tokenManager,
+                                     std::chrono::nanoseconds workDuration) {
     std::unique_ptr<scheduler::VSyncCallbackRegistration> oldRegistration;
     {
         std::lock_guard lock(mVsync.mutex);
@@ -87,7 +87,7 @@
     }
 
     // See comments in onNewVsyncSchedule. Today, oldRegistration should be
-    // empty, but nothing prevents us from calling initVsync multiple times, so
+    // empty, but nothing prevents us from calling initVsyncInternal multiple times, so
     // go ahead and destruct it outside the lock for safety.
     oldRegistration.reset();
 }
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index a523147..edb424b 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -65,8 +65,9 @@
 public:
     virtual ~MessageQueue() = default;
 
-    virtual void initVsync(std::shared_ptr<scheduler::VSyncDispatch>, frametimeline::TokenManager&,
-                           std::chrono::nanoseconds workDuration) = 0;
+    virtual void initVsyncInternal(std::shared_ptr<scheduler::VSyncDispatch>,
+                                   frametimeline::TokenManager&,
+                                   std::chrono::nanoseconds workDuration) = 0;
     virtual void destroyVsync() = 0;
     virtual void setDuration(std::chrono::nanoseconds workDuration) = 0;
     virtual void waitMessage() = 0;
@@ -137,8 +138,8 @@
 public:
     explicit MessageQueue(ICompositor&);
 
-    void initVsync(std::shared_ptr<scheduler::VSyncDispatch>, frametimeline::TokenManager&,
-                   std::chrono::nanoseconds workDuration) override;
+    void initVsyncInternal(std::shared_ptr<scheduler::VSyncDispatch>, frametimeline::TokenManager&,
+                           std::chrono::nanoseconds workDuration) override;
     void destroyVsync() override;
     void setDuration(std::chrono::nanoseconds workDuration) override;
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index 67e1b9c..d51af9a 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -49,10 +49,10 @@
 
 public:
     // TODO(b/185535769): Inject clock to avoid sleeping in tests.
-    RefreshRateStats(TimeStats& timeStats, Fps currentRefreshRate, PowerMode currentPowerMode)
+    RefreshRateStats(TimeStats& timeStats, Fps currentRefreshRate)
           : mTimeStats(timeStats),
             mCurrentRefreshRate(currentRefreshRate),
-            mCurrentPowerMode(currentPowerMode) {}
+            mCurrentPowerMode(PowerMode::OFF) {}
 
     void setPowerMode(PowerMode mode) {
         if (mCurrentPowerMode == mode) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 27ca17f..fff97f7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -77,8 +77,7 @@
         mFeatures(features),
         mVsyncConfiguration(factory.createVsyncConfiguration(activeRefreshRate)),
         mVsyncModulator(sp<VsyncModulator>::make(mVsyncConfiguration->getCurrentConfigs())),
-        mRefreshRateStats(std::make_unique<RefreshRateStats>(timeStats, activeRefreshRate,
-                                                             hal::PowerMode::OFF)),
+        mRefreshRateStats(std::make_unique<RefreshRateStats>(timeStats, activeRefreshRate)),
         mSchedulerCallback(callback),
         mVsyncTrackerCallback(vsyncTrackerCallback) {}
 
@@ -96,6 +95,11 @@
     demotePacesetterDisplay();
 }
 
+void Scheduler::initVsync(frametimeline::TokenManager& tokenManager,
+                          std::chrono::nanoseconds workDuration) {
+    Impl::initVsyncInternal(getVsyncSchedule()->getDispatch(), tokenManager, workDuration);
+}
+
 void Scheduler::startTimers() {
     using namespace sysprop;
     using namespace std::string_literals;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index f62f1ba..9912622 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -131,7 +131,7 @@
 
     void run();
 
-    using Impl::initVsync;
+    void initVsync(frametimeline::TokenManager&, std::chrono::nanoseconds workDuration);
 
     using Impl::getScheduledFrameTime;
     using Impl::setDuration;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index fe5b159..0c640aa 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1227,10 +1227,8 @@
     return NO_ERROR;
 }
 
-void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) {
-    const auto mode = desiredMode.mode;
-    const auto displayId = mode.modePtr->getPhysicalDisplayId();
-
+void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& request, bool force) {
+    const auto displayId = request.mode.modePtr->getPhysicalDisplayId();
     ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str());
 
     const auto display = getDisplayDeviceLocked(displayId);
@@ -1239,9 +1237,10 @@
         return;
     }
 
-    const bool emitEvent = desiredMode.emitEvent;
+    const auto mode = request.mode;
+    const bool emitEvent = request.emitEvent;
 
-    switch (display->setDesiredMode(std::move(desiredMode))) {
+    switch (display->setDesiredMode(std::move(request), force)) {
         case DisplayDevice::DesiredModeAction::InitiateDisplayModeSwitch:
             // DisplayDevice::setDesiredMode updated the render rate, so inform Scheduler.
             mScheduler->setRenderRate(displayId,
@@ -1427,8 +1426,7 @@
               to_string(displayModePtrOpt->get()->getVsyncRate()).c_str(),
               to_string(display->getId()).c_str());
 
-        if ((!FlagManager::getInstance().connected_display() || !desiredModeOpt->force) &&
-            display->getActiveMode() == desiredModeOpt->mode) {
+        if (display->getActiveMode() == desiredModeOpt->mode) {
             applyActiveMode(display);
             continue;
         }
@@ -3294,88 +3292,14 @@
     std::vector<HWComposer::HWCDisplayMode> hwcModes;
     std::optional<hal::HWDisplayId> activeModeHwcId;
 
-    const bool isExternalDisplay = FlagManager::getInstance().connected_display() &&
-            getHwComposer().getDisplayConnectionType(displayId) ==
-                    ui::DisplayConnectionType::External;
-
     int attempt = 0;
     constexpr int kMaxAttempts = 3;
     do {
         hwcModes = getHwComposer().getModes(displayId,
                                             scheduler::RefreshRateSelector::kMinSupportedFrameRate
                                                     .getPeriodNsecs());
-
         activeModeHwcId = getHwComposer().getActiveMode(displayId);
 
-        if (isExternalDisplay) {
-            constexpr nsecs_t k59HzVsyncPeriod = 16949153;
-            constexpr nsecs_t k60HzVsyncPeriod = 16666667;
-
-            // DM sets the initial mode for an external display to 1080p@60, but
-            // this comes after SF creates its own state (including the
-            // DisplayDevice). For now, pick the same mode in order to avoid
-            // inconsistent state and unnecessary mode switching.
-            // TODO (b/318534874): Let DM decide the initial mode.
-            //
-            // Try to find 1920x1080 @ 60 Hz
-            if (const auto iter = std::find_if(hwcModes.begin(), hwcModes.end(),
-                                               [](const auto& mode) {
-                                                   return mode.width == 1920 &&
-                                                           mode.height == 1080 &&
-                                                           mode.vsyncPeriod == k60HzVsyncPeriod;
-                                               });
-                iter != hwcModes.end()) {
-                activeModeHwcId = iter->hwcId;
-                break;
-            }
-
-            // Try to find 1920x1080 @ 59-60 Hz
-            if (const auto iter = std::find_if(hwcModes.begin(), hwcModes.end(),
-                                               [](const auto& mode) {
-                                                   return mode.width == 1920 &&
-                                                           mode.height == 1080 &&
-                                                           mode.vsyncPeriod >= k60HzVsyncPeriod &&
-                                                           mode.vsyncPeriod <= k59HzVsyncPeriod;
-                                               });
-                iter != hwcModes.end()) {
-                activeModeHwcId = iter->hwcId;
-                break;
-            }
-
-            // The display does not support 1080p@60, and this is the last attempt to pick a display
-            // mode. Prefer 60 Hz if available, with the closest resolution to 1080p.
-            if (attempt + 1 == kMaxAttempts) {
-                std::vector<HWComposer::HWCDisplayMode> hwcModeOpts;
-
-                for (const auto& mode : hwcModes) {
-                    if (mode.width <= 1920 && mode.height <= 1080 &&
-                        mode.vsyncPeriod >= k60HzVsyncPeriod &&
-                        mode.vsyncPeriod <= k59HzVsyncPeriod) {
-                        hwcModeOpts.push_back(mode);
-                    }
-                }
-
-                if (const auto iter = std::max_element(hwcModeOpts.begin(), hwcModeOpts.end(),
-                                                       [](const auto& a, const auto& b) {
-                                                           const auto aSize = a.width * a.height;
-                                                           const auto bSize = b.width * b.height;
-                                                           if (aSize < bSize)
-                                                               return true;
-                                                           else if (aSize == bSize)
-                                                               return a.vsyncPeriod > b.vsyncPeriod;
-                                                           else
-                                                               return false;
-                                                       });
-                    iter != hwcModeOpts.end()) {
-                    activeModeHwcId = iter->hwcId;
-                    break;
-                }
-
-                // hwcModeOpts was empty, use hwcModes[0] as the last resort
-                activeModeHwcId = hwcModes[0].hwcId;
-            }
-        }
-
         const auto isActiveMode = [activeModeHwcId](const HWComposer::HWCDisplayMode& mode) {
             return mode.hwcId == activeModeHwcId;
         };
@@ -3435,10 +3359,6 @@
                 return pair.second->getHwcId() == activeModeHwcId;
             })->second;
 
-    if (isExternalDisplay) {
-        ALOGI("External display %s initial mode: {%s}", to_string(displayId).c_str(),
-              to_string(*activeMode).c_str());
-    }
     return {modes, activeMode};
 }
 
@@ -3745,27 +3665,6 @@
     }
 
     mDisplays.try_emplace(displayToken, std::move(display));
-
-    // For an external display, loadDisplayModes already selected the same mode
-    // as DM, but SF still needs to be updated to match.
-    // TODO (b/318534874): Let DM decide the initial mode.
-    if (const auto& physical = state.physical;
-        mScheduler && physical && FlagManager::getInstance().connected_display()) {
-        const bool isInternalDisplay = mPhysicalDisplays.get(physical->id)
-                                               .transform(&PhysicalDisplay::isInternal)
-                                               .value_or(false);
-
-        if (!isInternalDisplay) {
-            auto activeModePtr = physical->activeMode;
-            const auto fps = activeModePtr->getPeakFps();
-
-            setDesiredMode(
-                    {.mode = scheduler::FrameRateMode{fps,
-                                                      ftl::as_non_null(std::move(activeModePtr))},
-                     .emitEvent = false,
-                     .force = true});
-        }
-    }
 }
 
 void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) {
@@ -4334,8 +4233,7 @@
                                           /* workDuration */ activeRefreshRate.getPeriod(),
                                           /* readyDuration */ configs.late.sfWorkDuration);
 
-    mScheduler->initVsync(mScheduler->getVsyncSchedule()->getDispatch(),
-                          *mFrameTimeline->getTokenManager(), configs.late.sfWorkDuration);
+    mScheduler->initVsync(*mFrameTimeline->getTokenManager(), configs.late.sfWorkDuration);
 
     mRegionSamplingThread =
             sp<RegionSamplingThread>::make(*this,
@@ -8434,7 +8332,7 @@
         return INVALID_OPERATION;
     }
 
-    setDesiredMode({std::move(preferredMode), .emitEvent = true, .force = force});
+    setDesiredMode({std::move(preferredMode), .emitEvent = true}, force);
 
     // Update the frameRateOverride list as the display render rate might have changed
     if (mScheduler->updateFrameRateOverrides(scheduler::GlobalSignals{}, preferredFps)) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6ae05d6..6e12172 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -718,7 +718,7 @@
     // Show hdr sdr ratio overlay
     bool mHdrSdrRatioOverlay = false;
 
-    void setDesiredMode(display::DisplayModeRequest&&) REQUIRES(mStateLock);
+    void setDesiredMode(display::DisplayModeRequest&&, bool force = false) REQUIRES(mStateLock);
 
     status_t setActiveModeFromBackdoor(const sp<display::DisplayToken>&, DisplayModeId, Fps minFps,
                                        Fps maxFps);
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 8a5500f..c098dda 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -405,8 +405,8 @@
                                              Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()));
 
     android::mock::TimeStats timeStats;
-    RefreshRateStats refreshRateStats(timeStats, Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
-                                      PowerMode::OFF);
+    RefreshRateStats refreshRateStats(timeStats,
+                                      Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()));
 
     const auto fpsOpt = displayModes.get(modeId).transform(
             [](const DisplayModePtr& mode) { return mode->getVsyncRate(); });
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 99fef7e..6671414 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -447,11 +447,9 @@
                     ? IComposerClient::DisplayConnectionType::INTERNAL
                     : IComposerClient::DisplayConnectionType::EXTERNAL;
 
-            using ::testing::AtLeast;
             EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _))
-                    .Times(AtLeast(1))
-                    .WillRepeatedly(DoAll(SetArgPointee<1>(CONNECTION_TYPE),
-                                          Return(hal::V2_4::Error::NONE)));
+                    .WillOnce(DoAll(SetArgPointee<1>(CONNECTION_TYPE),
+                                    Return(hal::V2_4::Error::NONE)));
         }
 
         EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_))
diff --git a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
index 6394d63..13b47ff 100644
--- a/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerSnapshotTest.cpp
@@ -64,6 +64,18 @@
         actualBuilder.update(args);
     }
 
+    void update(LayerSnapshotBuilder& actualBuilder) {
+        LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(),
+                                        .layerLifecycleManager = mLifecycleManager,
+                                        .includeMetadata = false,
+                                        .displays = mFrontEndDisplayInfos,
+                                        .globalShadowSettings = globalShadowSettings,
+                                        .supportsBlur = true,
+                                        .supportedLayerGenericMetadata = {},
+                                        .genericLayerMetadataKeyMap = {}};
+        update(actualBuilder, args);
+    }
+
     void updateAndVerify(LayerSnapshotBuilder& actualBuilder, bool hasDisplayChanges,
                          const std::vector<uint32_t> expectedVisibleLayerIdsInZOrder) {
         LayerSnapshotBuilder::Args args{.root = mHierarchyBuilder.getHierarchy(),
@@ -1199,4 +1211,30 @@
     EXPECT_EQ(getSnapshot(11)->dropInputMode, gui::DropInputMode::ALL);
 }
 
+TEST_F(LayerSnapshotTest, NonVisibleLayerWithInput) {
+    LayerHierarchyTestBase::createRootLayer(3);
+    setColor(3, {-1._hf, -1._hf, -1._hf});
+    UPDATE_AND_VERIFY(mSnapshotBuilder, STARTING_ZORDER);
+
+    std::vector<TransactionState> transactions;
+    transactions.emplace_back();
+    transactions.back().states.push_back({});
+    transactions.back().states.front().state.what = layer_state_t::eInputInfoChanged;
+    transactions.back().states.front().layerId = 3;
+    transactions.back().states.front().state.windowInfoHandle = sp<gui::WindowInfoHandle>::make();
+    auto inputInfo = transactions.back().states.front().state.windowInfoHandle->editInfo();
+    inputInfo->token = sp<BBinder>::make();
+    mLifecycleManager.applyTransactions(transactions);
+
+    update(mSnapshotBuilder);
+
+    bool foundInputLayer = false;
+    mSnapshotBuilder.forEachInputSnapshot([&](const frontend::LayerSnapshot& snapshot) {
+        if (snapshot.uniqueSequence == 3) {
+            foundInputLayer = true;
+        }
+    });
+    EXPECT_TRUE(foundInputLayer);
+}
+
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
index e9c4d80..249ed40 100644
--- a/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/MessageQueueTest.cpp
@@ -72,7 +72,8 @@
 struct MessageQueueTest : testing::Test {
     void SetUp() override {
         EXPECT_CALL(*mVSyncDispatch, registerCallback(_, "sf")).WillOnce(Return(mCallbackToken));
-        EXPECT_NO_FATAL_FAILURE(mEventQueue.initVsync(mVSyncDispatch, mTokenManager, kDuration));
+        EXPECT_NO_FATAL_FAILURE(
+                mEventQueue.initVsyncInternal(mVSyncDispatch, mTokenManager, kDuration));
         EXPECT_CALL(*mVSyncDispatch, unregisterCallback(mCallbackToken)).Times(1);
     }
 
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index e2e3d7b..fba77e9 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -37,7 +37,7 @@
     ~RefreshRateStatsTest();
 
     void resetStats(Fps fps) {
-        mRefreshRateStats = std::make_unique<RefreshRateStats>(mTimeStats, fps, PowerMode::OFF);
+        mRefreshRateStats = std::make_unique<RefreshRateStats>(mTimeStats, fps);
     }
 
     mock::TimeStats mTimeStats;
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
index 82b4ad0..8b16a8a 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DisplayModeSwitching.cpp
@@ -21,13 +21,9 @@
 #include "mock/DisplayHardware/MockDisplayMode.h"
 #include "mock/MockDisplayModeSpecs.h"
 
-#include <com_android_graphics_surfaceflinger_flags.h>
-#include <common/test/FlagUtils.h>
 #include <ftl/fake_guard.h>
 #include <scheduler/Fps.h>
 
-using namespace com::android::graphics::surfaceflinger;
-
 namespace android {
 namespace {
 
@@ -364,13 +360,6 @@
 }
 
 TEST_F(DisplayModeSwitchingTest, innerXorOuterDisplay) {
-    SET_FLAG_FOR_TEST(flags::connected_display, true);
-
-    // For the inner display, this is handled by setupHwcHotplugCallExpectations.
-    EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _))
-            .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL),
-                            Return(hal::V2_4::Error::NONE)));
-
     const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
 
     EXPECT_TRUE(innerDisplay->isPoweredOn());
@@ -440,12 +429,6 @@
 }
 
 TEST_F(DisplayModeSwitchingTest, innerAndOuterDisplay) {
-    SET_FLAG_FOR_TEST(flags::connected_display, true);
-
-    // For the inner display, this is handled by setupHwcHotplugCallExpectations.
-    EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _))
-            .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL),
-                            Return(hal::V2_4::Error::NONE)));
     const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
 
     EXPECT_TRUE(innerDisplay->isPoweredOn());
@@ -529,13 +512,6 @@
 }
 
 TEST_F(DisplayModeSwitchingTest, powerOffDuringConcurrentModeSet) {
-    SET_FLAG_FOR_TEST(flags::connected_display, true);
-
-    // For the inner display, this is handled by setupHwcHotplugCallExpectations.
-    EXPECT_CALL(*mComposer, getDisplayConnectionType(kOuterDisplayHwcId, _))
-            .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayConnectionType::INTERNAL),
-                            Return(hal::V2_4::Error::NONE)));
-
     const auto [innerDisplay, outerDisplay] = injectOuterDisplay();
 
     EXPECT_TRUE(innerDisplay->isPoweredOn());
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index f00eacc..4e0b5af 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -268,7 +268,7 @@
                                                           vsyncTrackerCallback);
         }
 
-        mScheduler->initVsync(mScheduler->getVsyncSchedule()->getDispatch(), *mTokenManager, 0ms);
+        mScheduler->initVsync(*mTokenManager, 0ms);
 
         mScheduler->mutableAppConnectionHandle() =
                 mScheduler->createConnection(std::move(appEventThread));
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h
index b17c8ad..ae41e7e 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerHalController.h
@@ -34,8 +34,6 @@
 
 namespace android::Hwc2::mock {
 
-using aidl::android::hardware::power::Boost;
-using aidl::android::hardware::power::Mode;
 using android::power::HalResult;
 
 class MockPowerHalController : public power::PowerHalController {
@@ -43,12 +41,22 @@
     MockPowerHalController();
     ~MockPowerHalController() override;
     MOCK_METHOD(void, init, (), (override));
-    MOCK_METHOD(HalResult<void>, setBoost, (Boost, int32_t), (override));
-    MOCK_METHOD(HalResult<void>, setMode, (Mode, bool), (override));
+    MOCK_METHOD(HalResult<void>, setBoost, (aidl::android::hardware::power::Boost, int32_t),
+                (override));
+    MOCK_METHOD(HalResult<void>, setMode, (aidl::android::hardware::power::Mode, bool), (override));
     MOCK_METHOD(HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>>,
                 createHintSession, (int32_t, int32_t, const std::vector<int32_t>&, int64_t),
                 (override));
+    MOCK_METHOD(HalResult<std::shared_ptr<aidl::android::hardware::power::IPowerHintSession>>,
+                createHintSessionWithConfig,
+                (int32_t tgid, int32_t uid, const std::vector<int32_t>& threadIds,
+                 int64_t durationNanos, aidl::android::hardware::power::SessionTag tag,
+                 aidl::android::hardware::power::SessionConfig* config),
+                (override));
     MOCK_METHOD(HalResult<int64_t>, getHintSessionPreferredRate, (), (override));
+    MOCK_METHOD(HalResult<aidl::android::hardware::power::ChannelConfig>, getSessionChannel,
+                (int tgid, int uid), (override));
+    MOCK_METHOD(HalResult<void>, closeSessionChannel, (int tgid, int uid), (override));
 };
 
 } // namespace android::Hwc2::mock
\ No newline at end of file