Merge "Convert touchpad gestures into pointer moves & clicks"
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index dc928b8..867a089 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -125,14 +125,21 @@
     bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars,
             Vector<KeyEvent>& outEvents) const;
 
+    /* Maps an Android key code to another Android key code. This mapping is applied after scanCode
+     * and usageCodes are mapped to corresponding Android Keycode */
+    void addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode);
+
     /* Maps a scan code and usage code to a key code, in case this key map overrides
      * the mapping in some way. */
     status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const;
 
-    /* Tries to find a replacement key code for a given key code and meta state
-     * in character map. */
-    void tryRemapKey(int32_t scanCode, int32_t metaState,
-            int32_t* outKeyCode, int32_t* outMetaState) const;
+    /* Returns keycode after applying Android key code remapping defined in mKeyRemapping */
+    int32_t applyKeyRemapping(int32_t fromKeyCode) const;
+
+    /* Returns the <keyCode, metaState> pair after applying key behavior defined in the kcm file,
+     * that tries to find a replacement key code based on current meta state */
+    std::pair<int32_t /*keyCode*/, int32_t /*metaState*/> applyKeyBehavior(int32_t keyCode,
+                                                                           int32_t metaState) const;
 
 #ifdef __linux__
     /* Reads a key map from a parcel. */
@@ -227,8 +234,9 @@
     std::string mLoadFileName;
     bool mLayoutOverlayApplied;
 
-    KeyedVector<int32_t, int32_t> mKeysByScanCode;
-    KeyedVector<int32_t, int32_t> mKeysByUsageCode;
+    std::map<int32_t /* fromAndroidKeyCode */, int32_t /* toAndroidKeyCode */> mKeyRemapping;
+    std::map<int32_t /* fromScanCode */, int32_t /* toAndroidKeyCode */> mKeysByScanCode;
+    std::map<int32_t /* fromHidUsageCode */, int32_t /* toAndroidKeyCode */> mKeysByUsageCode;
 
     KeyCharacterMap(const std::string& filename);
 
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 65b77c6..d261c21 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -141,11 +141,13 @@
             void                restoreCallingIdentity(int64_t token);
             bool hasExplicitIdentity();
 
+            // For main functions - dangerous for libraries to use
             status_t            setupPolling(int* fd);
             status_t            handlePolledCommands();
             void                flushCommands();
             bool                flushIfNeeded();
 
+            // For main functions - dangerous for libraries to use
             void                joinThreadPool(bool isMain = true);
             
             // Stop the local process.
diff --git a/libs/binder/include/binder/ProcessState.h b/libs/binder/include/binder/ProcessState.h
index 9679a5f..87eee3d 100644
--- a/libs/binder/include/binder/ProcessState.h
+++ b/libs/binder/include/binder/ProcessState.h
@@ -50,6 +50,7 @@
 
     sp<IBinder> getContextObject(const sp<IBinder>& caller);
 
+    // For main functions - dangerous for libraries to use
     void startThreadPool();
 
     bool becomeContextManager();
@@ -57,8 +58,10 @@
     sp<IBinder> getStrongProxyForHandle(int32_t handle);
     void expungeHandle(int32_t handle, IBinder* binder);
 
+    // TODO: deprecate.
     void spawnPooledThread(bool isMain);
 
+    // For main functions - dangerous for libraries to use
     status_t setThreadPoolMaxThreadCount(size_t maxThreads);
     status_t enableOnewaySpamDetection(bool enable);
     void giveThreadPoolName();
diff --git a/libs/binder/ndk/include_platform/android/binder_process.h b/libs/binder/ndk/include_platform/android/binder_process.h
index f408fad..8923129 100644
--- a/libs/binder/ndk/include_platform/android/binder_process.h
+++ b/libs/binder/ndk/include_platform/android/binder_process.h
@@ -28,17 +28,26 @@
  *
  * When using this, it is expected that ABinderProcess_setupPolling and
  * ABinderProcess_handlePolledCommands are not used.
+ *
+ * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
+ * function should be responsible for configuring the threadpool for the entire application.
  */
 void ABinderProcess_startThreadPool();
 /**
  * This sets the maximum number of threads that can be started in the threadpool. By default, after
  * startThreadPool is called, this is 15. If it is called additional times, it will only prevent
  * the kernel from starting new threads and will not delete already existing threads.
+ *
+ * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
+ * function should be responsible for configuring the threadpool for the entire application.
  */
 bool ABinderProcess_setThreadPoolMaxThreadCount(uint32_t numThreads);
 /**
  * This adds the current thread to the threadpool. This may cause the threadpool to exceed the
  * maximum size.
+ *
+ * Do not use this from a library. Apps setup their own threadpools, and otherwise, the main
+ * function should be responsible for configuring the threadpool for the entire application.
  */
 void ABinderProcess_joinThreadPool();
 
