Merge "Enable backpressure for BufferStateLayer" into sc-dev
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index ccf4dc8..cc0ee82 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -34,6 +34,8 @@
     <feature name="android.hardware.microphone" />
     <!-- Feature to specify if the device is a car -->
     <feature name="android.hardware.type.automotive" />
+    <!-- Indicate support for the Android security model per the CDD. -->
+    <feature name="android.hardware.security.model.compatible" />
 
     <!-- basic system services -->
     <feature name="android.software.connectionservice" />
diff --git a/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml
index 915e579..3aa2797 100644
--- a/data/etc/go_handheld_core_hardware.xml
+++ b/data/etc/go_handheld_core_hardware.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+u<?xml version="1.0" encoding="utf-8"?>
 <!-- Copyright (C) 2018 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,6 +33,8 @@
     <feature name="android.hardware.microphone" />
     <feature name="android.hardware.screen.portrait" />
     <feature name="android.hardware.screen.landscape" />
+    <!-- Indicate support for the Android security model per the CDD. -->
+    <feature name="android.hardware.security.model.compatible" />
 
     <!-- basic system services -->
     <feature name="android.software.connectionservice" />
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 2c34047..c3c3a7f 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -37,6 +37,8 @@
     <feature name="android.hardware.microphone" />
     <feature name="android.hardware.screen.portrait" />
     <feature name="android.hardware.screen.landscape" />
+    <!-- Indicate support for the Android security model per the CDD. -->
+    <feature name="android.hardware.security.model.compatible" />
 
     <!-- basic system services -->
     <feature name="android.software.app_widgets" />
diff --git a/data/etc/pc_core_hardware.xml b/data/etc/pc_core_hardware.xml
index c62da0a..b490ba0 100644
--- a/data/etc/pc_core_hardware.xml
+++ b/data/etc/pc_core_hardware.xml
@@ -33,6 +33,8 @@
     <feature name="android.hardware.screen.landscape" />
     <feature name="android.hardware.location" />
     <feature name="android.hardware.location.network" />
+    <!-- Indicate support for the Android security model per the CDD. -->
+    <feature name="android.hardware.security.model.compatible" />
 
     <!-- basic system services -->
     <feature name="android.software.app_widgets" />
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 873b5b7..4b565fd 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -38,6 +38,8 @@
     <feature name="android.hardware.microphone" />
     <feature name="android.hardware.screen.portrait" />
     <feature name="android.hardware.screen.landscape" />
+    <!-- Indicate support for the Android security model per the CDD. -->
+    <feature name="android.hardware.security.model.compatible" />
 
     <!-- basic system services -->
     <feature name="android.software.app_widgets" />
diff --git a/data/etc/wearable_core_hardware.xml b/data/etc/wearable_core_hardware.xml
index 0f364c1..855b110 100644
--- a/data/etc/wearable_core_hardware.xml
+++ b/data/etc/wearable_core_hardware.xml
@@ -32,6 +32,8 @@
     <feature name="android.hardware.bluetooth" />
     <feature name="android.hardware.touchscreen" />
     <feature name="android.hardware.microphone" />
+    <!-- Indicate support for the Android security model per the CDD. -->
+    <feature name="android.hardware.security.model.compatible" />
 
     <!-- basic system services -->
     <feature name="android.software.home_screen" />
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 4904955..42d2895 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -261,7 +261,7 @@
         mPendingReleaseItem.item = std::move(mSubmitted.front());
         mSubmitted.pop();
 
