Merge "SF: Clean up ftl::SmallMap lookup fallbacks" into udc-dev
diff --git a/include/ftl/flags.h b/include/ftl/flags.h
index cdb4e84..dbe3148 100644
--- a/include/ftl/flags.h
+++ b/include/ftl/flags.h
@@ -120,7 +120,7 @@
     }
 
     /* Tests whether any of the given flags are set */
-    bool any(Flags<F> f) const { return (mFlags & f.mFlags) != 0; }
+    bool any(Flags<F> f = ~Flags<F>()) const { return (mFlags & f.mFlags) != 0; }
 
     /* Tests whether all of the given flags are set */
     bool all(Flags<F> f) const { return (mFlags & f.mFlags) == f.mFlags; }
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 97cb810..5eb3308 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -62,7 +62,10 @@
         "android.hardware.audio@7.0::IDevicesFactory",
         "android.hardware.automotive.audiocontrol@1.0::IAudioControl",
         "android.hardware.automotive.audiocontrol@2.0::IAudioControl",
+        "android.hardware.automotive.can@1.0::ICanBus",
+        "android.hardware.automotive.can@1.0::ICanController",
         "android.hardware.automotive.evs@1.0::IEvsCamera",
+        "android.hardware.automotive.sv@1.0::ISurroundViewService",
         "android.hardware.automotive.vehicle@2.0::IVehicle",
         "android.hardware.biometrics.face@1.0::IBiometricsFace",
         "android.hardware.biometrics.fingerprint@2.1::IBiometricsFingerprint",
@@ -87,7 +90,12 @@
 /* list of hal interface to dump containing process during native dumps */
 static const std::vector<std::string> aidl_interfaces_to_dump {
         "android.hardware.automotive.audiocontrol.IAudioControl",
+        "android.hardware.automotive.can.ICanController",
         "android.hardware.automotive.evs.IEvsEnumerator",
+        "android.hardware.automotive.ivn.IIvnAndroidDevice",
+        "android.hardware.automotive.occupant_awareness.IOccupantAwareness",
+        "android.hardware.automotive.remoteaccess.IRemoteAccess",
+        "android.hardware.automotive.vehicle.IVehicle",
         "android.hardware.biometrics.face.IBiometricsFace",
         "android.hardware.biometrics.fingerprint.IBiometricsFingerprint",
         "android.hardware.camera.provider.ICameraProvider",
diff --git a/libs/ftl/flags_test.cpp b/libs/ftl/flags_test.cpp
index eea052b..1279d11 100644
--- a/libs/ftl/flags_test.cpp
+++ b/libs/ftl/flags_test.cpp
@@ -35,6 +35,7 @@
 
 TEST(Flags, Any) {
     Flags<TestFlags> flags = TestFlags::ONE | TestFlags::TWO;
+    ASSERT_TRUE(flags.any());
     ASSERT_TRUE(flags.any(TestFlags::ONE));
     ASSERT_TRUE(flags.any(TestFlags::TWO));
     ASSERT_FALSE(flags.any(TestFlags::THREE));
@@ -42,6 +43,9 @@
     ASSERT_TRUE(flags.any(TestFlags::TWO | TestFlags::THREE));
     ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::THREE));
     ASSERT_TRUE(flags.any(TestFlags::ONE | TestFlags::TWO | TestFlags::THREE));
+
+    Flags<TestFlags> emptyFlags;
+    ASSERT_FALSE(emptyFlags.any());
 }
 
 TEST(Flags, All) {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 21900a0..0a63c15 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -66,6 +66,18 @@
     ],
 }
 
+filegroup {
+    name: "android_gui_aidl",
+    srcs: [
+        "android/gui/DisplayInfo.aidl",
+        "android/gui/FocusRequest.aidl",
+        "android/gui/InputApplicationInfo.aidl",
+        "android/gui/IWindowInfosListener.aidl",
+        "android/gui/IWindowInfosReportedListener.aidl",
+        "android/gui/WindowInfo.aidl",
+    ],
+}
+
 cc_library_static {
     name: "libgui_window_info_static",
     vendor_available: true,
@@ -118,6 +130,9 @@
     name: "libgui_aidl",
     srcs: ["aidl/**/*.aidl"],
     path: "aidl/",
+    aidl: {
+        deps: [":android_gui_aidl"],
+    },
 }
 
 filegroup {
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 136a560..f703901 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -1050,14 +1050,14 @@
         return finishKey(*key);
     }
 
-    Vector<Property> properties;
+    std::vector<Property> properties;
 
     // Parse all comma-delimited property names up to the first colon.
     for (;;) {
         if (token == "label") {
-            properties.add(Property(PROPERTY_LABEL));
+            properties.emplace_back(PROPERTY_LABEL);
         } else if (token == "number") {
-            properties.add(Property(PROPERTY_NUMBER));
+            properties.emplace_back(PROPERTY_NUMBER);
         } else {
             int32_t metaState;
             status_t status = parseModifier(token.string(), &metaState);
@@ -1066,7 +1066,7 @@
                         mTokenizer->getLocation().string(), token.string());
                 return status;
             }
-            properties.add(Property(PROPERTY_META, metaState));
+            properties.emplace_back(PROPERTY_META, metaState);
         }
 
         mTokenizer->skipDelimiters(WHITESPACE);
@@ -1181,8 +1181,7 @@
     } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#');
 
     // Add the behavior.