diff --git a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
index edc695f..f0beed2 100644
--- a/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/tests/parcel_fuzzer/random_parcel.cpp
@@ -73,6 +73,11 @@
                                                                                 1));
                         CHECK(OK == p->writeFileDescriptor(fd.get(), false /*takeOwnership*/));
                     } else {
+                        // b/260119717 - Adding more FDs can eventually lead to FD limit exhaustion
+                        if (options->extraFds.size() > 1000) {
+                            return;
+                        }
+
                         std::vector<base::unique_fd> fds = getRandomFds(&provider);
                         CHECK(OK ==
                               p->writeFileDescriptor(fds.begin()->release(),
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 422e6e0..fa5c41f 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -43,7 +43,6 @@
 // Enables debug output for mapping.
 #define DEBUG_MAPPING 0
 
-
 namespace android {
 
 static const char* WHITESPACE = " \t\r";
@@ -93,6 +92,7 @@
       : mType(other.mType),
         mLoadFileName(other.mLoadFileName),
         mLayoutOverlayApplied(other.mLayoutOverlayApplied),
+        mKeyRemapping(other.mKeyRemapping),
         mKeysByScanCode(other.mKeysByScanCode),
         mKeysByUsageCode(other.mKeysByUsageCode) {
     for (size_t i = 0; i < other.mKeys.size(); i++) {
@@ -114,7 +114,7 @@
     if (mLayoutOverlayApplied != other.mLayoutOverlayApplied) {
         return false;
     }
-    if (mKeys.size() != other.mKeys.size() ||
+    if (mKeys.size() != other.mKeys.size() || mKeyRemapping.size() != other.mKeyRemapping.size() ||
         mKeysByScanCode.size() != other.mKeysByScanCode.size() ||
         mKeysByUsageCode.size() != other.mKeysByUsageCode.size()) {
         return false;
@@ -131,22 +131,9 @@
         }
     }
 
-    for (size_t i = 0; i < mKeysByScanCode.size(); i++) {
-        if (mKeysByScanCode.keyAt(i) != other.mKeysByScanCode.keyAt(i)) {
-            return false;
-        }
-        if (mKeysByScanCode.valueAt(i) != other.mKeysByScanCode.valueAt(i)) {
-            return false;
-        }
-    }
-
-    for (size_t i = 0; i < mKeysByUsageCode.size(); i++) {
-        if (mKeysByUsageCode.keyAt(i) != other.mKeysByUsageCode.keyAt(i)) {
-            return false;
-        }
-        if (mKeysByUsageCode.valueAt(i) != other.mKeysByUsageCode.valueAt(i)) {
-            return false;
-        }
+    if (mKeyRemapping != other.mKeyRemapping || mKeysByScanCode != other.mKeysByScanCode ||
+        mKeysByUsageCode != other.mKeysByUsageCode) {
+        return false;
     }
 
     return true;
@@ -258,14 +245,12 @@
         }
     }
 
-    for (size_t i = 0; i < overlay.mKeysByScanCode.size(); i++) {
-        mKeysByScanCode.replaceValueFor(overlay.mKeysByScanCode.keyAt(i),
-                                        overlay.mKeysByScanCode.valueAt(i));
+    for (auto const& it : overlay.mKeysByScanCode) {
+        mKeysByScanCode.insert_or_assign(it.first, it.second);
     }
 
-    for (size_t i = 0; i < overlay.mKeysByUsageCode.size(); i++) {
-        mKeysByUsageCode.replaceValueFor(overlay.mKeysByUsageCode.keyAt(i),
-                                         overlay.mKeysByUsageCode.valueAt(i));
+    for (auto const& it : overlay.mKeysByUsageCode) {
+        mKeysByUsageCode.insert_or_assign(it.first, it.second);
     }
     mLayoutOverlayApplied = true;
 }
@@ -400,11 +385,26 @@
     return true;
 }
 
+void KeyCharacterMap::addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode) {
+    if (fromKeyCode == toKeyCode) {
+        mKeyRemapping.erase(fromKeyCode);
+#if DEBUG_MAPPING
+        ALOGD("addKeyRemapping: Cleared remapping forKeyCode=%d ~ Result Successful.", fromKeyCode);
+#endif
+        return;
+    }
+    mKeyRemapping.insert_or_assign(fromKeyCode, toKeyCode);
+#if DEBUG_MAPPING
+    ALOGD("addKeyRemapping: fromKeyCode=%d, toKeyCode=%d ~ Result Successful.", fromKeyCode,
+          toKeyCode);
+#endif
+}
+
 status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const {
     if (usageCode) {
-        ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
-        if (index >= 0) {
-            *outKeyCode = mKeysByUsageCode.valueAt(index);
+        const auto it = mKeysByUsageCode.find(usageCode);
+        if (it != mKeysByUsageCode.end()) {
+            *outKeyCode = it->second;
 #if DEBUG_MAPPING
             ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
                     scanCode, usageCode, *outKeyCode);
@@ -413,9 +413,9 @@
         }
     }
     if (scanCode) {
-        ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
-        if (index >= 0) {
-            *outKeyCode = mKeysByScanCode.valueAt(index);
+        const auto it = mKeysByScanCode.find(scanCode);
+        if (it != mKeysByScanCode.end()) {
+            *outKeyCode = it->second;
 #if DEBUG_MAPPING
             ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
                     scanCode, usageCode, *outKeyCode);
@@ -431,45 +431,59 @@
     return NAME_NOT_FOUND;
 }
 
-void KeyCharacterMap::tryRemapKey(int32_t keyCode, int32_t metaState,
-                                  int32_t *outKeyCode, int32_t *outMetaState) const {
-    *outKeyCode = keyCode;
-    *outMetaState = metaState;
+int32_t KeyCharacterMap::applyKeyRemapping(int32_t fromKeyCode) const {
+    int32_t toKeyCode = fromKeyCode;
 
-    const Behavior* behavior = getKeyBehavior(keyCode, metaState);
+    const auto it = mKeyRemapping.find(fromKeyCode);
+    if (it != mKeyRemapping.end()) {
+        toKeyCode = it->second;
+    }
+#if DEBUG_MAPPING
+    ALOGD("applyKeyRemapping: keyCode=%d ~ replacement keyCode=%d.", fromKeyCode, toKeyCode);
+#endif
+    return toKeyCode;
+}
+
+std::pair<int32_t, int32_t> KeyCharacterMap::applyKeyBehavior(int32_t fromKeyCode,
+                                                              int32_t fromMetaState) const {
+    int32_t toKeyCode = fromKeyCode;
+    int32_t toMetaState = fromMetaState;
+
+    const Behavior* behavior = getKeyBehavior(fromKeyCode, fromMetaState);
     if (behavior != nullptr) {
         if (behavior->replacementKeyCode) {
-            *outKeyCode = behavior->replacementKeyCode;
-            int32_t newMetaState = metaState & ~behavior->metaState;
+            toKeyCode = behavior->replacementKeyCode;
+            toMetaState = fromMetaState & ~behavior->metaState;
             // Reset dependent meta states.
             if (behavior->metaState & AMETA_ALT_ON) {
-                newMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
+                toMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
             }
             if (behavior->metaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
-                newMetaState &= ~AMETA_ALT_ON;
+                toMetaState &= ~AMETA_ALT_ON;
             }
             if (behavior->metaState & AMETA_CTRL_ON) {
-                newMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
+                toMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
             }
             if (behavior->metaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
-                newMetaState &= ~AMETA_CTRL_ON;
+                toMetaState &= ~AMETA_CTRL_ON;
             }
             if (behavior->metaState & AMETA_SHIFT_ON) {
-                newMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON);
+                toMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON);
             }
             if (behavior->metaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
-                newMetaState &= ~AMETA_SHIFT_ON;
+                toMetaState &= ~AMETA_SHIFT_ON;
             }
             // ... and put universal bits back if needed
-            *outMetaState = normalizeMetaState(newMetaState);
+            toMetaState = normalizeMetaState(toMetaState);
         }
     }
 
 #if DEBUG_MAPPING
-    ALOGD("tryRemapKey: keyCode=%d, metaState=0x%08x ~ "
-            "replacement keyCode=%d, replacement metaState=0x%08x.",
-            keyCode, metaState, *outKeyCode, *outMetaState);
+    ALOGD("applyKeyBehavior: keyCode=%d, metaState=0x%08x ~ "
+          "replacement keyCode=%d, replacement metaState=0x%08x.",
+          fromKeyCode, fromMetaState, toKeyCode, toMetaState);
 #endif
+    return std::make_pair(toKeyCode, toMetaState);
 }
 
 bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
@@ -720,6 +734,18 @@
             return nullptr;
         }
     }
+    size_t numKeyRemapping = parcel->readInt32();
+    if (parcel->errorCheck()) {
+        return nullptr;
+    }
+    for (size_t i = 0; i < numKeyRemapping; i++) {
+        int32_t key = parcel->readInt32();
+        int32_t value = parcel->readInt32();
+        map->mKeyRemapping.insert_or_assign(key, value);
+        if (parcel->errorCheck()) {
+            return nullptr;
+        }
+    }
     size_t numKeysByScanCode = parcel->readInt32();
     if (parcel->errorCheck()) {
         return nullptr;
@@ -727,7 +753,7 @@
     for (size_t i = 0; i < numKeysByScanCode; i++) {
         int32_t key = parcel->readInt32();
         int32_t value = parcel->readInt32();
-        map->mKeysByScanCode.add(key, value);
+        map->mKeysByScanCode.insert_or_assign(key, value);
         if (parcel->errorCheck()) {
             return nullptr;
         }
@@ -739,7 +765,7 @@
     for (size_t i = 0; i < numKeysByUsageCode; i++) {
         int32_t key = parcel->readInt32();
         int32_t value = parcel->readInt32();
-        map->mKeysByUsageCode.add(key, value);
+        map->mKeysByUsageCode.insert_or_assign(key, value);
         if (parcel->errorCheck()) {
             return nullptr;
         }
@@ -773,17 +799,23 @@
         }
         parcel->writeInt32(0);
     }
+    size_t numKeyRemapping = mKeyRemapping.size();
+    parcel->writeInt32(numKeyRemapping);
+    for (auto const& [fromAndroidKeyCode, toAndroidKeyCode] : mKeyRemapping) {
+        parcel->writeInt32(fromAndroidKeyCode);
+        parcel->writeInt32(toAndroidKeyCode);
+    }
     size_t numKeysByScanCode = mKeysByScanCode.size();
     parcel->writeInt32(numKeysByScanCode);
-    for (size_t i = 0; i < numKeysByScanCode; i++) {
-        parcel->writeInt32(mKeysByScanCode.keyAt(i));
-        parcel->writeInt32(mKeysByScanCode.valueAt(i));
+    for (auto const& [fromScanCode, toAndroidKeyCode] : mKeysByScanCode) {
+        parcel->writeInt32(fromScanCode);
+        parcel->writeInt32(toAndroidKeyCode);
     }
     size_t numKeysByUsageCode = mKeysByUsageCode.size();
     parcel->writeInt32(numKeysByUsageCode);
-    for (size_t i = 0; i < numKeysByUsageCode; i++) {
-        parcel->writeInt32(mKeysByUsageCode.keyAt(i));
-        parcel->writeInt32(mKeysByUsageCode.valueAt(i));
+    for (auto const& [fromUsageCode, toAndroidKeyCode] : mKeysByUsageCode) {
+        parcel->writeInt32(fromUsageCode);
+        parcel->writeInt32(toAndroidKeyCode);
     }
 }
 #endif // __linux__
@@ -950,9 +982,9 @@
                 mapUsage ? "usage" : "scan code", codeToken.string());
         return BAD_VALUE;
     }
-    KeyedVector<int32_t, int32_t>& map =
-            mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
-    if (map.indexOfKey(code) >= 0) {
+    std::map<int32_t, int32_t>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;
+    const auto it = map.find(code);
+    if (it != map.end()) {
         ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(),
                 mapUsage ? "usage" : "scan code", codeToken.string());
         return BAD_VALUE;
@@ -971,7 +1003,7 @@
     ALOGD("Parsed map key %s: code=%d, keyCode=%d.",
             mapUsage ? "usage" : "scan code", code, keyCode);
 #endif
-    map.add(code, keyCode);
+    map.insert_or_assign(code, keyCode);
     return NO_ERROR;
 }
 
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index c345385..b7b2926 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -232,15 +232,6 @@
     return native_window_set_frame_rate(window, frameRate, compatibility, changeFrameRateStrategy);
 }
 
-int32_t ANativeWindow_clearFrameRate(ANativeWindow* window) {
-    if (!window || !query(window, NATIVE_WINDOW_IS_VALID)) {
-        return -EINVAL;
-    }
-    return native_window_set_frame_rate(window, 0,
-            ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
-            ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
-}
-
 /**************************************************************************************************
  * vndk-stable
  **************************************************************************************************/
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index a27e3dd..be6623e 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -372,8 +372,12 @@
  *
  * \return 0 for success, -EINVAL if the window value is invalid.
  */
-int32_t ANativeWindow_clearFrameRate(ANativeWindow* window)
-        __INTRODUCED_IN(__ANDROID_API_U__);
+inline int32_t ANativeWindow_clearFrameRate(ANativeWindow* window)
+        __INTRODUCED_IN(__ANDROID_API_U__) {
+    return ANativeWindow_setFrameRateWithChangeStrategy(window, 0,
+            ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT,
+            ANATIVEWINDOW_CHANGE_FRAME_RATE_ONLY_IF_SEAMLESS);
+}
 
 #ifdef __cplusplus
 }
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index e1ee490..c2fd6ef 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -51,7 +51,6 @@
     ANativeWindow_setDequeueTimeout; # systemapi # introduced=30
     ANativeWindow_setFrameRate; # introduced=30
     ANativeWindow_setFrameRateWithChangeStrategy; # introduced=31
-    ANativeWindow_clearFrameRate; # introduced=UpsideDownCake
     ANativeWindow_setSharedBufferMode; # llndk
     ANativeWindow_setSwapInterval; # llndk
     ANativeWindow_setUsage; # llndk
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index b885435..973986f 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -70,7 +70,7 @@
     name: "libinputflinger_defaults",
     srcs: [":libinputflinger_sources"],
     shared_libs: [
-        "android.hardware.input.processor-V1-ndk",
+        "android.hardware.input.processor-V2-ndk",
         "libbase",
         "libbinder",
         "libbinder_ndk",
diff --git a/services/inputflinger/InputCommonConverter.cpp b/services/inputflinger/InputCommonConverter.cpp
index 628ce6f..b292c09 100644
--- a/services/inputflinger/InputCommonConverter.cpp
+++ b/services/inputflinger/InputCommonConverter.cpp
@@ -263,7 +263,10 @@
 static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_14) == common::Axis::GENERIC_14);
 static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_15) == common::Axis::GENERIC_15);
 static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GENERIC_16) == common::Axis::GENERIC_16);