-        processNextBufferLocked(false);
+        processNextBufferLocked(false /* useNextTransaction */);
 
         currFrameNumber = mPendingReleaseItem.item.mFrameNumber;
         if (mTransactionCompleteCallback && mTransactionCompleteFrameNumber == currFrameNumber) {
@@ -282,9 +282,10 @@
     ATRACE_CALL();
     BQA_LOGV("processNextBufferLocked useNextTransaction=%s", toString(useNextTransaction));
 
-    // Wait to acquire a buffer if there are no frames available or we have acquired the max
-    // number of buffers.
-    if (mNumFrameAvailable == 0 || maxBuffersAcquired()) {
+    // If the next transaction is set, we want to guarantee the our acquire will not fail, so don't
+    // include the extra buffer when checking if we can acquire the next buffer.
+    const bool includeExtraAcquire = !useNextTransaction;
+    if (mNumFrameAvailable == 0 || maxBuffersAcquired(includeExtraAcquire)) {
         BQA_LOGV("processNextBufferLocked waiting for frame available or callback");
         mCallbackCV.notify_all();
         return;
@@ -308,7 +309,10 @@
 
     status_t status =
             mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
-    if (status != OK) {
+    if (status == BufferQueue::NO_BUFFER_AVAILABLE) {
+        BQA_LOGV("Failed to acquire a buffer, err=NO_BUFFER_AVAILABLE");
+        return;
+    } else if (status != OK) {
         BQA_LOGE("Failed to acquire a buffer, err=%s", statusToString(status).c_str());
         return;
     }
@@ -427,7 +431,7 @@
              item.mFrameNumber, toString(nextTransactionSet), toString(mFlushShadowQueue));
 
     if (nextTransactionSet || mFlushShadowQueue) {
-        while (mNumFrameAvailable > 0 || maxBuffersAcquired()) {
+        while (mNumFrameAvailable > 0 || maxBuffersAcquired(false /* includeExtraAcquire */)) {
             BQA_LOGV("waiting in onFrameAvailable...");
             mCallbackCV.wait(_lock);
         }
@@ -435,7 +439,7 @@
     mFlushShadowQueue = false;
     // add to shadow queue
     mNumFrameAvailable++;
-    processNextBufferLocked(true);
+    processNextBufferLocked(nextTransactionSet /* useNextTransaction */);
 }
 
 void BLASTBufferQueue::onFrameReplaced(const BufferItem& item) {
@@ -495,9 +499,12 @@
 // Check if we have acquired the maximum number of buffers.
 // As a special case, we wait for the first callback before acquiring the second buffer so we
 // can ensure the first buffer is presented if multiple buffers are queued in succession.
-bool BLASTBufferQueue::maxBuffersAcquired() const {
-    return mNumAcquired == MAX_ACQUIRED_BUFFERS + 1 ||
-            (!mInitialCallbackReceived && mNumAcquired == 1);
+// Consumer can acquire an additional buffer if that buffer is not droppable. Set
+// includeExtraAcquire is true to include this buffer to the count. Since this depends on the state
+// of the buffer, the next acquire may return with NO_BUFFER_AVAILABLE.
+bool BLASTBufferQueue::maxBuffersAcquired(bool includeExtraAcquire) const {
+    int maxAcquiredBuffers = MAX_ACQUIRED_BUFFERS + (includeExtraAcquire ? 2 : 1);
+    return mNumAcquired == maxAcquiredBuffers || (!mInitialCallbackReceived && mNumAcquired == 1);
 }
 
 class BBQSurface : public Surface {
@@ -667,7 +674,8 @@
     LOG_ALWAYS_FATAL_IF(producer == nullptr,
                         "BLASTBufferQueue: failed to create BBQBufferQueueProducer");
 
-    sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
+    sp<BufferQueueConsumer> consumer(new BufferQueueConsumer(core));
+    consumer->setAllowExtraAcquire(true);
     LOG_ALWAYS_FATAL_IF(consumer == nullptr,
                         "BLASTBufferQueue: failed to create BufferQueueConsumer");
 
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index da6143c..7f7a043 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -94,7 +94,10 @@
                 ++numAcquiredBuffers;
             }
         }
-        if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) {
+        const bool acquireNonDroppableBuffer = mCore->mAllowExtraAcquire &&
+                numAcquiredBuffers == mCore->mMaxAcquiredBufferCount + 1;
+        if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1 &&
+            !acquireNonDroppableBuffer) {
             BQ_LOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)",
                     numAcquiredBuffers, mCore->mMaxAcquiredBufferCount);
             return INVALID_OPERATION;
@@ -254,6 +257,9 @@
             outBuffer->mIsStale = false;
             outBuffer->mAutoRefresh = mCore->mSharedBufferMode &&
                     mCore->mAutoRefresh;
+        } else if (acquireNonDroppableBuffer && front->mIsDroppable) {
+            BQ_LOGV("acquireBuffer: front buffer is not droppable");
+            return NO_BUFFER_AVAILABLE;
         } else {
             slot = front->mSlot;
             *outBuffer = *front;
@@ -824,4 +830,9 @@
     return NO_ERROR;
 }
 
+void BufferQueueConsumer::setAllowExtraAcquire(bool allow) {
+    std::lock_guard<std::mutex> lock(mCore->mMutex);
+    mCore->mAllowExtraAcquire = allow;
+}
+
 } // namespace android
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 411526e..7f69bc4 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -109,7 +109,7 @@
     Rect computeCrop(const BufferItem& item) REQUIRES(mMutex);
     // Return true if we need to reject the buffer based on the scaling mode and the buffer size.
     bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex);
-    bool maxBuffersAcquired() const REQUIRES(mMutex);
+    bool maxBuffersAcquired(bool includeExtraAcquire) const REQUIRES(mMutex);
 
     std::string mName;
     sp<SurfaceControl> mSurfaceControl;
diff --git a/libs/gui/include/gui/BufferQueueConsumer.h b/libs/gui/include/gui/BufferQueueConsumer.h
index 7db69ec..6aa801a 100644
--- a/libs/gui/include/gui/BufferQueueConsumer.h
+++ b/libs/gui/include/gui/BufferQueueConsumer.h
@@ -174,6 +174,10 @@
     // Value used to determine if present time is valid.
     constexpr static int MAX_REASONABLE_NSEC = 1'000'000'000ULL; // 1 second
 
+    // This allows the consumer to acquire an additional buffer if that buffer is not droppable and
+    // will eventually be released or acquired by the consumer.
+    void setAllowExtraAcquire(bool /* allow */);
+
 private:
     sp<BufferQueueCore> mCore;
 
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 557c28b..8d0828d 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -354,6 +354,9 @@
     // mTransformHintInUse is to cache the mTransformHint used by the producer.
     uint32_t mTransformHintInUse;
 
+    // This allows the consumer to acquire an additional buffer if that buffer is not droppable and
+    // will eventually be released or acquired by the consumer.
+    bool mAllowExtraAcquire = false;
 }; // class BufferQueueCore
 
 } // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 4d36f0c..3133e90 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -96,7 +96,7 @@
     MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(PhysicalDisplayId));
     MOCK_CONST_METHOD1(getDisplayVsyncPeriod, nsecs_t(PhysicalDisplayId));
     MOCK_METHOD4(setActiveModeWithConstraints,
-                 status_t(PhysicalDisplayId, DisplayModeId,
+                 status_t(PhysicalDisplayId, hal::HWConfigId,
                           const hal::VsyncPeriodChangeConstraints&,
                           hal::VsyncPeriodChangeTimeline*));
     MOCK_METHOD2(setAutoLowLatencyMode, status_t(PhysicalDisplayId, bool));
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index fe9db5a..b4a3ed1 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -51,17 +51,22 @@
 ui::Transform::RotationFlags DisplayDevice::sPrimaryDisplayRotationFlags = ui::Transform::ROT_0;
 
 DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(
-        const sp<SurfaceFlinger>& flinger, const wp<IBinder>& displayToken,
+        const sp<SurfaceFlinger>& flinger, HWComposer& hwComposer, const wp<IBinder>& displayToken,
         std::shared_ptr<compositionengine::Display> compositionDisplay)
-      : flinger(flinger), displayToken(displayToken), compositionDisplay(compositionDisplay) {}
+      : flinger(flinger),
+        hwComposer(hwComposer),
+        displayToken(displayToken),
+        compositionDisplay(compositionDisplay) {}
 
 DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args)
       : mFlinger(args.flinger),