-    for (size_t i = 0; i < properties.size(); i++) {
-        const Property& property = properties.itemAt(i);
+    for (const Property& property : properties) {
         switch (property.property) {
         case PROPERTY_LABEL:
             if (key->label) {
diff --git a/services/automotive/display/Android.bp b/services/automotive/display/Android.bp
index 614a78e..72bd292 100644
--- a/services/automotive/display/Android.bp
+++ b/services/automotive/display/Android.bp
@@ -53,6 +53,4 @@
     vintf_fragments: [
         "manifest_android.frameworks.automotive.display@1.0.xml",
     ],
-
-    system_ext_specific: true,
 }
diff --git a/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
index ea1077a..5c7f344 100644
--- a/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
+++ b/services/automotive/display/android.frameworks.automotive.display@1.0-service.rc
@@ -1,4 +1,4 @@
-service automotive_display /system_ext/bin/android.frameworks.automotive.display@1.0-service
+service automotive_display /system/bin/android.frameworks.automotive.display@1.0-service
     class hal
     user graphics
     group automotive_evs
diff --git a/services/inputflinger/InputReaderBase.cpp b/services/inputflinger/InputReaderBase.cpp
index 2450235..4ec5b89 100644
--- a/services/inputflinger/InputReaderBase.cpp
+++ b/services/inputflinger/InputReaderBase.cpp
@@ -38,50 +38,6 @@
 
 // --- InputReaderConfiguration ---
 
-std::string InputReaderConfiguration::changesToString(uint32_t changes) {
-    if (changes == 0) {
-        return "<none>";
-    }
-    std::string result;
-    if (changes & CHANGE_POINTER_SPEED) {
-        result += "POINTER_SPEED | ";
-    }
-    if (changes & CHANGE_POINTER_GESTURE_ENABLEMENT) {
-        result += "POINTER_GESTURE_ENABLEMENT | ";
-    }
-    if (changes & CHANGE_DISPLAY_INFO) {
-        result += "DISPLAY_INFO | ";
-    }
-    if (changes & CHANGE_SHOW_TOUCHES) {
-        result += "SHOW_TOUCHES | ";
-    }
-    if (changes & CHANGE_KEYBOARD_LAYOUTS) {
-        result += "KEYBOARD_LAYOUTS | ";
-    }
-    if (changes & CHANGE_DEVICE_ALIAS) {
-        result += "DEVICE_ALIAS | ";
-    }
-    if (changes & CHANGE_TOUCH_AFFINE_TRANSFORMATION) {
-        result += "TOUCH_AFFINE_TRANSFORMATION | ";
-    }
-    if (changes & CHANGE_EXTERNAL_STYLUS_PRESENCE) {
-        result += "EXTERNAL_STYLUS_PRESENCE | ";
-    }
-    if (changes & CHANGE_POINTER_CAPTURE) {
-        result += "POINTER_CAPTURE | ";
-    }
-    if (changes & CHANGE_ENABLED_STATE) {
-        result += "ENABLED_STATE | ";
-    }
-    if (changes & CHANGE_TOUCHPAD_SETTINGS) {
-        result += "TOUCHPAD_SETTINGS | ";
-    }
-    if (changes & CHANGE_MUST_REOPEN) {
-        result += "MUST_REOPEN | ";
-    }
-    return result;
-}
-
 std::optional<DisplayViewport> InputReaderConfiguration::getDisplayViewportByUniqueId(
         const std::string& uniqueDisplayId) const {
     if (uniqueDisplayId.empty()) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index e8434be..a6d1810 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1297,7 +1297,7 @@
             (keyEntry.policyFlags & POLICY_FLAG_PASS_TO_USER);
 }
 
-bool InputDispatcher::isAppSwitchPendingLocked() {
+bool InputDispatcher::isAppSwitchPendingLocked() const {
     return mAppSwitchDueTime != LLONG_MAX;
 }
 
@@ -5411,7 +5411,7 @@
     mReplacedKeys.clear();
 }
 
-void InputDispatcher::logDispatchStateLocked() {
+void InputDispatcher::logDispatchStateLocked() const {
     std::string dump;
     dumpDispatchStateLocked(dump);
 
@@ -5423,7 +5423,7 @@
     }
 }
 
-std::string InputDispatcher::dumpPointerCaptureStateLocked() {
+std::string InputDispatcher::dumpPointerCaptureStateLocked() const {
     std::string dump;
 
     dump += StringPrintf(INDENT "Pointer Capture Requested: %s\n",
@@ -5441,7 +5441,7 @@
     return dump;
 }
 
-void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
+void InputDispatcher::dumpDispatchStateLocked(std::string& dump) const {
     dump += StringPrintf(INDENT "DispatchEnabled: %s\n", toString(mDispatchEnabled));
     dump += StringPrintf(INDENT "DispatchFrozen: %s\n", toString(mDispatchFrozen));
     dump += StringPrintf(INDENT "InputFilterEnabled: %s\n", toString(mInputFilterEnabled));
@@ -5544,7 +5544,7 @@
     // Dump recently dispatched or dropped events from oldest to newest.
     if (!mRecentQueue.empty()) {
         dump += StringPrintf(INDENT "RecentQueue: length=%zu\n", mRecentQueue.size());
-        for (std::shared_ptr<EventEntry>& entry : mRecentQueue) {
+        for (const std::shared_ptr<EventEntry>& entry : mRecentQueue) {
             dump += INDENT2;
             dump += entry->getDescription();
             dump += StringPrintf(", age=%" PRId64 "ms\n", ns2ms(currentTime - entry->eventTime));
@@ -5567,7 +5567,7 @@
     // Dump inbound events from oldest to newest.
     if (!mInboundQueue.empty()) {
         dump += StringPrintf(INDENT "InboundQueue: length=%zu\n", mInboundQueue.size());
-        for (std::shared_ptr<EventEntry>& entry : mInboundQueue) {
+        for (const std::shared_ptr<EventEntry>& entry : mInboundQueue) {
             dump += INDENT2;
             dump += entry->getDescription();
             dump += StringPrintf(", age=%" PRId64 "ms\n", ns2ms(currentTime - entry->eventTime));
@@ -5649,7 +5649,7 @@
     dump += mLatencyAggregator.dump(INDENT2);
 }
 
-void InputDispatcher::dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors) {
+void InputDispatcher::dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors) const {
     const size_t numMonitors = monitors.size();
     for (size_t i = 0; i < numMonitors; i++) {
         const Monitor& monitor = monitors[i];
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 4aba24c..76b15e2 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -232,7 +232,7 @@
     nsecs_t mAppSwitchDueTime GUARDED_BY(mLock);
 
     bool isAppSwitchKeyEvent(const KeyEntry& keyEntry);
-    bool isAppSwitchPendingLocked() REQUIRES(mLock);
+    bool isAppSwitchPendingLocked() const REQUIRES(mLock);
     void resetPendingAppSwitchLocked(bool handled) REQUIRES(mLock);
 
     // Blocked event latency optimization.  Drops old events when the user intends
@@ -647,10 +647,10 @@
     void resetAndDropEverythingLocked(const char* reason) REQUIRES(mLock);
 
     // Dump state.
-    void dumpDispatchStateLocked(std::string& dump) REQUIRES(mLock);
-    void dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors);
-    void logDispatchStateLocked() REQUIRES(mLock);
-    std::string dumpPointerCaptureStateLocked() REQUIRES(mLock);
+    void dumpDispatchStateLocked(std::string& dump) const REQUIRES(mLock);
+    void dumpMonitors(std::string& dump, const std::vector<Monitor>& monitors) const;
+    void logDispatchStateLocked() const REQUIRES(mLock);
+    std::string dumpPointerCaptureStateLocked() const REQUIRES(mLock);
 
     // Registration.
     void removeMonitorChannelLocked(const sp<IBinder>& connectionToken) REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/LatencyAggregator.cpp b/services/inputflinger/dispatcher/LatencyAggregator.cpp
index a5bfc25..96d78c3 100644
--- a/services/inputflinger/dispatcher/LatencyAggregator.cpp
+++ b/services/inputflinger/dispatcher/LatencyAggregator.cpp
@@ -256,7 +256,7 @@
     }
 }
 
-std::string LatencyAggregator::dump(const char* prefix) {
+std::string LatencyAggregator::dump(const char* prefix) const {
     std::string sketchDump = StringPrintf("%s  Sketches:\n", prefix);
     for (size_t i = 0; i < SketchIndex::SIZE; i++) {
         const int64_t numDown = mDownSketches[i]->num_values();
diff --git a/services/inputflinger/dispatcher/LatencyAggregator.h b/services/inputflinger/dispatcher/LatencyAggregator.h
index accfc29..60b6813 100644
--- a/services/inputflinger/dispatcher/LatencyAggregator.h
+++ b/services/inputflinger/dispatcher/LatencyAggregator.h
@@ -56,7 +56,7 @@
      */
     void processTimeline(const InputEventTimeline& timeline) override;
 
-    std::string dump(const char* prefix);
+    std::string dump(const char* prefix) const;
 
     ~LatencyAggregator();
 
diff --git a/services/inputflinger/dispatcher/LatencyTracker.cpp b/services/inputflinger/dispatcher/LatencyTracker.cpp
index 2dd7d3f..b7c36a8 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.cpp
+++ b/services/inputflinger/dispatcher/LatencyTracker.cpp
@@ -165,7 +165,7 @@
     }
 }
 
-std::string LatencyTracker::dump(const char* prefix) {
+std::string LatencyTracker::dump(const char* prefix) const {
     return StringPrintf("%sLatencyTracker:\n", prefix) +
             StringPrintf("%s  mTimelines.size() = %zu\n", prefix, mTimelines.size()) +
             StringPrintf("%s  mEventTimes.size() = %zu\n", prefix, mEventTimes.size());
diff --git a/services/inputflinger/dispatcher/LatencyTracker.h b/services/inputflinger/dispatcher/LatencyTracker.h
index 64dfeef..4212da8 100644
--- a/services/inputflinger/dispatcher/LatencyTracker.h
+++ b/services/inputflinger/dispatcher/LatencyTracker.h
@@ -55,7 +55,7 @@
     void trackGraphicsLatency(int32_t inputEventId, const sp<IBinder>& connectionToken,
                               std::array<nsecs_t, GraphicsTimeline::SIZE> timeline);
 
-    std::string dump(const char* prefix);
+    std::string dump(const char* prefix) const;
 
 private:
     /**
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 1750c64..a93a2ea 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -42,118 +42,6 @@
 
 namespace android {
 
-// --- InputReaderInterface ---
-
-/* The interface for the InputReader shared library.
- *
- * Manages one or more threads that process raw input events and sends cooked event data to an
- * input listener.
- *
- * The implementation must guarantee thread safety for this interface. However, since the input
- * listener is NOT thread safe, all calls to the listener must happen from the same thread.
- */
-class InputReaderInterface {
-public:
-    InputReaderInterface() { }
-    virtual ~InputReaderInterface() { }
-
-    /* Dumps the state of the input reader.
-     *
-     * This method may be called on any thread (usually by the input manager). */
-    virtual void dump(std::string& dump) = 0;
-
-    /* Called by the heartbeat to ensures that the reader has not deadlocked. */
-    virtual void monitor() = 0;
-
-    /* Returns true if the input device is enabled. */
-    virtual bool isInputDeviceEnabled(int32_t deviceId) = 0;
-
-    /* Makes the reader start processing events from the kernel. */
-    virtual status_t start() = 0;
-
-    /* Makes the reader stop processing any more events. */
-    virtual status_t stop() = 0;
-
-    /* Gets information about all input devices.
-     *
-     * This method may be called on any thread (usually by the input manager).
-     */
-    virtual std::vector<InputDeviceInfo> getInputDevices() const = 0;
-
-    /* Query current input state. */
-    virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,
-            int32_t scanCode) = 0;
-    virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
-            int32_t keyCode) = 0;
-    virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask,
-            int32_t sw) = 0;
-
-    virtual void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode,
-                                 int32_t toKeyCode) const = 0;
-
-    virtual int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const = 0;
-
-    /* Toggle Caps Lock */
-    virtual void toggleCapsLockState(int32_t deviceId) = 0;
-
-    /* Determine whether physical keys exist for the given framework-domain key codes. */
-    virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
-                         const std::vector<int32_t>& keyCodes, uint8_t* outFlags) = 0;
-
-    /* Requests that a reconfiguration of all input devices.
-     * The changes flag is a bitfield that indicates what has changed and whether
-     * the input devices must all be reopened. */
-    virtual void requestRefreshConfiguration(uint32_t changes) = 0;
-
-    /* Controls the vibrator of a particular input device. */
-    virtual void vibrate(int32_t deviceId, const VibrationSequence& sequence, ssize_t repeat,
-                         int32_t token) = 0;
-    virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;
-
-    virtual bool isVibrating(int32_t deviceId) = 0;
-
-    virtual std::vector<int32_t> getVibratorIds(int32_t deviceId) = 0;
-    /* Get battery level of a particular input device. */
-    virtual std::optional<int32_t> getBatteryCapacity(int32_t deviceId) = 0;
-    /* Get battery status of a particular input device. */
-    virtual std::optional<int32_t> getBatteryStatus(int32_t deviceId) = 0;
-    /* Get the device path for the battery of an input device. */
-    virtual std::optional<std::string> getBatteryDevicePath(int32_t deviceId) = 0;
-
-    virtual std::vector<InputDeviceLightInfo> getLights(int32_t deviceId) = 0;
-
-    virtual std::vector<InputDeviceSensorInfo> getSensors(int32_t deviceId) = 0;
-
-    /* Return true if the device can send input events to the specified display. */
-    virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) = 0;
-
-    /* Enable sensor in input reader mapper. */
-    virtual bool enableSensor(int32_t deviceId, InputDeviceSensorType sensorType,
-                              std::chrono::microseconds samplingPeriod,
-                              std::chrono::microseconds maxBatchReportLatency) = 0;
-
-    /* Disable sensor in input reader mapper. */
-    virtual void disableSensor(int32_t deviceId, InputDeviceSensorType sensorType) = 0;
-
-    /* Flush sensor data in input reader mapper. */
-    virtual void flushSensor(int32_t deviceId, InputDeviceSensorType sensorType) = 0;
-
-    /* Set color for the light */
-    virtual bool setLightColor(int32_t deviceId, int32_t lightId, int32_t color) = 0;
-    /* Set player ID for the light */
-    virtual bool setLightPlayerId(int32_t deviceId, int32_t lightId, int32_t playerId) = 0;
-    /* Get light color */
-    virtual std::optional<int32_t> getLightColor(int32_t deviceId, int32_t lightId) = 0;
-    /* Get light player ID */
-    virtual std::optional<int32_t> getLightPlayerId(int32_t deviceId, int32_t lightId) = 0;
-
-    /* Get the Bluetooth address of an input device, if known. */
-    virtual std::optional<std::string> getBluetoothAddress(int32_t deviceId) const = 0;
-
-    /* Sysfs node change reported. Recreate device if required to incorporate the new sysfs nodes */
-    virtual void sysfsNodeChanged(const std::string& sysfsNodePath) = 0;
-};
-
 // --- InputReaderConfiguration ---
 
 /*
@@ -163,51 +51,51 @@
  */
 struct InputReaderConfiguration {
     // Describes changes that have occurred.
-    enum {
+    enum class Change : uint32_t {
         // The mouse pointer speed changed.
-        CHANGE_POINTER_SPEED = 1 << 0,
+        POINTER_SPEED = 1u << 0,
 
         // The pointer gesture control changed.
-        CHANGE_POINTER_GESTURE_ENABLEMENT = 1 << 1,
+        POINTER_GESTURE_ENABLEMENT = 1u << 1,
 
         // The display size or orientation changed.
-        CHANGE_DISPLAY_INFO = 1 << 2,
+        DISPLAY_INFO = 1u << 2,
 
         // The visible touches option changed.
-        CHANGE_SHOW_TOUCHES = 1 << 3,
+        SHOW_TOUCHES = 1u << 3,
 
         // The keyboard layouts must be reloaded.
-        CHANGE_KEYBOARD_LAYOUTS = 1 << 4,
+        KEYBOARD_LAYOUTS = 1u << 4,
 
         // The device name alias supplied by the may have changed for some devices.
-        CHANGE_DEVICE_ALIAS = 1 << 5,
+        DEVICE_ALIAS = 1u << 5,
 
         // The location calibration matrix changed.
-        CHANGE_TOUCH_AFFINE_TRANSFORMATION = 1 << 6,
+        TOUCH_AFFINE_TRANSFORMATION = 1u << 6,
 
         // The presence of an external stylus has changed.
-        CHANGE_EXTERNAL_STYLUS_PRESENCE = 1 << 7,
+        EXTERNAL_STYLUS_PRESENCE = 1u << 7,
 
         // The pointer capture mode has changed.
-        CHANGE_POINTER_CAPTURE = 1 << 8,
+        POINTER_CAPTURE = 1u << 8,
 
         // The set of disabled input devices (disabledDevices) has changed.
-        CHANGE_ENABLED_STATE = 1 << 9,
+        ENABLED_STATE = 1u << 9,
 
         // The device type has been updated.
-        CHANGE_DEVICE_TYPE = 1 << 10,
+        DEVICE_TYPE = 1u << 10,
 
         // The keyboard layout association has changed.
-        CHANGE_KEYBOARD_LAYOUT_ASSOCIATION = 1 << 11,
+        KEYBOARD_LAYOUT_ASSOCIATION = 1u << 11,
 
         // The stylus button reporting configurations has changed.
-        CHANGE_STYLUS_BUTTON_REPORTING = 1 << 12,
+        STYLUS_BUTTON_REPORTING = 1u << 12,
 
         // The touchpad settings changed.
-        CHANGE_TOUCHPAD_SETTINGS = 1 << 13,
+        TOUCHPAD_SETTINGS = 1u << 13,
 
         // All devices must be reopened.
-        CHANGE_MUST_REOPEN = 1 << 31,
+        MUST_REOPEN = 1u << 31,
     };
 
     // Gets the amount of time to disable virtual keys after the screen is touched
@@ -367,8 +255,6 @@
             stylusButtonMotionEventsEnabled(true),
             stylusPointerIconEnabled(false) {}
 
-    static std::string changesToString(uint32_t changes);
-
     std::optional<DisplayViewport> getDisplayViewportByType(ViewportType type) const;
     std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueDisplayId)
             const;
@@ -383,6 +269,116 @@
     std::vector<DisplayViewport> mDisplays;
 };
 
+using ConfigurationChanges = ftl::Flags<InputReaderConfiguration::Change>;
+
+// --- InputReaderInterface ---
+
+/* The interface for the InputReader shared library.
+ *
+ * Manages one or more threads that process raw input events and sends cooked event data to an
+ * input listener.
+ *
+ * The implementation must guarantee thread safety for this interface. However, since the input
+ * listener is NOT thread safe, all calls to the listener must happen from the same thread.
+ */
+class InputReaderInterface {
+public:
+    InputReaderInterface() {}
+    virtual ~InputReaderInterface() {}
+    /* Dumps the state of the input reader.
+     *
+     * This method may be called on any thread (usually by the input manager). */
+    virtual void dump(std::string& dump) = 0;
+
+    /* Called by the heartbeat to ensures that the reader has not deadlocked. */
+    virtual void monitor() = 0;
+
+    /* Returns true if the input device is enabled. */
+    virtual bool isInputDeviceEnabled(int32_t deviceId) = 0;
+
+    /* Makes the reader start processing events from the kernel. */
+    virtual status_t start() = 0;
+
+    /* Makes the reader stop processing any more events. */
+    virtual status_t stop() = 0;
+
+    /* Gets information about all input devices.
+     *
+     * This method may be called on any thread (usually by the input manager).
+     */
+    virtual std::vector<InputDeviceInfo> getInputDevices() const = 0;
+
+    /* Query current input state. */
+    virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode) = 0;
+    virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) = 0;
+    virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw) = 0;
+
+    virtual void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode,
+                                 int32_t toKeyCode) const = 0;
+
+    virtual int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const = 0;
+
+    /* Toggle Caps Lock */
+    virtual void toggleCapsLockState(int32_t deviceId) = 0;
+
+    /* Determine whether physical keys exist for the given framework-domain key codes. */
+    virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask,
+                         const std::vector<int32_t>& keyCodes, uint8_t* outFlags) = 0;
+
+    /* Requests that a reconfiguration of all input devices.
+     * The changes flag is a bitfield that indicates what has changed and whether
+     * the input devices must all be reopened. */
+    virtual void requestRefreshConfiguration(ConfigurationChanges changes) = 0;
+
+    /* Controls the vibrator of a particular input device. */
+    virtual void vibrate(int32_t deviceId, const VibrationSequence& sequence, ssize_t repeat,
+                         int32_t token) = 0;
+    virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;
+
+    virtual bool isVibrating(int32_t deviceId) = 0;
+
+    virtual std::vector<int32_t> getVibratorIds(int32_t deviceId) = 0;
+    /* Get battery level of a particular input device. */
+    virtual std::optional<int32_t> getBatteryCapacity(int32_t deviceId) = 0;
+    /* Get battery status of a particular input device. */
+    virtual std::optional<int32_t> getBatteryStatus(int32_t deviceId) = 0;
+    /* Get the device path for the battery of an input device. */
+    virtual std::optional<std::string> getBatteryDevicePath(int32_t deviceId) = 0;
+
+    virtual std::vector<InputDeviceLightInfo> getLights(int32_t deviceId) = 0;
+
+    virtual std::vector<InputDeviceSensorInfo> getSensors(int32_t deviceId) = 0;
+
+    /* Return true if the device can send input events to the specified display. */
+    virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) = 0;
+
+    /* Enable sensor in input reader mapper. */
+    virtual bool enableSensor(int32_t deviceId, InputDeviceSensorType sensorType,
+                              std::chrono::microseconds samplingPeriod,
+                              std::chrono::microseconds maxBatchReportLatency) = 0;
+
+    /* Disable sensor in input reader mapper. */
+    virtual void disableSensor(int32_t deviceId, InputDeviceSensorType sensorType) = 0;
+
+    /* Flush sensor data in input reader mapper. */
+    virtual void flushSensor(int32_t deviceId, InputDeviceSensorType sensorType) = 0;
+
+    /* Set color for the light */
+    virtual bool setLightColor(int32_t deviceId, int32_t lightId, int32_t color) = 0;
+    /* Set player ID for the light */
+    virtual bool setLightPlayerId(int32_t deviceId, int32_t lightId, int32_t playerId) = 0;
+    /* Get light color */
+    virtual std::optional<int32_t> getLightColor(int32_t deviceId, int32_t lightId) = 0;
+    /* Get light player ID */
+    virtual std::optional<int32_t> getLightPlayerId(int32_t deviceId, int32_t lightId) = 0;
+
+    /* Get the Bluetooth address of an input device, if known. */
+    virtual std::optional<std::string> getBluetoothAddress(int32_t deviceId) const = 0;
+
+    /* Sysfs node change reported. Recreate device if required to incorporate the new sysfs nodes */
+    virtual void sysfsNodeChanged(const std::string& sysfsNodePath) = 0;
+};
+
 // --- TouchAffineTransformation ---
 
 struct TouchAffineTransformation {
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index b5ee044..b86906b 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -180,7 +180,7 @@
 
 std::list<NotifyArgs> InputDevice::configure(nsecs_t when,
                                              const InputReaderConfiguration& readerConfig,
-                                             uint32_t changes) {
+                                             ConfigurationChanges changes) {
     std::list<NotifyArgs> out;
     mSources = 0;
     mClasses = ftl::Flags<InputDeviceClass>(0);
@@ -201,12 +201,14 @@
     mIsExternal = mClasses.test(InputDeviceClass::EXTERNAL);
     mHasMic = mClasses.test(InputDeviceClass::MIC);
 
+    using Change = InputReaderConfiguration::Change;
+
     if (!isIgnored()) {
         // Full configuration should happen the first time configure is called
         // and when the device type is changed. Changing a device type can
         // affect various other parameters so should result in a
         // reconfiguration.
-        if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_TYPE)) {
+        if (!changes.any() || changes.test(Change::DEVICE_TYPE)) {
             mConfiguration.clear();
             for_each_subdevice([this](InputDeviceContext& context) {
                 std::optional<PropertyMap> configuration =
@@ -220,7 +222,7 @@
                     getValueByKey(readerConfig.deviceTypeAssociations, mIdentifier.location);
         }
 
-        if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) {
+        if (!changes.any() || changes.test(Change::KEYBOARD_LAYOUTS)) {
             if (!mClasses.test(InputDeviceClass::VIRTUAL)) {
                 std::shared_ptr<KeyCharacterMap> keyboardLayout =
                         mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier);
@@ -237,7 +239,7 @@
             }
         }
 
-        if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) {
+        if (!changes.any() || changes.test(Change::DEVICE_ALIAS)) {
             if (!(mClasses.test(InputDeviceClass::VIRTUAL))) {
                 std::string alias = mContext->getPolicy()->getDeviceAlias(mIdentifier);
                 if (mAlias != alias) {
@@ -247,7 +249,7 @@
             }
         }
 
-        if (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE) {
+        if (changes.test(Change::ENABLED_STATE)) {
             // Do not execute this code on the first configure, because 'setEnabled' would call
             // InputMapper::reset, and you can't reset a mapper before it has been configured.
             // The mappers are configured for the first time at the bottom of this function.
@@ -256,7 +258,7 @@
             out += setEnabled(enabled, when);
         }
 
-        if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+        if (!changes.any() || changes.test(Change::DISPLAY_INFO)) {
             // In most situations, no port or name will be specified.
             mAssociatedDisplayPort = std::nullopt;
             mAssociatedDisplayUniqueId = std::nullopt;
@@ -305,7 +307,7 @@
                 }
             }
 
-            if (changes) {
+            if (changes.any()) {
                 // For first-time configuration, only allow device to be disabled after mappers have
                 // finished configuring. This is because we need to read some of the properties from
                 // the device's open fd.
@@ -320,7 +322,7 @@
 
         // If a device is just plugged but it might be disabled, we need to update some info like
         // axis range of touch from each InputMapper first, then disable it.
-        if (!changes) {
+        if (!changes.any()) {
             out += setEnabled(readerConfig.disabledDevices.find(mId) ==
                                       readerConfig.disabledDevices.end(),
                               when);
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 0afe79d..ea95f78 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -85,7 +85,7 @@
         mDisableVirtualKeysTimeout(LLONG_MIN),
         mNextTimeout(LLONG_MAX),
         mConfigurationChangesToRefresh(0) {
-    refreshConfigurationLocked(0);
+    refreshConfigurationLocked(/*changes=*/{});
     updateGlobalMetaStateLocked();
 }
 
@@ -122,9 +122,9 @@
         oldGeneration = mGeneration;
         timeoutMillis = -1;
 
-        uint32_t changes = mConfigurationChangesToRefresh;
-        if (changes) {
-            mConfigurationChangesToRefresh = 0;
+        auto changes = mConfigurationChangesToRefresh;
+        if (changes.any()) {
+            mConfigurationChangesToRefresh.clear();
             timeoutMillis = 0;
             refreshConfigurationLocked(changes);
         } else if (mNextTimeout != LLONG_MAX) {
@@ -236,7 +236,7 @@
     InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(eventHubId);
     std::shared_ptr<InputDevice> device = createDeviceLocked(eventHubId, identifier);
 
-    notifyAll(device->configure(when, mConfig, 0));
+    notifyAll(device->configure(when, mConfig, /*changes=*/{}));
     notifyAll(device->reset(when));
 
     if (device->isIgnored()) {
@@ -312,7 +312,7 @@
 
     std::list<NotifyArgs> resetEvents;
     if (device->hasEventHubDevices()) {
-        resetEvents += device->configure(when, mConfig, 0);
+        resetEvents += device->configure(when, mConfig, /*changes=*/{});
     }
     resetEvents += device->reset(when);
     notifyAll(std::move(resetEvents));
@@ -390,21 +390,21 @@
     mQueuedListener.notifyConfigurationChanged({mContext.getNextId(), when});
 }
 
-void InputReader::refreshConfigurationLocked(uint32_t changes) {
+void InputReader::refreshConfigurationLocked(ConfigurationChanges changes) {
     mPolicy->getReaderConfiguration(&mConfig);
     mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
 
-    if (!changes) return;
+    using Change = InputReaderConfiguration::Change;
+    if (!changes.any()) return;
 
-    ALOGI("Reconfiguring input devices, changes=%s",
-          InputReaderConfiguration::changesToString(changes).c_str());
+    ALOGI("Reconfiguring input devices, changes=%s", changes.string().c_str());
     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    if (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) {
+    if (changes.test(Change::DISPLAY_INFO)) {
         updatePointerDisplayLocked();
     }
 
-    if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
+    if (changes.test(Change::MUST_REOPEN)) {
         mEventHub->requestReopenDevices();
     } else {
         for (auto& devicePair : mDevices) {
@@ -413,7 +413,7 @@
         }
     }
 
-    if (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE) {
+    if (changes.test(Change::POINTER_CAPTURE)) {
         if (mCurrentPointerCaptureRequest == mConfig.pointerCaptureRequest) {
             ALOGV("Skipping notifying pointer capture changes: "
                   "There was no change in the pointer capture state.");
@@ -457,7 +457,7 @@
 }
 
 void InputReader::notifyExternalStylusPresenceChangedLocked() {
-    refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE);
+    refreshConfigurationLocked(InputReaderConfiguration::Change::EXTERNAL_STYLUS_PRESENCE);
 }
 
 void InputReader::getExternalStylusDevicesLocked(std::vector<InputDeviceInfo>& outDevices) {
@@ -671,11 +671,11 @@
     return device->getKeyCodeForKeyLocation(locationKeyCode);
 }
 
-void InputReader::requestRefreshConfiguration(uint32_t changes) {
+void InputReader::requestRefreshConfiguration(ConfigurationChanges changes) {
     std::scoped_lock _l(mLock);
 
-    if (changes) {
-        bool needWake = !mConfigurationChangesToRefresh;
+    if (changes.any()) {
+        bool needWake = !mConfigurationChangesToRefresh.any();
         mConfigurationChangesToRefresh |= changes;
 
         if (needWake) {
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 2091e16..73351c4 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -85,7 +85,7 @@
     void removeEventHubDevice(int32_t eventHubId);
     [[nodiscard]] std::list<NotifyArgs> configure(nsecs_t when,
                                                   const InputReaderConfiguration& readerConfig,
-                                                  uint32_t changes);
+                                                  ConfigurationChanges changes);
     [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when);
     [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvents, size_t count);
     [[nodiscard]] std::list<NotifyArgs> timeoutExpired(nsecs_t when);
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 120e150..9112913 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -77,7 +77,7 @@
     bool hasKeys(int32_t deviceId, uint32_t sourceMask, const std::vector<int32_t>& keyCodes,
                  uint8_t* outFlags) override;
 
-    void requestRefreshConfiguration(uint32_t changes) override;
+    void requestRefreshConfiguration(ConfigurationChanges changes) override;
 
     void vibrate(int32_t deviceId, const VibrationSequence& sequence, ssize_t repeat,
                  int32_t token) override;
@@ -233,8 +233,8 @@
     nsecs_t mNextTimeout GUARDED_BY(mLock);
     void requestTimeoutAtTimeLocked(nsecs_t when) REQUIRES(mLock);
 
-    uint32_t mConfigurationChangesToRefresh GUARDED_BY(mLock);
-    void refreshConfigurationLocked(uint32_t changes) REQUIRES(mLock);
+    ConfigurationChanges mConfigurationChangesToRefresh GUARDED_BY(mLock);
+    void refreshConfigurationLocked(ConfigurationChanges changes) REQUIRES(mLock);
 
     void notifyAll(std::list<NotifyArgs>&& argsList);
 
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index adc893b..8ef5ff6 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -139,26 +139,26 @@
 
 std::list<NotifyArgs> CursorInputMapper::reconfigure(nsecs_t when,
                                                      const InputReaderConfiguration& readerConfig,
-                                                     uint32_t changes) {
+                                                     ConfigurationChanges changes) {
     std::list<NotifyArgs> out = InputMapper::reconfigure(when, readerConfig, changes);
 
-    if (!changes) {
+    if (!changes.any()) {
         configureWithZeroChanges(readerConfig);
         return out;
     }
 
     const bool configurePointerCapture = mParameters.mode != Parameters::Mode::NAVIGATION &&
-            (changes & InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+            changes.test(InputReaderConfiguration::Change::POINTER_CAPTURE);
     if (configurePointerCapture) {
         configureOnPointerCapture(readerConfig);
         out.push_back(NotifyDeviceResetArgs(getContext()->getNextId(), when, getDeviceId()));
     }
 
-    if ((changes & InputReaderConfiguration::CHANGE_POINTER_SPEED) || configurePointerCapture) {
+    if (changes.test(InputReaderConfiguration::Change::POINTER_SPEED) || configurePointerCapture) {
         configureOnChangePointerSpeed(readerConfig);
     }
 
-    if ((changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO) || configurePointerCapture) {
+    if (changes.test(InputReaderConfiguration::Change::DISPLAY_INFO) || configurePointerCapture) {
         configureOnChangeDisplayInfo(readerConfig);
     }
     return out;
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index a7cdd51..caf2e5a 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -62,7 +62,7 @@
     virtual void dump(std::string& dump) override;
     [[nodiscard]] std::list<NotifyArgs> reconfigure(nsecs_t when,
                                                     const InputReaderConfiguration& readerConfig,
-                                                    uint32_t changes) override;
+                                                    ConfigurationChanges changes) override;
     [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
     [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
 
diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp
index 7100f88..987d2d0 100644
--- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.cpp
@@ -49,7 +49,7 @@
 
 std::list<NotifyArgs> ExternalStylusInputMapper::reconfigure(nsecs_t when,
                                                              const InputReaderConfiguration& config,
-                                                             uint32_t changes) {
+                                                             ConfigurationChanges changes) {
     getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis);
     mTouchButtonAccumulator.configure();
     return {};
diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
index 7f926a7..841c437 100644
--- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
+++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
@@ -35,7 +35,7 @@
     void dump(std::string& dump) override;
     [[nodiscard]] std::list<NotifyArgs> reconfigure(nsecs_t when,
                                                     const InputReaderConfiguration& config,
-                                                    uint32_t changes) override;
+                                                    ConfigurationChanges changes) override;
     [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
     [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
 
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index bd86a5a..0692dbb 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -38,7 +38,7 @@
 void InputMapper::dump(std::string& dump) {}
 
 std::list<NotifyArgs> InputMapper::reconfigure(nsecs_t when, const InputReaderConfiguration& config,
-                                               uint32_t changes) {
+                                               ConfigurationChanges changes) {
     return {};
 }
 
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 211be9f..f017317 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -55,7 +55,7 @@
     virtual void dump(std::string& dump);
     [[nodiscard]] virtual std::list<NotifyArgs> reconfigure(nsecs_t when,
                                                             const InputReaderConfiguration& config,
-                                                            uint32_t changes);
+                                                            ConfigurationChanges changes);
     [[nodiscard]] virtual std::list<NotifyArgs> reset(nsecs_t when);
     [[nodiscard]] virtual std::list<NotifyArgs> process(const RawEvent* rawEvent) = 0;
     [[nodiscard]] virtual std::list<NotifyArgs> timeoutExpired(nsecs_t when);
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index 3450f86..099a955 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -106,10 +106,10 @@
 
 std::list<NotifyArgs> JoystickInputMapper::reconfigure(nsecs_t when,
                                                        const InputReaderConfiguration& config,
-                                                       uint32_t changes) {
+                                                       ConfigurationChanges changes) {
     std::list<NotifyArgs> out = InputMapper::reconfigure(when, config, changes);
 
-    if (!changes) { // first time only
+    if (!changes.any()) { // first time only
         // Collect all axes.
         for (int32_t abs = 0; abs <= ABS_MAX; abs++) {
             if (!(getAbsAxisUsage(abs, getDeviceContext().getDeviceClasses())
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.h b/services/inputflinger/reader/mapper/JoystickInputMapper.h
index c9e92de..49673a2 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.h
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.h
@@ -31,7 +31,7 @@
     virtual void dump(std::string& dump) override;
     [[nodiscard]] std::list<NotifyArgs> reconfigure(nsecs_t when,
                                                     const InputReaderConfiguration& config,
-                                                    uint32_t changes) override;
+                                                    ConfigurationChanges changes) override;
     [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
     [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
 
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 63ea3a8..582fb46 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -134,19 +134,20 @@
 
 std::list<NotifyArgs> KeyboardInputMapper::reconfigure(nsecs_t when,
                                                        const InputReaderConfiguration& config,
-                                                       uint32_t changes) {
+                                                       ConfigurationChanges changes) {
     std::list<NotifyArgs> out = InputMapper::reconfigure(when, config, changes);
 
-    if (!changes) { // first time only
+    if (!changes.any()) { // first time only
         // Configure basic parameters.
         configureParameters();
     }
 
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+    if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO)) {
         mViewport = findViewport(config);
     }
 
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUT_ASSOCIATION)) {
+    if (!changes.any() ||
+        changes.test(InputReaderConfiguration::Change::KEYBOARD_LAYOUT_ASSOCIATION)) {
         mKeyboardLayoutInfo =
                 getValueByKey(config.keyboardLayoutAssociations, getDeviceContext().getLocation());
     }
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index 25fad57..bd27383 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -33,7 +33,7 @@
     void dump(std::string& dump) override;
     [[nodiscard]] std::list<NotifyArgs> reconfigure(nsecs_t when,
                                                     const InputReaderConfiguration& config,
-                                                    uint32_t changes) override;
+                                                    ConfigurationChanges changes) override;
     [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
     [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
 
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index 2ffa5cd..13f2e59 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -66,12 +66,12 @@
 
 std::list<NotifyArgs> RotaryEncoderInputMapper::reconfigure(nsecs_t when,
                                                             const InputReaderConfiguration& config,
-                                                            uint32_t changes) {
+                                                            ConfigurationChanges changes) {
     std::list<NotifyArgs> out = InputMapper::reconfigure(when, config, changes);
-    if (!changes) {
+    if (!changes.any()) {
         mRotaryEncoderScrollAccumulator.configure(getDeviceContext());
     }
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+    if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO)) {
         std::optional<DisplayViewport> internalViewport =
                 config.getDisplayViewportByType(ViewportType::INTERNAL);
         if (internalViewport) {
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
index 8feaf8e..d3dcbe1 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
@@ -34,7 +34,7 @@
     virtual void dump(std::string& dump) override;
     [[nodiscard]] std::list<NotifyArgs> reconfigure(nsecs_t when,
                                                     const InputReaderConfiguration& config,
-                                                    uint32_t changes) override;
+                                                    ConfigurationChanges changes) override;
     [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
     [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
 
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.cpp b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
index f7f23a4..a131e35 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.cpp
@@ -119,10 +119,10 @@
 
 std::list<NotifyArgs> SensorInputMapper::reconfigure(nsecs_t when,
                                                      const InputReaderConfiguration& config,
-                                                     uint32_t changes) {
+                                                     ConfigurationChanges changes) {
     std::list<NotifyArgs> out = InputMapper::reconfigure(when, config, changes);
 
-    if (!changes) { // first time only
+    if (!changes.any()) { // first time only
         mDeviceEnabled = true;
         // Check if device has MSC_TIMESTAMP event.
         mHasHardwareTimestamp = getDeviceContext().hasMscEvent(MSC_TIMESTAMP);
diff --git a/services/inputflinger/reader/mapper/SensorInputMapper.h b/services/inputflinger/reader/mapper/SensorInputMapper.h
index 2f3a396..1f82559 100644
--- a/services/inputflinger/reader/mapper/SensorInputMapper.h
+++ b/services/inputflinger/reader/mapper/SensorInputMapper.h
@@ -36,7 +36,7 @@
     void dump(std::string& dump) override;
     [[nodiscard]] std::list<NotifyArgs> reconfigure(nsecs_t when,
                                                     const InputReaderConfiguration& config,
-                                                    uint32_t changes) override;
+                                                    ConfigurationChanges changes) override;
     [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
     [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
     bool enableSensor(InputDeviceSensorType sensorType, std::chrono::microseconds samplingPeriod,
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 60bf857..55b869a 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -290,7 +290,7 @@
 
 std::list<NotifyArgs> TouchInputMapper::reconfigure(nsecs_t when,
                                                     const InputReaderConfiguration& config,
-                                                    uint32_t changes) {
+                                                    ConfigurationChanges changes) {
     std::list<NotifyArgs> out = InputMapper::reconfigure(when, config, changes);
 
     mConfig = config;
@@ -298,7 +298,7 @@
     // Full configuration should happen the first time configure is called and
     // when the device type is changed. Changing a device type can affect
     // various other parameters so should result in a reconfiguration.
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_TYPE)) {
+    if (!changes.any() || changes.test(InputReaderConfiguration::Change::DEVICE_TYPE)) {
         // Configure basic parameters.
         configureParameters();
 
@@ -314,33 +314,34 @@
         resolveCalibration();
     }
 
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) {
+    if (!changes.any() ||
+        changes.test(InputReaderConfiguration::Change::TOUCH_AFFINE_TRANSFORMATION)) {
         // Update location calibration to reflect current settings
         updateAffineTransformation();
     }
 
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {
+    if (!changes.any() || changes.test(InputReaderConfiguration::Change::POINTER_SPEED)) {
         // Update pointer speed.
         mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters);
         mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
         mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
     }
 
+    using namespace ftl::flag_operators;
     bool resetNeeded = false;
-    if (!changes ||
-        (changes &
-         (InputReaderConfiguration::CHANGE_DISPLAY_INFO |
-          InputReaderConfiguration::CHANGE_POINTER_CAPTURE |
-          InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT |
-          InputReaderConfiguration::CHANGE_SHOW_TOUCHES |
-          InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE |
-          InputReaderConfiguration::CHANGE_DEVICE_TYPE))) {
+    if (!changes.any() ||
+        changes.any(InputReaderConfiguration::Change::DISPLAY_INFO |
+                    InputReaderConfiguration::Change::POINTER_CAPTURE |
+                    InputReaderConfiguration::Change::POINTER_GESTURE_ENABLEMENT |
+                    InputReaderConfiguration::Change::SHOW_TOUCHES |
+                    InputReaderConfiguration::Change::EXTERNAL_STYLUS_PRESENCE |
+                    InputReaderConfiguration::Change::DEVICE_TYPE)) {
         // Configure device sources, display dimensions, orientation and
         // scaling factors.
         configureInputDevice(when, &resetNeeded);
     }
 
-    if (changes && resetNeeded) {
+    if (changes.any() && resetNeeded) {
         out += reset(when);
 
         // Send reset, unless this is the first time the device has been configured,
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index e7d66a1..e023e90 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -155,7 +155,7 @@
     void dump(std::string& dump) override;
     [[nodiscard]] std::list<NotifyArgs> reconfigure(nsecs_t when,
                                                     const InputReaderConfiguration& config,
-                                                    uint32_t changes) override;
+                                                    ConfigurationChanges changes) override;
     [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
     [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
 
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
index 5a1ced4..8753b48 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.cpp
@@ -222,13 +222,13 @@
 
 std::list<NotifyArgs> TouchpadInputMapper::reconfigure(nsecs_t when,
                                                        const InputReaderConfiguration& config,
-                                                       uint32_t changes) {
-    if (!changes) {
+                                                       ConfigurationChanges changes) {
+    if (!changes.any()) {
         // First time configuration
         mPropertyProvider.loadPropertiesFromIdcFile(getDeviceContext().getConfiguration());
     }
 
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+    if (!changes.any() || changes.test(InputReaderConfiguration::Change::DISPLAY_INFO)) {
         std::optional<int32_t> displayId = mPointerController->getDisplayId();
         ui::Rotation orientation = ui::ROTATION_0;
         if (displayId.has_value()) {
@@ -238,7 +238,7 @@
         }
         mGestureConverter.setOrientation(orientation);
     }
-    if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCHPAD_SETTINGS)) {
+    if (!changes.any() || changes.test(InputReaderConfiguration::Change::TOUCHPAD_SETTINGS)) {
         mPropertyProvider.getProperty("Use Custom Touchpad Pointer Accel Curve")
                 .setBoolValues({true});
         GesturesProp accelCurveProp = mPropertyProvider.getProperty("Pointer Accel Curve");
diff --git a/services/inputflinger/reader/mapper/TouchpadInputMapper.h b/services/inputflinger/reader/mapper/TouchpadInputMapper.h
index e051097..268b275 100644
--- a/services/inputflinger/reader/mapper/TouchpadInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchpadInputMapper.h
@@ -47,7 +47,7 @@
 
     [[nodiscard]] std::list<NotifyArgs> reconfigure(nsecs_t when,
                                                     const InputReaderConfiguration& config,
-                                                    uint32_t changes) override;
+                                                    ConfigurationChanges changes) override;
     [[nodiscard]] std::list<NotifyArgs> reset(nsecs_t when) override;
     [[nodiscard]] std::list<NotifyArgs> process(const RawEvent* rawEvent) override;
 
diff --git a/services/inputflinger/tests/InputMapperTest.cpp b/services/inputflinger/tests/InputMapperTest.cpp
index ae30006..ad48a79 100644
--- a/services/inputflinger/tests/InputMapperTest.cpp
+++ b/services/inputflinger/tests/InputMapperTest.cpp
@@ -50,12 +50,12 @@
     mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, key, value);
 }
 
-std::list<NotifyArgs> InputMapperTest::configureDevice(uint32_t changes) {
-    if (!changes ||
-        (changes &
-         (InputReaderConfiguration::CHANGE_DISPLAY_INFO |
-          InputReaderConfiguration::CHANGE_POINTER_CAPTURE |
-          InputReaderConfiguration::CHANGE_DEVICE_TYPE))) {
+std::list<NotifyArgs> InputMapperTest::configureDevice(ConfigurationChanges changes) {
+    using namespace ftl::flag_operators;
+    if (!changes.any() ||
+        (changes.any(InputReaderConfiguration::Change::DISPLAY_INFO |
+                     InputReaderConfiguration::Change::POINTER_CAPTURE |
+                     InputReaderConfiguration::Change::DEVICE_TYPE))) {
         mReader->requestRefreshConfiguration(changes);
         mReader->loopOnce();
     }
@@ -94,7 +94,7 @@
                                                    ViewportType viewportType) {
     mFakePolicy->addDisplayViewport(displayId, width, height, orientation, /* isActive= */ true,
                                     uniqueId, physicalPort, viewportType);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
 }
 
 void InputMapperTest::clearViewports() {
diff --git a/services/inputflinger/tests/InputMapperTest.h b/services/inputflinger/tests/InputMapperTest.h
index df601ea..d969034 100644
--- a/services/inputflinger/tests/InputMapperTest.h
+++ b/services/inputflinger/tests/InputMapperTest.h
@@ -54,7 +54,7 @@
     void TearDown() override;
 
     void addConfigurationProperty(const char* key, const char* value);
-    std::list<NotifyArgs> configureDevice(uint32_t changes);
+    std::list<NotifyArgs> configureDevice(ConfigurationChanges changes);
     std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
                                            const std::string& location, int32_t eventHubId,
                                            ftl::Flags<InputDeviceClass> classes, int bus = 0);
@@ -62,7 +62,7 @@
     T& addMapperAndConfigure(Args... args) {
         T& mapper =
                 mDevice->addMapper<T>(EVENTHUB_ID, mFakePolicy->getReaderConfiguration(), args...);
-        configureDevice(0);
+        configureDevice(/*changes=*/{});
         std::list<NotifyArgs> resetArgList = mDevice->reset(ARBITRARY_TIME);
         resetArgList += mapper.reset(ARBITRARY_TIME);
         // Loop the reader to flush the input listener queue.
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index da3fe5b..0b50504 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -265,13 +265,13 @@
     }
 
     std::list<NotifyArgs> reconfigure(nsecs_t, const InputReaderConfiguration& config,
-                                      uint32_t changes) override {
+                                      ConfigurationChanges changes) override {
         std::scoped_lock<std::mutex> lock(mLock);
         mConfigureWasCalled = true;
 
         // Find the associated viewport if exist.
         const std::optional<uint8_t> displayPort = getDeviceContext().getAssociatedDisplayPort();
-        if (displayPort && (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+        if (displayPort && changes.test(InputReaderConfiguration::Change::DISPLAY_INFO)) {
             mViewport = config.getDisplayViewportByPort(*displayPort);
         }
 
@@ -610,12 +610,12 @@
 
     void disableDevice(int32_t deviceId) {
         mFakePolicy->addDisabledDevice(deviceId);
-        mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_ENABLED_STATE);
+        mReader->requestRefreshConfiguration(InputReaderConfiguration::Change::ENABLED_STATE);
     }
 
     void enableDevice(int32_t deviceId) {
         mFakePolicy->removeDisabledDevice(deviceId);
-        mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_ENABLED_STATE);
+        mReader->requestRefreshConfiguration(InputReaderConfiguration::Change::ENABLED_STATE);
     }
 
     FakeInputMapper& addDeviceWithFakeInputMapper(int32_t deviceId, int32_t eventHubId,
@@ -1043,7 +1043,7 @@
     mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
                                     ui::ROTATION_0, /*isActive=*/true, "local:1", hdmi1,
                                     ViewportType::EXTERNAL);
-    mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    mReader->requestRefreshConfiguration(InputReaderConfiguration::Change::DISPLAY_INFO);
     mReader->loopOnce();
 
     // Add the device, and make sure all of the callbacks are triggered.
@@ -1142,21 +1142,21 @@
     NotifyPointerCaptureChangedArgs args;
 
     auto request = mFakePolicy->setPointerCapture(true);
-    mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    mReader->requestRefreshConfiguration(InputReaderConfiguration::Change::POINTER_CAPTURE);
     mReader->loopOnce();
     mFakeListener->assertNotifyCaptureWasCalled(&args);
     ASSERT_TRUE(args.request.enable) << "Pointer Capture should be enabled.";
     ASSERT_EQ(args.request, request) << "Pointer Capture sequence number should match.";
 
     mFakePolicy->setPointerCapture(false);
-    mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    mReader->requestRefreshConfiguration(InputReaderConfiguration::Change::POINTER_CAPTURE);
     mReader->loopOnce();
     mFakeListener->assertNotifyCaptureWasCalled(&args);
     ASSERT_FALSE(args.request.enable) << "Pointer Capture should be disabled.";
 
     // Verify that the Pointer Capture state is not updated when the configuration value
     // does not change.
-    mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    mReader->requestRefreshConfiguration(InputReaderConfiguration::Change::POINTER_CAPTURE);
     mReader->loopOnce();
     mFakeListener->assertNotifyCaptureWasNotCalled();
 }
@@ -1527,7 +1527,7 @@
                                       ViewportType viewportType) {
         mFakePolicy->addDisplayViewport(displayId, width, height, orientation, /*isActive=*/true,
                                         uniqueId, physicalPort, viewportType);
-        mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+        mReader->requestRefreshConfiguration(InputReaderConfiguration::Change::DISPLAY_INFO);
     }
 
     void assertReceivedMotion(int32_t action, const std::vector<Point>& points) {
@@ -2070,7 +2070,7 @@
 TYPED_TEST(StylusButtonIntegrationTest, DISABLED_StylusButtonMotionEventsDisabled) {
     TestFixture::mFakePolicy->setStylusButtonMotionEventsEnabled(false);
     TestFixture::mReader->requestRefreshConfiguration(
-            InputReaderConfiguration::CHANGE_STYLUS_BUTTON_REPORTING);
+            InputReaderConfiguration::Change::STYLUS_BUTTON_REPORTING);
 
     const Point centerPoint = TestFixture::mTouchscreen->getCenterPoint();
     const auto touchscreenId = TestFixture::mTouchscreenInfo.getId();
@@ -2341,7 +2341,7 @@
 TEST_F(InputDeviceTest, WhenNoMappersAreRegistered_DeviceIsIgnored) {
     // Configuration.
     InputReaderConfiguration config;
-    std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, config, 0);
+    std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, config, /*changes=*/{});
 
     // Reset.
     unused += mDevice->reset(ARBITRARY_TIME);
@@ -2402,7 +2402,7 @@
     mapper2.setMetaState(AMETA_SHIFT_ON);
 
     InputReaderConfiguration config;
-    std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, config, 0);
+    std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, config, /*changes=*/{});
 
     std::optional<std::string> propertyValue = mDevice->getConfiguration().getString("key");
     ASSERT_TRUE(propertyValue.has_value())
@@ -2484,7 +2484,8 @@
 
     // First Configuration.
     std::list<NotifyArgs> unused =
-            mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
+            mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+                               /*changes=*/{});
 
     // Device should be enabled by default.
     ASSERT_TRUE(mDevice->isEnabled());
@@ -2495,7 +2496,7 @@
 
     mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi);
     unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+                                 InputReaderConfiguration::Change::DISPLAY_INFO);
     // Device should be disabled because it is associated with a specific display via
     // input port <-> display port association, but the corresponding display is not found
     ASSERT_FALSE(mDevice->isEnabled());
@@ -2505,18 +2506,18 @@
                                     ui::ROTATION_0, /*isActive=*/true, UNIQUE_ID, hdmi,
                                     ViewportType::INTERNAL);
     unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+                                 InputReaderConfiguration::Change::DISPLAY_INFO);
     ASSERT_TRUE(mDevice->isEnabled());
 
     // Device should be disabled after set disable.
     mFakePolicy->addDisabledDevice(mDevice->getId());
     unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::CHANGE_ENABLED_STATE);
+                                 InputReaderConfiguration::Change::ENABLED_STATE);
     ASSERT_FALSE(mDevice->isEnabled());
 
     // Device should still be disabled even found the associated display.
     unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+                                 InputReaderConfiguration::Change::DISPLAY_INFO);
     ASSERT_FALSE(mDevice->isEnabled());
 }
 
@@ -2526,14 +2527,15 @@
     mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, mFakePolicy->getReaderConfiguration(),
                                         AINPUT_SOURCE_KEYBOARD);
     std::list<NotifyArgs> unused =
-            mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
+            mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+                               /*changes=*/{});
     ASSERT_TRUE(mDevice->isEnabled());
 
     // Device should be disabled because it is associated with a specific display, but the
     // corresponding display is not found.
     mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
     unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+                                 InputReaderConfiguration::Change::DISPLAY_INFO);
     ASSERT_FALSE(mDevice->isEnabled());
 
     // Device should be enabled when a display is found.
@@ -2541,18 +2543,18 @@
                                     ui::ROTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID,
                                     NO_PORT, ViewportType::INTERNAL);
     unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+                                 InputReaderConfiguration::Change::DISPLAY_INFO);
     ASSERT_TRUE(mDevice->isEnabled());
 
     // Device should be disabled after set disable.
     mFakePolicy->addDisabledDevice(mDevice->getId());
     unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::CHANGE_ENABLED_STATE);
+                                 InputReaderConfiguration::Change::ENABLED_STATE);
     ASSERT_FALSE(mDevice->isEnabled());
 
     // Device should still be disabled even found the associated display.
     unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+                                 InputReaderConfiguration::Change::DISPLAY_INFO);
     ASSERT_FALSE(mDevice->isEnabled());
 }
 
@@ -2561,14 +2563,15 @@
     mDevice->addMapper<FakeInputMapper>(EVENTHUB_ID, mFakePolicy->getReaderConfiguration(),
                                         AINPUT_SOURCE_KEYBOARD);
     std::list<NotifyArgs> unused =
-            mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
+            mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+                               /*changes=*/{});
 
     mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, DISPLAY_UNIQUE_ID);
     mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
                                     ui::ROTATION_0, /* isActive= */ true, DISPLAY_UNIQUE_ID,
                                     NO_PORT, ViewportType::INTERNAL);
     unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+                                 InputReaderConfiguration::Change::DISPLAY_INFO);
     ASSERT_EQ(DISPLAY_UNIQUE_ID, mDevice->getAssociatedDisplayUniqueId());
 }
 
@@ -3423,7 +3426,7 @@
                                                     AINPUT_KEYBOARD_TYPE_ALPHABETIC);
     std::list<NotifyArgs> unused =
             device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                               /*changes=*/0);
+                               /*changes=*/{});
     unused += device2->reset(ARBITRARY_TIME);
 
     // Prepared displays and associated info.
@@ -3436,7 +3439,7 @@
 
     // No associated display viewport found, should disable the device.
     unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+                                 InputReaderConfiguration::Change::DISPLAY_INFO);
     ASSERT_FALSE(device2->isEnabled());
 
     // Prepare second display.
@@ -3447,7 +3450,7 @@
                                  SECONDARY_UNIQUE_ID, hdmi2, ViewportType::EXTERNAL);
     // Default device will reconfigure above, need additional reconfiguration for another device.
     unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+                                 InputReaderConfiguration::Change::DISPLAY_INFO);
 
     // Device should be enabled after the associated display is found.
     ASSERT_TRUE(mDevice->isEnabled());
@@ -3535,7 +3538,7 @@
                                                     AINPUT_KEYBOARD_TYPE_ALPHABETIC);
     std::list<NotifyArgs> unused =
             device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                               /*changes=*/0);
+                               /*changes=*/{});
     unused += device2->reset(ARBITRARY_TIME);
 
     ASSERT_TRUE(mFakeEventHub->getLedState(SECOND_EVENTHUB_ID, LED_CAPSL));
@@ -3598,7 +3601,7 @@
                                                     AINPUT_KEYBOARD_TYPE_ALPHABETIC);
     std::list<NotifyArgs> unused =
             device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                               /*changes=*/0);
+                               /*changes=*/{});
     unused += device2->reset(ARBITRARY_TIME);
 
     // Initial metastate is AMETA_NONE.
@@ -3667,7 +3670,7 @@
 
     // Disable device, it should synthesize cancellation events for down events.
     mFakePolicy->addDisabledDevice(DEVICE_ID);
-    configureDevice(InputReaderConfiguration::CHANGE_ENABLED_STATE);
+    configureDevice(InputReaderConfiguration::Change::ENABLED_STATE);
 
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
     ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
@@ -3681,12 +3684,13 @@
                                             AINPUT_SOURCE_KEYBOARD,
                                             AINPUT_KEYBOARD_TYPE_ALPHABETIC);
     std::list<NotifyArgs> unused =
-            mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
+            mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+                               /*changes=*/{});
 
     mFakePolicy->addKeyboardLayoutAssociation(DEVICE_LOCATION, DEVICE_KEYBOARD_LAYOUT_INFO);
 
     unused += mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUT_ASSOCIATION);
+                                 InputReaderConfiguration::Change::KEYBOARD_LAYOUT_ASSOCIATION);
 
     InputDeviceInfo deviceInfo = mDevice->getDeviceInfo();
     ASSERT_EQ(DEVICE_KEYBOARD_LAYOUT_INFO.languageTag,
@@ -3703,7 +3707,7 @@
     addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
                                                AINPUT_KEYBOARD_TYPE_ALPHABETIC);
     InputReaderConfiguration config;
-    std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, config, 0);
+    std::list<NotifyArgs> unused = mDevice->configure(ARBITRARY_TIME, config, /*changes=*/{});
 
     ASSERT_EQ("en", mDevice->getDeviceInfo().getKeyboardLayoutInfo()->languageTag);
     ASSERT_EQ("extended", mDevice->getDeviceInfo().getKeyboardLayoutInfo()->layoutType);
@@ -4509,7 +4513,7 @@
     // and events are generated the usual way.
     const uint32_t generation = mReader->getContext()->getGeneration();
     mFakePolicy->setPointerCapture(false);
-    configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    configureDevice(InputReaderConfiguration::Change::POINTER_CAPTURE);
     ASSERT_TRUE(mReader->getContext()->getGeneration() != generation);
 
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
@@ -4558,7 +4562,7 @@
 
     // Enable Pointer Capture
     mFakePolicy->setPointerCapture(true);
-    configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    configureDevice(InputReaderConfiguration::Change::POINTER_CAPTURE);
     NotifyPointerCaptureChangedArgs captureArgs;
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyCaptureWasCalled(&captureArgs));
     ASSERT_TRUE(captureArgs.request.enable);