-// TODO(hcutts): add GESTURE_X_OFFSET and GESTURE_Y_OFFSET.
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GESTURE_X_OFFSET) ==
+              common::Axis::GESTURE_X_OFFSET);
+static_assert(static_cast<common::Axis>(AMOTION_EVENT_AXIS_GESTURE_Y_OFFSET) ==
+              common::Axis::GESTURE_Y_OFFSET);
 // If you added a new axis, consider whether this should also be exposed as a HAL axis. Update the
 // static_assert below and add the new axis here, or leave a comment summarizing your decision.
 static_assert(static_cast<common::Axis>(AMOTION_EVENT_MAXIMUM_VALID_AXIS_VALUE) ==
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 6d6cefb..b8a6dad 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -88,6 +88,9 @@
     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 */
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index f2ea90c..e26bc8c 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -952,15 +952,19 @@
             device->getKeyCharacterMap()->mapKey(scanCodes[0], 0 /*usageCode*/, &outKeyCode);
     switch (mapKeyRes) {
         case OK:
-            return outKeyCode;
+            break;
         case NAME_NOT_FOUND:
             // key character map doesn't re-map this scanCode, hence the keyCode remains the same
-            return locationKeyCode;
+            outKeyCode = locationKeyCode;
+            break;
         default:
             ALOGW("Failed to get key code for key location: Key character map returned error %s",
                   statusToString(mapKeyRes).c_str());
-            return AKEYCODE_UNKNOWN;
+            outKeyCode = AKEYCODE_UNKNOWN;
+            break;
     }
+    // Remap if there is a Key remapping added to the KCM and return the remapped key
+    return device->getKeyCharacterMap()->applyKeyRemapping(outKeyCode);
 }
 
 int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const {
@@ -1023,6 +1027,18 @@
     return false;
 }
 