+        mHwComposer(args.hwComposer),
         mDisplayToken(args.displayToken),
         mSequenceId(args.sequenceId),
         mConnectionType(args.connectionType),
         mCompositionDisplay{args.compositionDisplay},
         mPhysicalOrientation(args.physicalOrientation),
+        mSupportedModes(std::move(args.supportedModes)),
         mIsPrimary(args.isPrimary) {
     mCompositionDisplay->editState().isSecure = args.isSecure;
     mCompositionDisplay->createRenderSurface(
@@ -139,12 +144,39 @@
     return mPowerMode != hal::PowerMode::OFF;
 }
 
-void DisplayDevice::setActiveMode(DisplayModeId mode) {
-    mActiveMode = mode;
+void DisplayDevice::setActiveMode(DisplayModeId id) {
+    LOG_FATAL_IF(id.value() >= mSupportedModes.size(),
+                 "Cannot set active mode which is not supported.");
+    mActiveModeId = id;
 }
 
-DisplayModeId DisplayDevice::getActiveMode() const {
-    return mActiveMode;
+status_t DisplayDevice::initiateModeChange(DisplayModeId modeId,
+                                           const hal::VsyncPeriodChangeConstraints& constraints,
+                                           hal::VsyncPeriodChangeTimeline* outTimeline) const {
+    const auto mode = getMode(modeId);
+    if (!mode) {
+        ALOGE("Trying to initiate a mode change to invalid mode %s on display %s",
+              std::to_string(modeId.value()).c_str(), to_string(getId()).c_str());
+        return BAD_VALUE;
+    }
+    return mHwComposer.setActiveModeWithConstraints(getPhysicalId(), mode->getHwcId(), constraints,
+                                                    outTimeline);
+}
+
+const DisplayModePtr& DisplayDevice::getActiveMode() const {
+    return mSupportedModes[mActiveModeId.value()];
+}
+
+const DisplayModes& DisplayDevice::getSupportedModes() const {
+    return mSupportedModes;
+}
+
+DisplayModePtr DisplayDevice::getMode(DisplayModeId modeId) const {
+    const auto id = modeId.value();
+    if (id < mSupportedModes.size()) {
+        return mSupportedModes[id];
+    }
+    return nullptr;
 }
 
 ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
@@ -206,17 +238,24 @@
 
 void DisplayDevice::dump(std::string& result) const {
     StringAppendF(&result, "+ %s\n", getDebugName().c_str());
-
-    result.append("   ");
-    StringAppendF(&result, "powerMode=%s (%d), ", to_string(mPowerMode).c_str(),
+    StringAppendF(&result, "   powerMode=%s (%d)\n", to_string(mPowerMode).c_str(),
                   static_cast<int32_t>(mPowerMode));
-    StringAppendF(&result, "activeConfig=%zu, ", mActiveMode.value());
-    StringAppendF(&result, "deviceProductInfo=");
+    StringAppendF(&result, "   activeMode=%s\n", to_string(*getActiveMode()).c_str());
+
+    result.append("   supportedModes=\n");
+
+    for (const auto& mode : mSupportedModes) {
+        result.append("     ");
+        result.append(to_string(*mode));
+        result.append("\n");
+    }
+    StringAppendF(&result, "   deviceProductInfo=");
     if (mDeviceProductInfo) {
         mDeviceProductInfo->dump(result);
     } else {
         result.append("{}");
     }
+    result.append("\n");
     getCompositionDisplay()->dump(result);
 }
 
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index d29f97d..85f2f3b 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -34,6 +34,7 @@
 #include <ui/HdrCapabilities.h>
 #include <ui/Region.h>
 #include <ui/Transform.h>
+#include <utils/Errors.h>
 #include <utils/Mutex.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
@@ -157,10 +158,23 @@
     ui::Dataspace getCompositionDataSpace() const;
 
     /* ------------------------------------------------------------------------
-     * Display active config management.
+     * Display mode management.
      */
-    DisplayModeId getActiveMode() const;
-    void setActiveMode(DisplayModeId mode);
+    const DisplayModePtr& getActiveMode() const;
+    void setActiveMode(DisplayModeId);
+    status_t initiateModeChange(DisplayModeId modeId,
+                                const hal::VsyncPeriodChangeConstraints& constraints,
+                                hal::VsyncPeriodChangeTimeline* outTimeline) const;
+
+    // Return the immutable list of supported display modes. The HWC may report different modes
+    // after a hotplug reconnect event, in which case the DisplayDevice object will be recreated.
+    // Hotplug reconnects are common for external displays.
+    const DisplayModes& getSupportedModes() const;
+
+    // Returns nullptr if the given mode ID is not supported. A previously
+    // supported mode may be no longer supported for some devices like TVs and
+    // set-top boxes after a hotplug reconnect.
+    DisplayModePtr getMode(DisplayModeId) const;
 
     // release HWC resources (if any) for removable displays
     void disconnect();
@@ -174,6 +188,7 @@
 
 private:
     const sp<SurfaceFlinger> mFlinger;
+    HWComposer& mHwComposer;
     const wp<IBinder> mDisplayToken;
     const int32_t mSequenceId;
     const std::optional<DisplayConnectionType> mConnectionType;
@@ -189,7 +204,8 @@
 
     hardware::graphics::composer::hal::PowerMode mPowerMode =
             hardware::graphics::composer::hal::PowerMode::OFF;
-    DisplayModeId mActiveMode;
+    DisplayModeId mActiveModeId;
+    const DisplayModes mSupportedModes;
 
     // TODO(b/74619554): Remove special cases for primary display.
     const bool mIsPrimary;
@@ -229,9 +245,11 @@
 struct DisplayDeviceCreationArgs {
     // We use a constructor to ensure some of the values are set, without
     // assuming a default value.
-    DisplayDeviceCreationArgs(const sp<SurfaceFlinger>&, const wp<IBinder>& displayToken,
+    DisplayDeviceCreationArgs(const sp<SurfaceFlinger>&, HWComposer& hwComposer,
+                              const wp<IBinder>& displayToken,
                               std::shared_ptr<compositionengine::Display>);
     const sp<SurfaceFlinger> flinger;
+    HWComposer& hwComposer;
     const wp<IBinder> displayToken;
     const std::shared_ptr<compositionengine::Display> compositionDisplay;
 
@@ -248,6 +266,7 @@
     hardware::graphics::composer::hal::PowerMode initialPowerMode{
             hardware::graphics::composer::hal::PowerMode::ON};
     bool isPrimary{false};
+    DisplayModes supportedModes;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h
index 7ae54f1..61c1b61 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayMode.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h
@@ -17,8 +17,10 @@
 #pragma once
 
 #include "DisplayHardware/Hal.h"
+#include "Fps.h"
 #include "Scheduler/StrongTyping.h"
 
+#include <android-base/stringprintf.h>
 #include <android/configuration.h>
 #include <utils/Timers.h>
 
@@ -61,7 +63,7 @@
         }
 
         Builder& setVsyncPeriod(int32_t vsyncPeriod) {
-            mDisplayMode->mVsyncPeriod = vsyncPeriod;
+            mDisplayMode->mFps = Fps::fromPeriodNsecs(vsyncPeriod);
             return *this;
         }
 
@@ -111,7 +113,8 @@
 
     int32_t getWidth() const { return mWidth; }
     int32_t getHeight() const { return mHeight; }
-    nsecs_t getVsyncPeriod() const { return mVsyncPeriod; }
+    Fps getFps() const { return mFps; }
+    nsecs_t getVsyncPeriod() const { return mFps.getPeriodNsecs(); }
     float getDpiX() const { return mDpiX; }
     float getDpiY() const { return mDpiY; }
     int32_t getConfigGroup() const { return mConfigGroup; }
@@ -124,10 +127,18 @@
 
     int32_t mWidth = -1;
     int32_t mHeight = -1;
-    nsecs_t mVsyncPeriod = -1;
+    Fps mFps;
     float mDpiX = -1;
     float mDpiY = -1;
     int32_t mConfigGroup = -1;
 };
 
+inline std::string to_string(const DisplayMode& mode) {
+    return base::StringPrintf("{id=%zu, hwcId=%d, width=%d, height=%d, refreshRate=%s, "
+                              "dpiX=%.2f, dpiY=%.2f, configGroup=%d}",
+                              mode.getId().value(), mode.getHwcId(), mode.getWidth(),
+                              mode.getHeight(), to_string(mode.getFps()).c_str(), mode.getDpiX(),
+                              mode.getDpiY(), mode.getConfigGroup());
+}
+
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 6350144..46dc54e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -674,20 +674,14 @@
 }
 
 status_t HWComposer::setActiveModeWithConstraints(
-        PhysicalDisplayId displayId, DisplayModeId modeId,
+        PhysicalDisplayId displayId, hal::HWConfigId hwcModeId,
         const hal::VsyncPeriodChangeConstraints& constraints,
         hal::VsyncPeriodChangeTimeline* outTimeline) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
-    auto& displayData = mDisplayData[displayId];
-    if (modeId.value() >= displayData.modes.size()) {
-        LOG_DISPLAY_ERROR(displayId, ("Invalid mode " + std::to_string(modeId.value())).c_str());
-        return BAD_INDEX;
-    }
-
-    const auto hwcConfigId = displayData.modes[modeId.value()]->getHwcId();
-    auto error = displayData.hwcDisplay->setActiveConfigWithConstraints(hwcConfigId, constraints,
-                                                                        outTimeline);
+    auto error = mDisplayData[displayId].hwcDisplay->setActiveConfigWithConstraints(hwcModeId,
+                                                                                    constraints,
+                                                                                    outTimeline);
     RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
     return NO_ERROR;
 }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 59c3699..1ffe276 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -198,7 +198,7 @@
     virtual DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const = 0;
     virtual bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const = 0;
     virtual nsecs_t getDisplayVsyncPeriod(PhysicalDisplayId) const = 0;
-    virtual status_t setActiveModeWithConstraints(PhysicalDisplayId, DisplayModeId,
+    virtual status_t setActiveModeWithConstraints(PhysicalDisplayId, hal::HWConfigId,
                                                   const hal::VsyncPeriodChangeConstraints&,
                                                   hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
     virtual status_t setAutoLowLatencyMode(PhysicalDisplayId, bool on) = 0;
@@ -329,7 +329,7 @@
     DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override;
     bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const override;
     nsecs_t getDisplayVsyncPeriod(PhysicalDisplayId displayId) const override;
-    status_t setActiveModeWithConstraints(PhysicalDisplayId, DisplayModeId,
+    status_t setActiveModeWithConstraints(PhysicalDisplayId, hal::HWConfigId,
                                           const hal::VsyncPeriodChangeConstraints&,
                                           hal::VsyncPeriodChangeTimeline* outTimeline) override;
     status_t setAutoLowLatencyMode(PhysicalDisplayId, bool) override;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index bf0c2d6..4225e92 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -900,16 +900,14 @@
 
     Mutex::Autolock lock(mStateLock);
 
-    const auto displayId = getPhysicalDisplayIdLocked(displayToken);
-    if (!displayId) {
+    const auto display = getDisplayDeviceLocked(displayToken);
+    if (!display) {
         return NAME_NOT_FOUND;
     }
 
-    const bool isInternal = (displayId == getInternalDisplayIdLocked());
-
     configs->clear();
 
-    for (const auto& mode : getHwComposer().getModes(*displayId)) {
+    for (const auto& mode : display->getSupportedModes()) {
         DisplayConfig config;
 
         auto width = mode->getWidth();
@@ -918,7 +916,7 @@
         auto xDpi = mode->getDpiX();
         auto yDpi = mode->getDpiY();
 
-        if (isInternal &&
+        if (display->isPrimary() &&
             (internalDisplayOrientation == ui::ROTATION_90 ||
              internalDisplayOrientation == ui::ROTATION_270)) {
             std::swap(width, height);
@@ -981,7 +979,7 @@
         Mutex::Autolock lock(mStateLock);
 
         if (const auto display = getDisplayDeviceLocked(displayToken)) {
-            activeConfig = display->getActiveMode().value();
+            activeConfig = display->getActiveMode()->getId().value();
             isPrimary = display->isPrimary();
         } else {
             ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
@@ -1011,9 +1009,9 @@
         mDesiredActiveConfig = info;
         mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig;
     } else {
-        // Check is we are already at the desired config
+        // Check if we are already at the desired config
         const auto display = getDefaultDisplayDeviceLocked();
-        if (!display || display->getActiveMode() == refreshRate.getConfigId()) {
+        if (!display || display->getActiveMode()->getId() == refreshRate.getConfigId()) {
             return;
         }
 
@@ -1030,7 +1028,7 @@
         // VsyncController model is locked.
         modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated);
 
-        updatePhaseConfiguration(refreshRate);
+        updatePhaseConfiguration(refreshRate.getFps());
         mScheduler->setConfigChangePending(true);
     }
 
@@ -1039,7 +1037,7 @@
     }
 }
 
-status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
+status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int modeId) {
     ATRACE_CALL();
 
     if (!displayToken) {
@@ -1052,22 +1050,29 @@
             ALOGE("Attempt to set allowed display configs for invalid display token %p",
                   displayToken.get());
             return NAME_NOT_FOUND;
-        } else if (display->isVirtual()) {
+        }
+
+        if (display->isVirtual()) {
             ALOGW("Attempt to set allowed display configs for virtual display");
             return INVALID_OPERATION;
-        } else {
-            const DisplayModeId config(mode);
-            const auto fps = mRefreshRateConfigs->getRefreshRateFromConfigId(config).getFps();
-            // Keep the old switching type.
-            const auto allowGroupSwitching =
-                    mRefreshRateConfigs->getCurrentPolicy().allowGroupSwitching;
-            const scheduler::RefreshRateConfigs::Policy policy{config,
-                                                               allowGroupSwitching,
-                                                               {fps, fps}};
-            constexpr bool kOverridePolicy = false;
-
-            return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
         }
+
+        const auto mode = display->getMode(DisplayModeId{modeId});
+        if (!mode) {
+            ALOGW("Attempt to switch to an unsupported mode %d.", modeId);
+            return BAD_VALUE;
+        }
+
+        const auto fps = mode->getFps();
+        // Keep the old switching type.
+        const auto allowGroupSwitching =
+                mRefreshRateConfigs->getCurrentPolicy().allowGroupSwitching;
+        const scheduler::RefreshRateConfigs::Policy policy{mode->getId(),
+                                                           allowGroupSwitching,
+                                                           {fps, fps}};
+        constexpr bool kOverridePolicy = false;
+
+        return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
     });
 
     return future.get();
@@ -1081,48 +1086,58 @@
         return;
     }
 
-    auto oldRefreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(display->getActiveMode());
+    const auto upcomingConfig = display->getMode(mUpcomingActiveConfig.configId);
+    if (!upcomingConfig) {
+        ALOGW("Upcoming active config is no longer supported. ConfigId = %zu",
+              mUpcomingActiveConfig.configId.value());
+        // TODO(b/159590486) Handle the error better. Some parts of SurfaceFlinger may
+        // have been already updated with the upcoming active config.
+        return;
+    }
+    const Fps oldRefreshRate = display->getActiveMode()->getFps();
 
     std::lock_guard<std::mutex> lock(mActiveConfigLock);
     mRefreshRateConfigs->setCurrentConfigId(mUpcomingActiveConfig.configId);
     display->setActiveMode(mUpcomingActiveConfig.configId);
 
-    auto refreshRate =
-            mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId);
-    mRefreshRateStats->setRefreshRate(refreshRate.getFps());
+    const Fps refreshRate = upcomingConfig->getFps();
 
-    if (refreshRate.getVsyncPeriod() != oldRefreshRate.getVsyncPeriod()) {
+    mRefreshRateStats->setRefreshRate(refreshRate);
+
+    if (!refreshRate.equalsWithMargin(oldRefreshRate)) {
         mTimeStats->incrementRefreshRateSwitches();
     }
     updatePhaseConfiguration(refreshRate);
-    ATRACE_INT("ActiveConfigFPS", refreshRate.getFps().getValue());
+    ATRACE_INT("ActiveConfigFPS", refreshRate.getValue());
 
     if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
-        const nsecs_t vsyncPeriod =
-                mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId)
-                        .getVsyncPeriod();
+        const nsecs_t vsyncPeriod = refreshRate.getPeriodNsecs();
         const auto physicalId = display->getPhysicalId();
         mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, physicalId,
                                                   mUpcomingActiveConfig.configId, vsyncPeriod);
     }
 }
 
-void SurfaceFlinger::desiredActiveConfigChangeDone() {
+void SurfaceFlinger::clearDesiredActiveConfigState() {
     std::lock_guard<std::mutex> lock(mActiveConfigLock);
     mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
     mDesiredActiveConfigChanged = false;
-
-    const auto& refreshRate =
-            mRefreshRateConfigs->getRefreshRateFromConfigId(mDesiredActiveConfig.configId);
-
-    mScheduler->resyncToHardwareVsync(true, refreshRate.getVsyncPeriod());
-    updatePhaseConfiguration(refreshRate);
     mScheduler->setConfigChangePending(false);
 }
 
+void SurfaceFlinger::desiredActiveConfigChangeDone() {
+    const auto modeId = getDesiredActiveConfig()->configId;
+
+    clearDesiredActiveConfigState();
+
+    const auto& refreshRate = getDefaultDisplayDeviceLocked()->getMode(modeId)->getFps();
+    mScheduler->resyncToHardwareVsync(true, refreshRate.getPeriodNsecs());
+    updatePhaseConfiguration(refreshRate);
+}
+
 void SurfaceFlinger::performSetActiveConfig() {
     ATRACE_CALL();
-    ALOGV("performSetActiveConfig");
+    ALOGV("%s", __FUNCTION__);
     // Store the local variable to release the lock.
     const auto desiredActiveConfig = getDesiredActiveConfig();
     if (!desiredActiveConfig) {
@@ -1130,12 +1145,19 @@
         return;
     }
 
-    auto refreshRate =
-            mRefreshRateConfigs->getRefreshRateFromConfigId(desiredActiveConfig->configId);
-    ALOGV("performSetActiveConfig changing active config to %zu(%s)",
-          refreshRate.getConfigId().value(), refreshRate.getName().c_str());
     const auto display = getDefaultDisplayDeviceLocked();
-    if (!display || display->getActiveMode() == desiredActiveConfig->configId) {
+    const auto desiredConfig = display->getMode(desiredActiveConfig->configId);
+    if (!desiredConfig) {
+        ALOGW("Desired display config is no longer supported. Config ID = %zu",
+              desiredActiveConfig->configId.value());
+        clearDesiredActiveConfigState();
+        return;
+    }
+    const auto refreshRate = desiredConfig->getFps();
+    ALOGV("performSetActiveConfig changing active config to %zu(%s)",
+          desiredConfig->getId().value(), to_string(refreshRate).c_str());
+
+    if (!display || display->getActiveMode()->getId() == desiredActiveConfig->configId) {
         // display is not valid or we are already in the requested mode
         // on both cases there is nothing left to do
         desiredActiveConfigChangeDone();
@@ -1143,7 +1165,7 @@
     }
 
     // Desired active config was set, it is different than the config currently in use, however
-    // allowed configs might have change by the time we process the refresh.
+    // allowed configs might have changed by the time we process the refresh.
     // Make sure the desired config is still allowed
     if (!isDisplayConfigAllowed(desiredActiveConfig->configId)) {
         desiredActiveConfigChangeDone();
@@ -1151,9 +1173,8 @@
     }
 
     mUpcomingActiveConfig = *desiredActiveConfig;
-    const auto displayId = display->getPhysicalId();
 
-    ATRACE_INT("ActiveConfigFPS_HWC", refreshRate.getFps().getValue());
+    ATRACE_INT("ActiveConfigFPS_HWC", refreshRate.getValue());
 
     // TODO(b/142753666) use constrains
     hal::VsyncPeriodChangeConstraints constraints;
@@ -1161,13 +1182,12 @@
     constraints.seamlessRequired = false;
 
     hal::VsyncPeriodChangeTimeline outTimeline;
-    auto status =
-            getHwComposer().setActiveModeWithConstraints(displayId, mUpcomingActiveConfig.configId,
-                                                         constraints, &outTimeline);
+    const auto status =
+            display->initiateModeChange(mUpcomingActiveConfig.configId, constraints, &outTimeline);
     if (status != NO_ERROR) {
-        // setActiveModeWithConstraints may fail if a hotplug event is just about
+        // initiateModeChange may fail if a hotplug event is just about
         // to be sent. We just log the error in this case.
-        ALOGW("setActiveModeWithConstraints failed: %d", status);
+        ALOGW("initiateModeChange failed: %d", status);
         return;
     }
 
@@ -2409,8 +2429,9 @@
         const DisplayDeviceState& state,
         const sp<compositionengine::DisplaySurface>& displaySurface,
         const sp<IGraphicBufferProducer>& producer) {
-    DisplayDeviceCreationArgs creationArgs(this, displayToken, compositionDisplay);
+    DisplayDeviceCreationArgs creationArgs(this, getHwComposer(), displayToken, compositionDisplay);
     creationArgs.sequenceId = state.sequenceId;
+    creationArgs.hwComposer = getHwComposer();
     creationArgs.isSecure = state.isSecure;
     creationArgs.displaySurface = displaySurface;
     creationArgs.hasWideColorGamut = false;
@@ -2422,6 +2443,7 @@
 
     if (const auto id = PhysicalDisplayId::tryCast(compositionDisplay->getId())) {
         creationArgs.isPrimary = id == getInternalDisplayIdLocked();
+        creationArgs.supportedModes = getHwComposer().getModes(*id);
 
         if (useColorManagement) {
             std::vector<ColorMode> modes = getHwComposer().getColorModes(*id);
@@ -2629,7 +2651,7 @@
                 // TODO(b/175678215) Handle the case when currentConfig is not in configs
                 mRefreshRateConfigs->updateDisplayConfigs(configs, currentConfig);
                 mVsyncConfiguration->reset();
-                updatePhaseConfiguration(mRefreshRateConfigs->getCurrentRefreshRate());
+                updatePhaseConfiguration(mRefreshRateConfigs->getCurrentRefreshRate().getFps());
                 if (mRefreshRateOverlay) {
                     mRefreshRateOverlay->reset();
                 }
@@ -2970,10 +2992,10 @@
             getHwComposer().hasCapability(hal::Capability::PRESENT_FENCE_IS_NOT_RELIABLE));
 }
 
-void SurfaceFlinger::updatePhaseConfiguration(const RefreshRate& refreshRate) {
-    mVsyncConfiguration->setRefreshRateFps(refreshRate.getFps());
+void SurfaceFlinger::updatePhaseConfiguration(const Fps& refreshRate) {
+    mVsyncConfiguration->setRefreshRateFps(refreshRate);
     setVsyncConfig(mVsyncModulator->setVsyncConfigSet(mVsyncConfiguration->getCurrentConfigs()),
-                   refreshRate.getVsyncPeriod());
+                   refreshRate.getPeriodNsecs());
 }
 
 void SurfaceFlinger::setVsyncConfig(const VsyncModulator::VsyncConfig& config,
@@ -5337,22 +5359,22 @@
                 return NO_ERROR;
             }
             case 1035: {
-                const int newConfigId = data.readInt32();
+                const int modeId = data.readInt32();
                 mDebugDisplayConfigSetByBackdoor = false;
+
                 const auto displayId = getInternalDisplayId();
                 if (!displayId) {
                     ALOGE("No internal display found.");
                     return NO_ERROR;
                 }
-                const auto numConfigs = getHwComposer().getModes(*displayId).size();
-                if (newConfigId >= 0 && newConfigId < numConfigs) {
-                    const auto displayToken = getInternalDisplayToken();
-                    status_t result = setActiveConfig(displayToken, newConfigId);
-                    if (result != NO_ERROR) {
-                        return result;
-                    }
-                    mDebugDisplayConfigSetByBackdoor = true;
+
+                status_t result = setActiveConfig(getPhysicalDisplayToken(*displayId), modeId);
+                if (result != NO_ERROR) {
+                    return result;
                 }
+
+                mDebugDisplayConfigSetByBackdoor = true;
+
                 return NO_ERROR;
             }
             case 1036: {
@@ -6034,7 +6056,7 @@
 
     if (!display->isPrimary()) {
         // TODO(b/144711714): For non-primary displays we should be able to set an active config
-        // as well. For now, just call directly to setActiveModeWithConstraints but ideally
+        // as well. For now, just call directly to initiateModeChange but ideally
         // it should go thru setDesiredActiveConfig, similar to primary display.
         ALOGV("setAllowedDisplayConfigsInternal for non-primary display");
         const auto displayId = display->getPhysicalId();
@@ -6044,8 +6066,8 @@
         constraints.seamlessRequired = false;
 
         hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
-        if (getHwComposer().setActiveModeWithConstraints(displayId, policy->defaultConfig,
-                                                         constraints, &timeline) < 0) {
+        if (display->initiateModeChange(policy->defaultConfig, constraints, &timeline) !=
+            NO_ERROR) {
             return BAD_VALUE;
         }
         if (timeline.refreshRequired) {
@@ -6053,9 +6075,7 @@
         }
 
         display->setActiveMode(policy->defaultConfig);
-        const nsecs_t vsyncPeriod = getHwComposer()
-                                            .getModes(displayId)[policy->defaultConfig.value()]
-                                            ->getVsyncPeriod();
+        const nsecs_t vsyncPeriod = display->getMode(policy->defaultConfig)->getVsyncPeriod();
         mScheduler->onNonPrimaryDisplayConfigChanged(mAppConnectionHandle, displayId,
                                                      policy->defaultConfig, vsyncPeriod);
         return NO_ERROR;
@@ -6081,12 +6101,11 @@
 
     // TODO(b/140204874): Leave the event in until we do proper testing with all apps that might
     // be depending in this callback.
-    const nsecs_t vsyncPeriod =
-            mRefreshRateConfigs->getRefreshRateFromConfigId(display->getActiveMode())
-                    .getVsyncPeriod();
+    const auto activeConfig = display->getActiveMode();
+    const nsecs_t vsyncPeriod = activeConfig->getVsyncPeriod();
     const auto physicalId = display->getPhysicalId();
     mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, physicalId,
-                                              display->getActiveMode(), vsyncPeriod);
+                                              activeConfig->getId(), vsyncPeriod);
     toggleKernelIdleTimer();
 
     auto configId = mScheduler->getPreferredConfigId();
@@ -6174,8 +6193,7 @@
     } else if (display->isVirtual()) {
         return INVALID_OPERATION;
     } else {
-        const auto displayId = display->getPhysicalId();
-        const auto activeMode = getHwComposer().getActiveMode(displayId);
+        const auto activeMode = display->getActiveMode();
         *outDefaultConfig = activeMode->getId().value();
         *outAllowGroupSwitching = false;
         auto vsyncPeriod = activeMode->getVsyncPeriod();
@@ -6395,10 +6413,8 @@
 
             if (const auto display = getDefaultDisplayDeviceLocked()) {
                 mRefreshRateOverlay->setViewport(display->getSize());
+                mRefreshRateOverlay->changeRefreshRate(display->getActiveMode()->getFps());
             }
-
-            mRefreshRateOverlay->changeRefreshRate(
-                    mRefreshRateConfigs->getCurrentRefreshRate().getFps());
         }
     }));
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 194131d..1deef6e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -54,6 +54,7 @@
 #include "DisplayHardware/PowerAdvisor.h"
 #include "DisplayIdGenerator.h"
 #include "Effects/Daltonizer.h"
+#include "Fps.h"
 #include "FrameTracker.h"
 #include "LayerVector.h"
 #include "Scheduler/RefreshRateConfigs.h"
@@ -667,7 +668,7 @@
     void signalLayerUpdate();
     void signalRefresh();
 
-    // called on the main thread in response to initializeDisplays()
+    // Called on the main thread in response to initializeDisplays()
     void onInitializeDisplays() REQUIRES(mStateLock);
     // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
     void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock);
@@ -678,9 +679,10 @@
     // Calls to setActiveConfig on the main thread if there is a pending config
     // that needs to be applied.
     void performSetActiveConfig() REQUIRES(mStateLock);
+    void clearDesiredActiveConfigState() REQUIRES(mStateLock) EXCLUDES(mActiveConfigLock);
     // Called when active config is no longer is progress
     void desiredActiveConfigChangeDone() REQUIRES(mStateLock);
-    // called on the main thread in response to setPowerMode()
+    // Called on the main thread in response to setPowerMode()
     void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
             REQUIRES(mStateLock);
 
@@ -712,8 +714,8 @@
     void commitInputWindowCommands() REQUIRES(mStateLock);
     void updateCursorAsync();
 
-    void initScheduler(PhysicalDisplayId primaryDisplayId);
-    void updatePhaseConfiguration(const RefreshRate&);
+    void initScheduler(PhysicalDisplayId primaryDisplayId) REQUIRES(mStateLock);
+    void updatePhaseConfiguration(const Fps&) REQUIRES(mStateLock);
     void setVsyncConfig(const VsyncModulator::VsyncConfig&, nsecs_t vsyncPeriod);
 
     /* handlePageFlip - latch a new buffer if available and compute the dirty
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 8fac8e9..df40ef6 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -315,8 +315,9 @@
 
     static const size_t MAX_NUM_LAYER_RECORDS = 200;
     static const size_t MAX_NUM_LAYER_STATS = 200;
+    static const size_t MAX_NUM_PULLED_LAYERS = MAX_NUM_LAYER_STATS;
     std::unique_ptr<StatsEventDelegate> mStatsDelegate = std::make_unique<StatsEventDelegate>();
-    size_t mMaxPulledLayers = 8;
+    size_t mMaxPulledLayers = MAX_NUM_PULLED_LAYERS;
     size_t mMaxPulledHistogramBuckets = 6;
 };
 
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 71986fe..1e24c0a 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -35,6 +35,7 @@
 
 #include "DisplayHardware/DisplayMode.h"
 #include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/Hal.h"
 #include "mock/DisplayHardware/MockComposer.h"
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
@@ -230,7 +231,7 @@
     constraints.seamlessRequired = false;
 
     hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
-    constexpr DisplayModeId kConfigIndex(0);
+    constexpr Config kConfigIndex = 0;
     const auto status =
             hwc.setActiveModeWithConstraints(physicalId, kConfigIndex, constraints, &timeline);
     EXPECT_EQ(NO_ERROR, status);
@@ -243,8 +244,10 @@
     hwc.allocatePhysicalDisplay(hwcId, physicalId);
 
     for (size_t configIndex = 0; configIndex < kConfigs.size(); configIndex++) {
-        const auto status = hwc.setActiveModeWithConstraints(physicalId, DisplayModeId(configIndex),
-                                                             constraints, &timeline);
+        const auto status =
+                hwc.setActiveModeWithConstraints(physicalId,
+                                                 static_cast<hal::HWConfigId>(configIndex),
+                                                 constraints, &timeline);
         EXPECT_EQ(NO_ERROR, status) << "Error when switching to config " << configIndex;
     }
 }
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index ca7c755..9a95ab4 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -262,12 +262,14 @@
     EXPECT_EQ(Case::HdrSupport::HDR10_SUPPORTED, device->hasHDR10Support());
     EXPECT_EQ(Case::HdrSupport::HDR_HLG_SUPPORTED, device->hasHLGSupport());
     EXPECT_EQ(Case::HdrSupport::HDR_DOLBY_VISION_SUPPORTED, device->hasDolbyVisionSupport());
-    // Note: This is not Case::Display::HWC_ACTIVE_CONFIG_ID as the ids are
-    // remapped, and the test only ever sets up one config. If there were an error
-    // looking up the remapped index, device->getActiveMode() would be -1 instead.
-    EXPECT_EQ(0, device->getActiveMode().value());
     EXPECT_EQ(Case::PerFrameMetadataSupport::PER_FRAME_METADATA_KEYS,
               device->getSupportedPerFrameMetadata());
+
+    if constexpr (Case::Display::CONNECTION_TYPE::value) {
+        EXPECT_EQ(1, device->getSupportedModes().size());
+        EXPECT_NE(nullptr, device->getActiveMode());
+        EXPECT_EQ(Case::Display::HWC_ACTIVE_CONFIG_ID, device->getActiveMode()->getHwcId());
+    }
 }
 
 TEST_F(SetupNewDisplayDeviceInternalTest, createSimplePrimaryDisplay) {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 9a9eeab..fc284ff 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -598,7 +598,8 @@
                                   std::optional<DisplayConnectionType> connectionType,
                                   std::optional<hal::HWDisplayId> hwcDisplayId, bool isPrimary)
               : mFlinger(flinger),
-                mCreationArgs(flinger.mFlinger.get(), mDisplayToken, compositionDisplay),
+                mCreationArgs(flinger.mFlinger.get(), flinger.mFlinger->getHwComposer(),
+                              mDisplayToken, compositionDisplay),
                 mHwcDisplayId(hwcDisplayId) {
             mCreationArgs.connectionType = connectionType;
             mCreationArgs.isPrimary = isPrimary;