@@ -4600,7 +4604,7 @@
 
     // Enable Pointer Capture.
     mFakePolicy->setPointerCapture(true);
-    configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    configureDevice(InputReaderConfiguration::Change::POINTER_CAPTURE);
     NotifyPointerCaptureChangedArgs captureArgs;
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyCaptureWasCalled(&captureArgs));
     ASSERT_TRUE(captureArgs.request.enable);
@@ -4626,7 +4630,7 @@
     // The InputDevice is not associated with any display.
     prepareSecondaryDisplay();
     mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
 
     mFakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
     mFakePointerController->setPosition(100, 200);
@@ -4653,7 +4657,7 @@
     prepareSecondaryDisplay();
     mFakePolicy->setDefaultPointerDisplayId(SECONDARY_DISPLAY_ID);
     mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, SECONDARY_DISPLAY_UNIQUE_ID);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
 
     mFakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
     mFakePointerController->setPosition(100, 200);
@@ -4678,7 +4682,7 @@
     // Associate the InputDevice with the secondary display.
     prepareSecondaryDisplay();
     mFakePolicy->addInputUniqueIdAssociation(DEVICE_LOCATION, SECONDARY_DISPLAY_UNIQUE_ID);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
 
     // The mapper should not generate any events because it is associated with a display that is
     // different from the pointer display.