+void EventHub::addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const {
+    std::scoped_lock _l(mLock);
+    Device* device = getDeviceLocked(deviceId);
+    if (device == nullptr) {
+        return;
+    }
+    const std::shared_ptr<KeyCharacterMap> kcm = device->getKeyCharacterMap();
+    if (kcm) {
+        kcm->addKeyRemapping(fromKeyCode, toKeyCode);
+    }
+}
+
 status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
                           int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
     std::scoped_lock _l(mLock);
@@ -1048,7 +1064,13 @@
 
         if (status == NO_ERROR) {
             if (kcm) {
-                kcm->tryRemapKey(*outKeycode, metaState, outKeycode, outMetaState);
+                // Remap keys based on user-defined key remappings and key behavior defined in the
+                // corresponding kcm file
+                *outKeycode = kcm->applyKeyRemapping(*outKeycode);
+
+                // Remap keys based on Key behavior defined in KCM file
+                std::tie(*outKeycode, *outMetaState) =
+                        kcm->applyKeyBehavior(*outKeycode, metaState);
             } else {
                 *outMetaState = metaState;
             }
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 8d5377f..f9d72e0 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -631,6 +631,12 @@
     });
 }
 
+void InputDevice::addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode) {
+    for_each_subdevice([fromKeyCode, toKeyCode](auto& context) {
+        context.addKeyRemapping(fromKeyCode, toKeyCode);
+    });
+}
+
 void InputDevice::bumpGeneration() {
     mGeneration = mContext->bumpGeneration();
 }
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index f04a646..57f679c 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -650,6 +650,15 @@
     return result;
 }
 
+void InputReader::addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const {
+    std::scoped_lock _l(mLock);
+
+    InputDevice* device = findInputDeviceLocked(deviceId);
+    if (device != nullptr) {
+        device->addKeyRemapping(fromKeyCode, toKeyCode);
+    }
+}
+
 int32_t InputReader::getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const {
     std::scoped_lock _l(mLock);
 
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 42ca482..8a844b2 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -262,6 +262,9 @@
 
     virtual bool hasMscEvent(int32_t deviceId, int mscEvent) const = 0;
 
+    virtual void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode,
+                                 int32_t toKeyCode) const = 0;
+
     virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
                             int32_t metaState, int32_t* outKeycode, int32_t* outMetaState,
                             uint32_t* outFlags) const = 0;
@@ -460,6 +463,9 @@
 
     bool hasMscEvent(int32_t deviceId, int mscEvent) const override final;
 
+    void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode,
+                         int32_t toKeyCode) const override final;
+
     status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
                     int32_t* outKeycode, int32_t* outMetaState,
                     uint32_t* outFlags) const override final;
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 439123b..6fa21e5 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -114,6 +114,8 @@
     int32_t getMetaState();
     void updateMetaState(int32_t keyCode);
 
+    void addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode);
+
     void bumpGeneration();
 
     [[nodiscard]] NotifyDeviceResetArgs notifyReset(nsecs_t when);
@@ -278,6 +280,10 @@
 
     inline bool hasMscEvent(int mscEvent) const { return mEventHub->hasMscEvent(mId, mscEvent); }
 
+    inline void addKeyRemapping(int32_t fromKeyCode, int32_t toKeyCode) const {
+        mEventHub->addKeyRemapping(mId, fromKeyCode, toKeyCode);
+    }
+
     inline status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t metaState,
                            int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
         return mEventHub->mapKey(mId, scanCode, usageCode, metaState, outKeycode, outMetaState,
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 4f2503a..e9c989a 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -68,6 +68,8 @@
     int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) override;
     int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw) override;
 
+    void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const override;
+
     int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const override;
 
     void toggleCapsLockState(int32_t deviceId) override;
diff --git a/services/inputflinger/tests/FakeEventHub.cpp b/services/inputflinger/tests/FakeEventHub.cpp
index f6cf1cc..289a780 100644
--- a/services/inputflinger/tests/FakeEventHub.cpp
+++ b/services/inputflinger/tests/FakeEventHub.cpp
@@ -154,6 +154,11 @@
     getDevice(deviceId)->keyCodeMapping.insert_or_assign(fromKeyCode, toKeyCode);
 }
 