@@ -5845,7 +5849,7 @@
     viewport->physicalRight = 30;
     viewport->physicalBottom = 610;
     mFakePolicy->updateViewport(*viewport);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
 
     // Start the touch.
     process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, BTN_TOUCH, 1);
@@ -6570,7 +6574,7 @@
     auto viewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL);
     viewport->isActive = false;
     mFakePolicy->updateViewport(*viewport);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
 
     // We should receive a cancel event for the ongoing gesture.
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -6595,7 +6599,7 @@
     // Make the viewport active again. The device should resume processing events.
     viewport->isActive = true;
     mFakePolicy->updateViewport(*viewport);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
 
     // The device is reset because it changes back to direct mode, without generating any events.
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled());
@@ -6763,7 +6767,7 @@
     // Send update to the mapper.
     std::list<NotifyArgs> unused2 =
             mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                               InputReaderConfiguration::CHANGE_DEVICE_TYPE /*changes*/);
+                               InputReaderConfiguration::Change::DEVICE_TYPE /*changes*/);
 
     // Check whether device type update was successful.
     ASSERT_EQ(AINPUT_SOURCE_TOUCH_NAVIGATION, mDevice->getSources());
@@ -6784,7 +6788,7 @@
     viewport->physicalRight = DISPLAY_WIDTH / 2;
     viewport->physicalBottom = DISPLAY_HEIGHT / 2;
     mFakePolicy->updateViewport(*viewport);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
 
     SingleTouchInputMapper& mapper = addMapperAndConfigure<SingleTouchInputMapper>();
 