+void FakeEventHub::addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const {
+    Device* device = getDevice(deviceId);
+    device->keyRemapping.insert_or_assign(fromKeyCode, toKeyCode);
+}
+
 void FakeEventHub::addLed(int32_t deviceId, int32_t led, bool initialState) {
     getDevice(deviceId)->leds.add(led, initialState);
 }
@@ -299,7 +304,8 @@
         const KeyInfo* key = getKey(device, scanCode, usageCode);
         if (key) {
             if (outKeycode) {
-                *outKeycode = key->keyCode;
+                auto it = device->keyRemapping.find(key->keyCode);
+                *outKeycode = it != device->keyRemapping.end() ? it->second : key->keyCode;
             }
             if (outFlags) {
                 *outFlags = key->flags;
diff --git a/services/inputflinger/tests/FakeEventHub.h b/services/inputflinger/tests/FakeEventHub.h
index 21cb2f1..fb3c859 100644
--- a/services/inputflinger/tests/FakeEventHub.h
+++ b/services/inputflinger/tests/FakeEventHub.h
@@ -59,6 +59,7 @@
         KeyedVector<int32_t, int32_t> absoluteAxisValue;
         KeyedVector<int32_t, KeyInfo> keysByScanCode;
         KeyedVector<int32_t, KeyInfo> keysByUsageCode;
+        std::unordered_map<int32_t, int32_t> keyRemapping;
         KeyedVector<int32_t, bool> leds;
         // fake mapping which would normally come from keyCharacterMap
         std::unordered_map<int32_t, int32_t> keyCodeMapping;
@@ -132,6 +133,7 @@
     void addKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t keyCode,
                 uint32_t flags);
     void addKeyCodeMapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode);
+    void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const;
     void addVirtualKeyDefinition(int32_t deviceId, const VirtualKeyDefinition& definition);
 
     void addSensorAxis(int32_t deviceId, int32_t absCode, InputDeviceSensorType sensorType,
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index eef5690..4cc48f6 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -2912,6 +2912,27 @@
     ASSERT_EQ(ARBITRARY_TIME, args.downTime);
 }
 
+TEST_F(KeyboardInputMapperTest, Process_KeyRemapping) {
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_A, 0, AKEYCODE_A, 0);
+    mFakeEventHub->addKey(EVENTHUB_ID, KEY_B, 0, AKEYCODE_B, 0);
+    mFakeEventHub->addKeyRemapping(EVENTHUB_ID, AKEYCODE_A, AKEYCODE_B);
+
+    KeyboardInputMapper& mapper =
+            addMapperAndConfigure<KeyboardInputMapper>(AINPUT_SOURCE_KEYBOARD,
+                                                       AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+
+    // Key down by scan code.
+    process(mapper, ARBITRARY_TIME, READ_TIME, EV_KEY, KEY_A, 1);
+    NotifyKeyArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(AKEYCODE_B, args.keyCode);
+
+    // Key up by scan code.
+    process(mapper, ARBITRARY_TIME + 1, READ_TIME, EV_KEY, KEY_A, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(AKEYCODE_B, args.keyCode);
+}
+
 /**
  * Ensure that the readTime is set to the time when the EV_KEY is received.
  */
diff --git a/services/inputflinger/tests/fuzzers/Android.bp b/services/inputflinger/tests/fuzzers/Android.bp
index 55c2db6..4359a4b 100644
--- a/services/inputflinger/tests/fuzzers/Android.bp
+++ b/services/inputflinger/tests/fuzzers/Android.bp
@@ -55,7 +55,7 @@
     ],
     shared_libs: [
         "android.hardware.input.classifier@1.0",
-        "android.hardware.input.processor-V1-ndk",
+        "android.hardware.input.processor-V2-ndk",
         "libbase",
         "libbinder",
         "libcutils",
diff --git a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
index 2eed997..057c15d 100644
--- a/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
+++ b/services/inputflinger/tests/fuzzers/InputReaderFuzzer.cpp
@@ -153,6 +153,10 @@
         return reader->getLightPlayerId(deviceId, lightId);
     }
 
+    void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const {
+        reader->addKeyRemapping(deviceId, fromKeyCode, toKeyCode);
+    }
+
     int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const {
         return reader->getKeyCodeForKeyLocation(deviceId, locationKeyCode);
     }
diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h
index 445ed18..cd852d6 100644
--- a/services/inputflinger/tests/fuzzers/MapperHelpers.h
+++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h
@@ -211,6 +211,7 @@
     int32_t getSwitchState(int32_t deviceId, int32_t sw) const override {
         return mFdp->ConsumeIntegral<int32_t>();
     }
+    void addKeyRemapping(int32_t deviceId, int32_t fromKeyCode, int32_t toKeyCode) const override {}
     int32_t getKeyCodeForKeyLocation(int32_t deviceId, int32_t locationKeyCode) const override {
         return mFdp->ConsumeIntegral<int32_t>();
     }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cc4e082..36ff3ec 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4731,18 +4731,18 @@
                                            .value_or(false);
 
     const auto activeDisplay = getDisplayDeviceLocked(mActiveDisplayId);
-    if (isInternalDisplay && activeDisplay != display && activeDisplay &&
-        activeDisplay->isPoweredOn()) {
-        ALOGW("Trying to change power mode on non active display while the active display is ON");
-    }
+    const bool isActiveDisplayPoweredOn = activeDisplay && activeDisplay->isPoweredOn();
+
+    ALOGW_IF(display != activeDisplay && isInternalDisplay && isActiveDisplayPoweredOn,
+             "Trying to change power mode on inactive display without powering off active display");
 
     display->setPowerMode(mode);
 
     const auto refreshRate = display->refreshRateSelector().getActiveMode().modePtr->getFps();
     if (!currentModeOpt || *currentModeOpt == hal::PowerMode::OFF) {
         // Turn on the display
-        if (isInternalDisplay && (!activeDisplay || !activeDisplay->isPoweredOn())) {
-            onActiveDisplayChangedLocked(display);
+        if (isInternalDisplay && !isActiveDisplayPoweredOn) {
+            onActiveDisplayChangedLocked(activeDisplay, display);
         }
         // Keep uclamp in a separate syscall and set it before changing to RT due to b/190237315.
         // We can merge the syscall later.
@@ -7042,17 +7042,14 @@
     getRenderEngine().onActiveDisplaySizeChanged(activeDisplay->getSize());
 }
 
-void SurfaceFlinger::onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) {
+void SurfaceFlinger::onActiveDisplayChangedLocked(const sp<DisplayDevice>& inactiveDisplay,
+                                                  const sp<DisplayDevice>& activeDisplay) {
     ATRACE_CALL();
 
-    if (const auto display = getDisplayDeviceLocked(mActiveDisplayId)) {
-        display->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(false);
+    if (inactiveDisplay) {
+        inactiveDisplay->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(false);
     }
 
-    if (!activeDisplay) {
-        ALOGE("%s: activeDisplay is null", __func__);
-        return;
-    }
     mActiveDisplayId = activeDisplay->getPhysicalId();
     activeDisplay->getCompositionDisplay()->setLayerCachingTexturePoolEnabled(true);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b9903a7..6ddcfbc 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1002,7 +1002,10 @@
     VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat) REQUIRES(mStateLock);
     void releaseVirtualDisplay(VirtualDisplayId);
 
-    void onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay)
+    // TODO(b/255635821): Replace pointers with references. `inactiveDisplay` is only ever `nullptr`
+    // in tests, and `activeDisplay` must not be `nullptr` as a precondition.
+    void onActiveDisplayChangedLocked(const sp<DisplayDevice>& inactiveDisplay,
+                                      const sp<DisplayDevice>& activeDisplay)
             REQUIRES(mStateLock, kMainThreadContext);
 
     void onActiveDisplaySizeChanged(const sp<const DisplayDevice>&);
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 19c7d5c..d58e644 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -359,6 +359,7 @@
     }
 
     // Called by tests to inject a HWC display setup
+    template <bool kInitPowerMode = true>
     static void injectHwcDisplayWithNoDefaultCapabilities(DisplayTransactionTest* test) {
         const auto displayId = DisplayVariant::DISPLAY_ID::get();
         ASSERT_FALSE(GpuVirtualDisplayId::tryCast(displayId));
@@ -367,18 +368,21 @@
                 .setHwcDisplayId(HWC_DISPLAY_ID)
                 .setResolution(DisplayVariant::RESOLUTION)
                 .setActiveConfig(HWC_ACTIVE_CONFIG_ID)
-                .setPowerMode(INIT_POWER_MODE)
+                .setPowerMode(kInitPowerMode ? std::make_optional(INIT_POWER_MODE) : std::nullopt)
                 .inject(&test->mFlinger, test->mComposer);
     }
 
     // Called by tests to inject a HWC display setup
+    template <bool kInitPowerMode = true>
     static void injectHwcDisplay(DisplayTransactionTest* test) {
         EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY_ID, _))
                 .WillOnce(DoAll(SetArgPointee<1>(std::vector<DisplayCapability>({})),
                                 Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer, setPowerMode(HWC_DISPLAY_ID, INIT_POWER_MODE))
-                .WillOnce(Return(Error::NONE));
-        injectHwcDisplayWithNoDefaultCapabilities(test);
+        if constexpr (kInitPowerMode) {
+            EXPECT_CALL(*test->mComposer, setPowerMode(HWC_DISPLAY_ID, INIT_POWER_MODE))
+                    .WillOnce(Return(Error::NONE));
+        }
+        injectHwcDisplayWithNoDefaultCapabilities<kInitPowerMode>(test);
     }
 
     static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
index bc66961..622717f 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_PowerHintTest.cpp
@@ -97,7 +97,6 @@
                     .setNativeWindow(mNativeWindow)
                     .setPowerMode(hal::PowerMode::ON)
                     .inject();
-    mFlinger.mutableActiveDisplayId() = mDisplay->getPhysicalId();
 }
 
 void SurfaceFlingerPowerHintTest::setupScheduler() {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
index 25857ec..0fb8e2b 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -259,12 +259,6 @@
         auto injector = Display::makeFakeExistingDisplayInjector(test);
         const auto display = injector.inject();
         display->setPowerMode(mode);
-        if (injector.physicalDisplay()
-                    .transform(&display::PhysicalDisplay::isInternal)
-                    .value_or(false)) {
-            test->mFlinger.mutableActiveDisplayId() = display->getPhysicalId();
-        }
-
         return display;
     }
 