@@ -6873,7 +6877,7 @@
         v.uniqueId = UNIQUE_ID;
         v.type = ViewportType::INTERNAL;
         mFakePolicy->updateViewport(v);
-        configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+        configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
     }
 
     void assertReceivedMove(const Point& point) {
@@ -7233,7 +7237,7 @@
         mStylusState.pressure = 0.f;
         mStylusState.toolType = ToolType::STYLUS;
         mReader->getContext()->setExternalStylusDevices({mExternalStylusDeviceInfo});
-        configureDevice(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE);
+        configureDevice(InputReaderConfiguration::Change::EXTERNAL_STYLUS_PRESENCE);
         processExternalStylusState(mapper);
         return mapper;
     }
@@ -9289,7 +9293,7 @@
     // Don't set touch.enableForInactiveViewport to verify the default behavior.
     mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0,
                                     /*isActive=*/false, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
     prepareAxes(POSITION);
     MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
 
@@ -9309,7 +9313,7 @@
     addConfigurationProperty("touch.enableForInactiveViewport", "1");
     mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, ui::ROTATION_0,
                                     /*isActive=*/false, UNIQUE_ID, NO_PORT, ViewportType::INTERNAL);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
     prepareAxes(POSITION);
     MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
 
@@ -9331,7 +9335,7 @@
     ASSERT_TRUE(optionalDisplayViewport.has_value());
     DisplayViewport displayViewport = *optionalDisplayViewport;
 
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
     prepareAxes(POSITION);
     MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
 
@@ -9347,7 +9351,7 @@
     // Deactivate display viewport
     displayViewport.isActive = false;
     ASSERT_TRUE(mFakePolicy->updateViewport(displayViewport));
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
 
     // The ongoing touch should be canceled immediately
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs));
@@ -9362,7 +9366,7 @@
     // Reactivate display viewport
     displayViewport.isActive = true;
     ASSERT_TRUE(mFakePolicy->updateViewport(displayViewport));
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
 
     // Finger move again starts new gesture
     x += 10, y += 10;
@@ -9405,7 +9409,7 @@
                                                       mFakePolicy->getReaderConfiguration());
     std::list<NotifyArgs> unused =
             device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                               /*changes=*/0);
+                               /*changes=*/{});
     unused += device2->reset(ARBITRARY_TIME);
 
     // Setup PointerController.
@@ -9426,8 +9430,8 @@
 
     // Default device will reconfigure above, need additional reconfiguration for another device.
     unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::CHANGE_DISPLAY_INFO |
-                                         InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
+                                 InputReaderConfiguration::Change::DISPLAY_INFO |
+                                         InputReaderConfiguration::Change::SHOW_TOUCHES);
 
     // Two fingers down at default display.
     int32_t x1 = 100, y1 = 125, x2 = 300, y2 = 500;
@@ -9458,7 +9462,7 @@
     // Disable the show touches configuration and ensure the spots are cleared.
     mFakePolicy->setShowTouches(false);
     unused += device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