@@ -490,5 +484,37 @@
     transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToUnknownVariant>>();
 }
 
+TEST_F(SetPowerModeInternalTest, designatesLeaderDisplay) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // Inject a primary display with uninitialized power mode.
+    constexpr bool kInitPowerMode = false;
+    Case::Display::injectHwcDisplay<kInitPowerMode>(this);
+    auto injector = Case::Display::makeFakeExistingDisplayInjector(this);
+    injector.setPowerMode(std::nullopt);
+    const auto display = injector.inject();
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    // FakeDisplayDeviceInjector registers the display with Scheduler, so it has already been
+    // designated as the leader. Set an arbitrary leader to verify that `setPowerModeInternal`
+    // designates a leader regardless of any preceding `Scheduler::registerDisplay` call(s).
+    constexpr PhysicalDisplayId kPlaceholderId = PhysicalDisplayId::fromPort(42);
+    ASSERT_NE(display->getPhysicalId(), kPlaceholderId);
+    mFlinger.scheduler()->setLeaderDisplay(kPlaceholderId);
+
+    mFlinger.setPowerModeInternal(display, PowerMode::ON);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The primary display should be designated as the leader.
+    EXPECT_EQ(mFlinger.scheduler()->leaderDisplayId(), display->getPhysicalId());
+}
+
 } // namespace
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 54c10c5..b8a6063 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -87,6 +87,10 @@
         Scheduler::unregisterDisplay(displayId);
     }
 
+    std::optional<PhysicalDisplayId> leaderDisplayId() const NO_THREAD_SAFETY_ANALYSIS {
+        return mLeaderDisplayId;
+    }
+
     void setLeaderDisplay(PhysicalDisplayId displayId) {
         ftl::FakeGuard guard(kMainThreadContext);
         Scheduler::setLeaderDisplay(displayId);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index c8362ee..7d0b340 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -471,7 +471,7 @@
     void onActiveDisplayChanged(const sp<DisplayDevice>& activeDisplay) {
         Mutex::Autolock lock(mFlinger->mStateLock);
         ftl::FakeGuard guard(kMainThreadContext);
-        mFlinger->onActiveDisplayChangedLocked(activeDisplay);
+        mFlinger->onActiveDisplayChangedLocked(nullptr, activeDisplay);
     }
 
     auto createLayer(LayerCreationArgs& args, const sp<IBinder>& parentHandle,
@@ -627,7 +627,7 @@
             return *this;
         }
 
-        auto& setPowerMode(hal::PowerMode mode) {
+        auto& setPowerMode(std::optional<hal::PowerMode> mode) {
             mPowerMode = mode;
             return *this;
         }
@@ -650,7 +650,11 @@
             auto display = std::make_unique<HWC2Display>(*composer, *mCapabilities, mHwcDisplayId,
                                                          mHwcDisplayType);
             display->mutableIsConnected() = true;
-            display->setPowerMode(mPowerMode);
+
+            if (mPowerMode) {
+                display->setPowerMode(*mPowerMode);
+            }
+
             flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = std::move(display);
 
             EXPECT_CALL(*composer, getDisplayConfigs(mHwcDisplayId, _))
@@ -715,7 +719,7 @@
         int32_t mDpiY = DEFAULT_DPI;
         int32_t mConfigGroup = DEFAULT_CONFIG_GROUP;
         hal::HWConfigId mActiveConfig = DEFAULT_ACTIVE_CONFIG;
-        hal::PowerMode mPowerMode = DEFAULT_POWER_MODE;
+        std::optional<hal::PowerMode> mPowerMode = DEFAULT_POWER_MODE;
         const std::unordered_set<aidl::android::hardware::graphics::composer3::Capability>*
                 mCapabilities = nullptr;
     };
@@ -792,7 +796,7 @@
             return *this;
         }
 
-        auto& setPowerMode(hal::PowerMode mode) {
+        auto& setPowerMode(std::optional<hal::PowerMode> mode) {
             mCreationArgs.initialPowerMode = mode;
             return *this;
         }
@@ -857,6 +861,10 @@
                 LOG_ALWAYS_FATAL_IF(!physicalIdOpt);
                 const auto physicalId = *physicalIdOpt;
 
+                if (mCreationArgs.isPrimary) {
+                    mFlinger.mutableActiveDisplayId() = physicalId;
+                }
+
                 LOG_ALWAYS_FATAL_IF(!mHwcDisplayId);
 
                 const auto activeMode = modes.get(activeModeId);
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index df70bf4..a9706bc 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -682,6 +682,7 @@
         "vkGetPhysicalDeviceMemoryProperties2",
         "vkGetPhysicalDeviceMemoryProperties2KHR",
         "vkGetPhysicalDeviceMultisamplePropertiesEXT",
+        "vkGetPhysicalDeviceOpticalFlowImageFormatsNV",
         "vkGetPhysicalDevicePresentRectanglesKHR",
         "vkGetPhysicalDeviceProperties",
         "vkGetPhysicalDeviceProperties2",