-                                 InputReaderConfiguration::CHANGE_SHOW_TOUCHES);
+                                 InputReaderConfiguration::Change::SHOW_TOUCHES);
 
     ASSERT_TRUE(fakePointerController->getSpots().empty());
 }
@@ -10368,7 +10372,7 @@
 
     // non captured touchpad should be a mouse source
     mFakePolicy->setPointerCapture(false);
-    configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    configureDevice(InputReaderConfiguration::Change::POINTER_CAPTURE);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
     ASSERT_EQ(AINPUT_SOURCE_MOUSE, mapper.getSources());
 }
@@ -10453,7 +10457,7 @@
 
     // captured touchpad should be a touchpad device
     mFakePolicy->setPointerCapture(true);
-    configureDevice(InputReaderConfiguration::CHANGE_POINTER_CAPTURE);
+    configureDevice(InputReaderConfiguration::Change::POINTER_CAPTURE);
     ASSERT_EQ(AINPUT_SOURCE_TOUCHPAD, mapper.getSources());
 }
 
@@ -10839,7 +10843,7 @@
     auto viewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL);
     viewport->isActive = false;
     mFakePolicy->updateViewport(*viewport);
-    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    configureDevice(InputReaderConfiguration::Change::DISPLAY_INFO);
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(
             AllOf(WithMotionAction(AMOTION_EVENT_ACTION_CANCEL),
                   WithSource(AINPUT_SOURCE_MOUSE | AINPUT_SOURCE_STYLUS),
@@ -10947,14 +10951,6 @@
         mFakePolicy.clear();
     }
 
-    std::list<NotifyArgs> configureDevice(uint32_t changes) {
-        if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
-            mReader->requestRefreshConfiguration(changes);
-            mReader->loopOnce();
-        }
-        return mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
-    }
-
     std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
                                            const std::string& location, int32_t eventHubId,
                                            ftl::Flags<InputDeviceClass> classes) {
diff --git a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
index 8ed1f31..8098ef2 100644
--- a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp
@@ -53,12 +53,14 @@
                 [&]() -> void {
                     std::list<NotifyArgs> unused =
                             mapper.reconfigure(fdp->ConsumeIntegral<nsecs_t>(), policyConfig,
-                                               fdp->ConsumeIntegral<int32_t>());
+                                               InputReaderConfiguration::Change(
+                                                       fdp->ConsumeIntegral<int32_t>()));
                 },
                 [&]() -> void {
                     // Need to reconfigure with 0 or you risk a NPE.
                     std::list<NotifyArgs> unused =
-                            mapper.reconfigure(fdp->ConsumeIntegral<nsecs_t>(), policyConfig, 0);
+                            mapper.reconfigure(fdp->ConsumeIntegral<nsecs_t>(), policyConfig,
+                                               InputReaderConfiguration::Change(0));
                     InputDeviceInfo info;
                     mapper.populateDeviceInfo(info);
                 },
@@ -71,7 +73,8 @@
 
                     // Need to reconfigure with 0 or you risk a NPE.
                     std::list<NotifyArgs> unused =
-                            mapper.reconfigure(fdp->ConsumeIntegral<nsecs_t>(), policyConfig, 0);
+                            mapper.reconfigure(fdp->ConsumeIntegral<nsecs_t>(), policyConfig,
+                                               InputReaderConfiguration::Change(0));
                     RawEvent rawEvent{fdp->ConsumeIntegral<nsecs_t>(),
                                       fdp->ConsumeIntegral<nsecs_t>(),
                                       fdp->ConsumeIntegral<int32_t>(),
@@ -90,7 +93,8 @@
                 [&]() -> void {
                     // Need to reconfigure with 0 or you risk a NPE.
                     std::list<NotifyArgs> unused =
-                            mapper.reconfigure(fdp->ConsumeIntegral<nsecs_t>(), policyConfig, 0);
+                            mapper.reconfigure(fdp->ConsumeIntegral<nsecs_t>(), policyConfig,
+                                               InputReaderConfiguration::Change(0));
                     mapper.getAssociatedDisplayId();
                 },
         })();
diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h
index d42d11c..84ac0fd 100644
--- a/services/inputflinger/tests/fuzzers/FuzzContainer.h
+++ b/services/inputflinger/tests/fuzzers/FuzzContainer.h
@@ -59,7 +59,7 @@
     void configureDevice() {
         nsecs_t arbitraryTime = mFdp->ConsumeIntegral<nsecs_t>();
         std::list<NotifyArgs> out;
-        out += mFuzzDevice->configure(arbitraryTime, mPolicyConfig, 0);
+        out += mFuzzDevice->configure(arbitraryTime, mPolicyConfig, /*changes=*/{});
         out += mFuzzDevice->reset(arbitraryTime);
         for (const NotifyArgs& args : out) {
             mFuzzListener.notify(args);
diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
index baece3c..9223287 100644
--- a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
@@ -82,7 +82,7 @@
         return reader->hasKeys(deviceId, sourceMask, keyCodes, outFlags);
     }
 
-    void requestRefreshConfiguration(uint32_t changes) {
+    void requestRefreshConfiguration(ConfigurationChanges changes) {
         reader->requestRefreshConfiguration(changes);
     }
 
@@ -232,7 +232,8 @@
                                     fdp->ConsumeIntegral<uint32_t>(), keyCodes, outFlags.data());
                 },
                 [&]() -> void {
-                    reader->requestRefreshConfiguration(fdp->ConsumeIntegral<uint32_t>());
+                    reader->requestRefreshConfiguration(
+                            InputReaderConfiguration::Change(fdp->ConsumeIntegral<uint32_t>()));
                 },
                 [&]() -> void {
                     reader->cancelVibrate(fdp->ConsumeIntegral<int32_t>(),
diff --git a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
index 0a6327d..616e870 100644
--- a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp
@@ -65,7 +65,8 @@
                 [&]() -> void {
                     std::list<NotifyArgs> unused =
                             mapper.reconfigure(fdp->ConsumeIntegral<nsecs_t>(), policyConfig,
-                                               fdp->ConsumeIntegral<uint32_t>());
+                                               InputReaderConfiguration::Change(
+                                                       fdp->ConsumeIntegral<uint32_t>()));
                 },
                 [&]() -> void {
                     std::list<NotifyArgs> unused = mapper.reset(fdp->ConsumeIntegral<nsecs_t>());
diff --git a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
index fdf9f41..212462d 100644
--- a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp
@@ -80,7 +80,8 @@
                 [&]() -> void {
                     std::list<NotifyArgs> unused =
                             mapper.reconfigure(fdp->ConsumeIntegral<nsecs_t>(), policyConfig,
-                                               fdp->ConsumeIntegral<uint32_t>());
+                                               InputReaderConfiguration::Change(
+                                                       fdp->ConsumeIntegral<uint32_t>()));
                 },
                 [&]() -> void {
                     std::list<NotifyArgs> unused = mapper.reset(fdp->ConsumeIntegral<nsecs_t>());
diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
index 6af352c..cfa2b03 100644
--- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.cpp
@@ -23,6 +23,7 @@
 namespace android::surfaceflinger {
 
 std::atomic<uint32_t> LayerCreationArgs::sSequence{1};
+std::atomic<uint32_t> LayerCreationArgs::sInternalSequence{1};
 
 uint32_t LayerCreationArgs::getInternalLayerId(uint32_t id) {
     return id | INTERNAL_LAYER_PREFIX;
@@ -48,13 +49,11 @@
                 metadata.getInt32(gui::METADATA_OWNER_UID, static_cast<int32_t>(ownerUid)));
     }
 
-    if (id) {
+    if (internalLayer) {
+        sequence = getInternalLayerId(sInternalSequence++);
+    } else if (id) {
         sequence = *id;
-        if (internalLayer) {
-            sequence = getInternalLayerId(*id);
-        } else {
-            sSequence = *id + 1;
-        }
+        sSequence = *id + 1;
     } else {
         sequence = sSequence++;
         if (sequence >= INTERNAL_LAYER_PREFIX) {
diff --git a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
index 3a0fc6d..c26edb5 100644
--- a/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
+++ b/services/surfaceflinger/FrontEnd/LayerCreationArgs.h
@@ -36,6 +36,7 @@
 
 struct LayerCreationArgs {
     static std::atomic<uint32_t> sSequence;
+    static std::atomic<uint32_t> sInternalSequence;
     static uint32_t getInternalLayerId(uint32_t id);
     static LayerCreationArgs fromOtherArgs(const LayerCreationArgs& other);
 
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
index 33d9dbe..6cacfb5 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.cpp
@@ -41,7 +41,7 @@
             LOG_ALWAYS_FATAL("Duplicate layer id %d found. Existing layer: %s", layer.id,
                              it->second.owner.getDebugString().c_str());
         }
-
+        mAddedLayers.push_back(newLayer.get());
         layer.parentId = linkLayer(layer.parentId, layer.id);
         layer.relativeParentId = linkLayer(layer.relativeParentId, layer.id);
         if (layer.layerStackToMirror != ui::INVALID_LAYER_STACK) {
@@ -258,23 +258,19 @@
 }
 
 void LayerLifecycleManager::commitChanges() {
-    for (auto& layer : mLayers) {
-        if (layer->changes.test(RequestedLayerState::Changes::Created)) {
-            for (auto listener : mListeners) {
-                listener->onLayerAdded(*layer);
-            }
+    for (auto layer : mAddedLayers) {
+        for (auto& listener : mListeners) {
+            listener->onLayerAdded(*layer);
         }
+    }
+    mAddedLayers.clear();
+
+    for (auto& layer : mLayers) {
         layer->clearChanges();
     }
 
     for (auto& destroyedLayer : mDestroyedLayers) {
-        if (destroyedLayer->changes.test(RequestedLayerState::Changes::Created)) {
-            for (auto listener : mListeners) {
-                listener->onLayerAdded(*destroyedLayer);
-            }
-        }
-
-        for (auto listener : mListeners) {
+        for (auto& listener : mListeners) {
             listener->onLayerDestroyed(*destroyedLayer);
         }
     }
diff --git a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
index f258678..f0d2c22 100644
--- a/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
+++ b/services/surfaceflinger/FrontEnd/LayerLifecycleManager.h
@@ -108,6 +108,9 @@
     std::vector<std::unique_ptr<RequestedLayerState>> mLayers;
     // Layers pending destruction. Layers will be destroyed once changes are committed.
     std::vector<std::unique_ptr<RequestedLayerState>> mDestroyedLayers;
+    // Keeps track of all the layers that were added in order. Changes will be cleared once
+    // committed.
+    std::vector<RequestedLayerState*> mAddedLayers;
 };
 
 } // namespace android::surfaceflinger::frontend
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
index 1e931a7..a992584 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshot.cpp
@@ -27,7 +27,6 @@
 LayerSnapshot::LayerSnapshot(const RequestedLayerState& state,
                              const LayerHierarchy::TraversalPath& path)
       : path(path) {
-    static uint32_t sUniqueSequenceId = 0;
     // Provide a unique id for all snapshots.
     // A front end layer can generate multiple snapshots if its mirrored.
     // Additionally, if the layer is not reachable, we may choose to destroy
@@ -35,7 +34,12 @@
     // change. The consumer shouldn't tie any lifetimes to this unique id but
     // register a LayerLifecycleManager::ILifecycleListener or get a list of
     // destroyed layers from LayerLifecycleManager.
-    uniqueSequence = sUniqueSequenceId++;
+    if (path.isClone()) {
+        uniqueSequence =
+                LayerCreationArgs::getInternalLayerId(LayerCreationArgs::sInternalSequence++);
+    } else {
+        uniqueSequence = state.id;
+    }
     sequence = static_cast<int32_t>(state.id);
     name = state.name;
     textureName = state.textureName;
diff --git a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
index a209cad..9cbe0bb 100644
--- a/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
+++ b/services/surfaceflinger/FrontEnd/TransactionHandler.cpp
@@ -21,6 +21,7 @@
 
 #include <cutils/trace.h>
 #include <utils/Log.h>
+#include <utils/Trace.h>
 
 #include "TransactionHandler.h"
 
@@ -73,12 +74,13 @@
 
 void TransactionHandler::applyUnsignaledBufferTransaction(
         std::vector<TransactionState>& transactions, TransactionFlushState& flushState) {
-    // only apply an unsignaled buffer transaction if it's the first one
-    if (!transactions.empty()) {
+    if (!flushState.queueWithUnsignaledBuffer) {
         return;
     }
 
-    if (!flushState.queueWithUnsignaledBuffer) {
+    // only apply an unsignaled buffer transaction if it's the first one
+    if (!transactions.empty()) {
+        ATRACE_NAME("fence unsignaled");
         return;
     }
 
diff --git a/services/surfaceflinger/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 5d92485..3472d20 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -392,7 +392,11 @@
 
     layerInfo->set_id(snapshot.uniqueSequence);
     layerInfo->set_original_id(snapshot.sequence);
-    layerInfo->set_name(requestedState.name);
+    if (!snapshot.path.isClone()) {
+        layerInfo->set_name(requestedState.name);
+    } else {
+        layerInfo->set_name(requestedState.name + "(Mirror)");
+    }
     layerInfo->set_type("Layer");
 
     LayerProtoHelper::writeToProto(requestedState.transparentRegion,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 31bf7ef..a6f4630 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4203,20 +4203,20 @@
         const TransactionHandler::TransactionFlushState& flushState) {
     using TransactionReadiness = TransactionHandler::TransactionReadiness;
     const auto& transaction = *flushState.transaction;
-    ATRACE_FORMAT("transactionIsReadyToBeApplied vsyncId: %" PRId64,
-                  transaction.frameTimelineInfo.vsyncId);
     TimePoint desiredPresentTime = TimePoint::fromNs(transaction.desiredPresentTime);
     // Do not present if the desiredPresentTime has not passed unless it is more than
     // one second in the future. We ignore timestamps more than 1 second in the future
     // for stability reasons.
     if (!transaction.isAutoTimestamp && desiredPresentTime >= mExpectedPresentTime &&
         desiredPresentTime < mExpectedPresentTime + 1s) {
-        ATRACE_NAME("not current");
+        ATRACE_FORMAT("not current desiredPresentTime: %" PRId64 " expectedPresentTime: %" PRId64,
+                      desiredPresentTime, mExpectedPresentTime);
         return TransactionReadiness::NotReady;
     }
 
     if (!mScheduler->isVsyncValid(mExpectedPresentTime, transaction.originUid)) {
-        ATRACE_NAME("!isVsyncValid");
+        ATRACE_FORMAT("!isVsyncValid expectedPresentTime: %" PRId64 " uid: %d",
+                      mExpectedPresentTime, transaction.originUid);
         return TransactionReadiness::NotReady;
     }
 
@@ -4224,7 +4224,8 @@
     // expected present time of this transaction.
     if (transaction.isAutoTimestamp &&
         frameIsEarly(mExpectedPresentTime, VsyncId{transaction.frameTimelineInfo.vsyncId})) {
-        ATRACE_NAME("frameIsEarly");
+        ATRACE_FORMAT("frameIsEarly vsyncId: %" PRId64 " expectedPresentTime: %" PRId64,
+                      transaction.frameTimelineInfo.vsyncId, mExpectedPresentTime);
         return TransactionReadiness::NotReady;
     }
     return TransactionReadiness::Ready;
@@ -4254,7 +4255,9 @@
                                                  s.bufferData->acquireFence);
                 // Delete the entire state at this point and not just release the buffer because
                 // everything associated with the Layer in this Transaction is now out of date.
-                ATRACE_NAME("DeleteStaleBuffer");
+                ATRACE_FORMAT("DeleteStaleBuffer %s barrierProducerId:%d > %d",
+                              layer->getDebugName(), layer->getDrawingState().barrierProducerId,
+                              s.bufferData->producerId);
                 return TraverseBuffersReturnValues::DELETE_AND_CONTINUE_TRAVERSAL;
             }
 
@@ -4264,7 +4267,10 @@
                         ((flushState.bufferLayersReadyToPresent.get(s.surface.get()) >=
                           s.bufferData->barrierFrameNumber));
                 if (!willApplyBarrierFrame) {
-                    ATRACE_NAME("NotReadyBarrier");
+                    ATRACE_FORMAT("NotReadyBarrier %s barrierFrameNumber:%" PRId64 " > %" PRId64,
+                                  layer->getDebugName(),
+                                  layer->getDrawingState().barrierFrameNumber,
+                                  s.bufferData->barrierFrameNumber);
                     ready = TransactionReadiness::NotReadyBarrier;
                     return TraverseBuffersReturnValues::STOP_TRAVERSAL;
                 }
@@ -4276,7 +4282,7 @@
         const bool hasPendingBuffer =
                 flushState.bufferLayersReadyToPresent.contains(s.surface.get());
         if (layer->backpressureEnabled() && hasPendingBuffer && transaction.isAutoTimestamp) {
-            ATRACE_NAME("hasPendingBuffer");
+            ATRACE_FORMAT("hasPendingBuffer %s", layer->getDebugName());
             ready = TransactionReadiness::NotReady;
             return TraverseBuffersReturnValues::STOP_TRAVERSAL;
         }
@@ -4293,9 +4299,9 @@
             const bool allowLatchUnsignaled =
                     shouldLatchUnsignaled(layer, s, transaction.states.size(),
                                           flushState.firstTransaction);
-            ATRACE_FORMAT("%s allowLatchUnsignaled=%s", layer->getName().c_str(),
-                          allowLatchUnsignaled ? "true" : "false");
             if (allowLatchUnsignaled) {
+                ATRACE_FORMAT("fence unsignaled try allowLatchUnsignaled %s",
+                              layer->getDebugName());
                 ready = TransactionReadiness::NotReadyUnsignaled;
             } else {
                 ready = TransactionReadiness::NotReady;
@@ -4308,12 +4314,12 @@
                                                        "Buffer processing hung up due to stuck "
                                                        "fence. Indicates GPU hang");
                 }
+                ATRACE_FORMAT("fence unsignaled %s", layer->getDebugName());
                 return TraverseBuffersReturnValues::STOP_TRAVERSAL;
             }
         }
         return TraverseBuffersReturnValues::CONTINUE_TRAVERSAL;
     });
-    ATRACE_INT("TransactionReadiness", static_cast<int>(ready));
     return ready;
 }
 
diff --git a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
index 88d39db..e4f49e8 100644
--- a/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHierarchyTest.cpp
@@ -466,7 +466,8 @@
 
     updateBackgroundColor(1, 0.5);
     UPDATE_AND_VERIFY(hierarchyBuilder);
-    auto bgLayerId = LayerCreationArgs::getInternalLayerId(1);
+    auto hierarchy = hierarchyBuilder.getPartialHierarchy(1, /*childrenOnly=*/true);
+    auto bgLayerId = hierarchy.mChildren.front().first->getLayer()->id;
     std::vector<uint32_t> expectedTraversalPath = {1,   bgLayerId, 11,   111, 12,
                                                    121, 122,       1221, 13,  2};
     EXPECT_EQ(getTraversalPath(hierarchyBuilder.getHierarchy()), expectedTraversalPath);
diff --git a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
index 14b8e4b..97ef5a2 100644
--- a/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerLifecycleManagerTest.cpp
@@ -36,13 +36,13 @@
 class ExpectLayerLifecycleListener : public LayerLifecycleManager::ILifecycleListener {
 public:
     void onLayerAdded(const RequestedLayerState& layer) override {
-        mActualLayersAdded.emplace(layer.id);
+        mActualLayersAdded.push_back(layer.id);
     };
     void onLayerDestroyed(const RequestedLayerState& layer) override {
         mActualLayersDestroyed.emplace(layer.id);
     };
 
-    void expectLayersAdded(const std::unordered_set<uint32_t>& expectedLayersAdded) {
+    void expectLayersAdded(const std::vector<uint32_t>& expectedLayersAdded) {
         EXPECT_EQ(expectedLayersAdded, mActualLayersAdded);
         mActualLayersAdded.clear();
     }
@@ -51,7 +51,7 @@
         mActualLayersDestroyed.clear();
     }
 
-    std::unordered_set<uint32_t> mActualLayersAdded;
+    std::vector<uint32_t> mActualLayersAdded;
     std::unordered_set<uint32_t> mActualLayersDestroyed;
 };
 
@@ -318,7 +318,8 @@
 
     EXPECT_TRUE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy));
     lifecycleManager.commitChanges();
-    auto bgLayerId = LayerCreationArgs::getInternalLayerId(1);
+    ASSERT_EQ(listener->mActualLayersAdded.size(), 2u);
+    auto bgLayerId = listener->mActualLayersAdded[1];
     listener->expectLayersAdded({1, bgLayerId});
     listener->expectLayersDestroyed({});
     EXPECT_EQ(getRequestedLayerState(lifecycleManager, bgLayerId)->color.a, 0.5_hf);
@@ -352,7 +353,8 @@
 
     EXPECT_TRUE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy));
     lifecycleManager.commitChanges();
-    auto bgLayerId = LayerCreationArgs::getInternalLayerId(1);
+    ASSERT_EQ(listener->mActualLayersAdded.size(), 2u);
+    auto bgLayerId = listener->mActualLayersAdded[1];
     listener->expectLayersAdded({1, bgLayerId});
     listener->expectLayersDestroyed({bgLayerId});
 }
@@ -381,7 +383,8 @@
 
     EXPECT_TRUE(lifecycleManager.getGlobalChanges().test(RequestedLayerState::Changes::Hierarchy));
     lifecycleManager.commitChanges();
-    auto bgLayerId = LayerCreationArgs::getInternalLayerId(1);
+    ASSERT_EQ(listener->mActualLayersAdded.size(), 2u);
+    auto bgLayerId = listener->mActualLayersAdded[1];
     listener->expectLayersAdded({1, bgLayerId});
     listener->expectLayersDestroyed({1, bgLayerId});
 }
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 922a44f..5965953 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -227,6 +227,10 @@
     android::sp<ANativeWindow> window;
     VkSwapchainKHR swapchain_handle;
     uint64_t consumer_usage;
+
+    // Indicate whether this surface has been used by a swapchain, no matter the
+    // swapchain is still current or has been destroyed.
+    bool used_by_swapchain;
 };
 
 VkSurfaceKHR HandleFromSurface(Surface* surface) {
@@ -601,6 +605,7 @@
 
     surface->window = pCreateInfo->window;
     surface->swapchain_handle = VK_NULL_HANDLE;
+    surface->used_by_swapchain = false;
     int err = native_window_get_consumer_usage(surface->window.get(),
                                                &surface->consumer_usage);
     if (err != android::OK) {
@@ -1394,14 +1399,20 @@
     // orphans the previous buffers, getting us back to the state where we can
     // dequeue all buffers.
     //
+    // This is not necessary if the surface was never used previously.
+    //
     // TODO(http://b/134186185) recycle swapchain images more efficiently
     ANativeWindow* window = surface.window.get();
-    err = native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
-    ALOGW_IF(err != android::OK, "native_window_api_disconnect failed: %s (%d)",
-             strerror(-err), err);
-    err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
-    ALOGW_IF(err != android::OK, "native_window_api_connect failed: %s (%d)",
-             strerror(-err), err);
+    if (surface.used_by_swapchain) {
+        err = native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
+        ALOGW_IF(err != android::OK,
+                 "native_window_api_disconnect failed: %s (%d)", strerror(-err),
+                 err);
+        err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+        ALOGW_IF(err != android::OK,
+                 "native_window_api_connect failed: %s (%d)", strerror(-err),
+                 err);
+    }
 
     err =
         window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, nsecs_t{-1});
@@ -1787,6 +1798,7 @@
     android::GraphicsEnv::getInstance().setTargetStats(
         android::GpuStatsInfo::Stats::CREATED_VULKAN_SWAPCHAIN);
 
+    surface.used_by_swapchain = true;
     surface.swapchain_handle = HandleFromSwapchain(swapchain);
     *swapchain_handle = surface.swapchain_handle;
     return VK_SUCCESS;