Merge "SF: Update the cached display modes in HWComposer on hotplug"
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 5fa72b8..6f3987f 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -74,6 +74,7 @@
 
 namespace hal = android::hardware::graphics::composer::hal;
 
+namespace android {
 namespace {
 
 using android::hardware::Return;
@@ -88,47 +89,46 @@
             mSequenceId(sequenceId),
             mVsyncSwitchingSupported(vsyncSwitchingSupported) {}
 
-    android::hardware::Return<void> onHotplug(hal::HWDisplayId display,
-                                              hal::Connection conn) override {
+    Return<void> onHotplug(hal::HWDisplayId display, hal::Connection conn) override {
         mCallback->onHotplugReceived(mSequenceId, display, conn);
-        return android::hardware::Void();
+        return Void();
     }
 
-    android::hardware::Return<void> onRefresh(hal::HWDisplayId display) override {
+    Return<void> onRefresh(hal::HWDisplayId display) override {
         mCallback->onRefreshReceived(mSequenceId, display);
-        return android::hardware::Void();
+        return Void();
     }
 
-    android::hardware::Return<void> onVsync(hal::HWDisplayId display, int64_t timestamp) override {
+    Return<void> onVsync(hal::HWDisplayId display, int64_t timestamp) override {
         if (!mVsyncSwitchingSupported) {
             mCallback->onVsyncReceived(mSequenceId, display, timestamp, std::nullopt);
         } else {
             ALOGW("Unexpected onVsync callback on composer >= 2.4, ignoring.");
         }
-        return android::hardware::Void();
+        return Void();
     }
 
-    android::hardware::Return<void> onVsync_2_4(hal::HWDisplayId display, int64_t timestamp,
-                                                hal::VsyncPeriodNanos vsyncPeriodNanos) override {
+    Return<void> onVsync_2_4(hal::HWDisplayId display, int64_t timestamp,
+                             hal::VsyncPeriodNanos vsyncPeriodNanos) override {
         if (mVsyncSwitchingSupported) {
             mCallback->onVsyncReceived(mSequenceId, display, timestamp,
                                        std::make_optional(vsyncPeriodNanos));
         } else {
             ALOGW("Unexpected onVsync_2_4 callback on composer <= 2.3, ignoring.");
         }
-        return android::hardware::Void();
+        return Void();
     }
 
-    android::hardware::Return<void> onVsyncPeriodTimingChanged(
+    Return<void> onVsyncPeriodTimingChanged(
             hal::HWDisplayId display,
             const hal::VsyncPeriodChangeTimeline& updatedTimeline) override {
         mCallback->onVsyncPeriodTimingChangedReceived(mSequenceId, display, updatedTimeline);
-        return android::hardware::Void();
+        return Void();
     }
 
-    android::hardware::Return<void> onSeamlessPossible(hal::HWDisplayId display) override {
+    Return<void> onSeamlessPossible(hal::HWDisplayId display) override {
         mCallback->onSeamlessPossible(mSequenceId, display);
-        return android::hardware::Void();
+        return Void();
     }
 
 private:
@@ -139,8 +139,6 @@
 
 } // namespace
 
-namespace android {
-
 HWComposer::~HWComposer() = default;
 
 namespace impl {
@@ -295,6 +293,7 @@
                                                   hal::DisplayType::PHYSICAL);
     newDisplay->setConnected(true);
     displayData.hwcDisplay = std::move(newDisplay);
+    displayData.configs = displayData.hwcDisplay->getConfigs();
     mPhysicalDisplayIdMap[hwcDisplayId] = displayId;
 }
 
@@ -335,14 +334,9 @@
         PhysicalDisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, {});
 
-    const auto& displayData = mDisplayData.at(displayId);
-    auto configs = displayData.hwcDisplay->getConfigs();
-    if (displayData.configMap.empty()) {
-        for (size_t i = 0; i < configs.size(); ++i) {
-            displayData.configMap[i] = configs[i];
-        }
-    }
-    return configs;
+    // We cache the configs when the DisplayData is created on hotplug. If the configs need to
+    // change HWC will send a hotplug event which will recreate displayData.
+    return mDisplayData.at(displayId).configs;
 }
 
 std::shared_ptr<const HWC2::Display::Config> HWComposer::getActiveConfig(
@@ -653,13 +647,13 @@
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     auto& displayData = mDisplayData[displayId];
-    if (displayData.configMap.count(configId) == 0) {
+    if (configId >= displayData.configs.size()) {
         LOG_DISPLAY_ERROR(displayId, ("Invalid config " + std::to_string(configId)).c_str());
         return BAD_INDEX;
     }
 
     auto error =
-            displayData.hwcDisplay->setActiveConfigWithConstraints(displayData.configMap[configId],
+            displayData.hwcDisplay->setActiveConfigWithConstraints(displayData.configs[configId],
                                                                    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 50c9853..7e1da252 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -184,7 +184,6 @@
     virtual nsecs_t getRefreshTimestamp(PhysicalDisplayId) const = 0;
     virtual bool isConnected(PhysicalDisplayId) const = 0;
 
-    // Non-const because it can update configMap inside of mDisplayData
     virtual std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(
             PhysicalDisplayId) const = 0;
 
@@ -320,7 +319,6 @@
     nsecs_t getRefreshTimestamp(PhysicalDisplayId) const override;
     bool isConnected(PhysicalDisplayId) const override;
 
-    // Non-const because it can update configMap inside of mDisplayData
     std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(
             PhysicalDisplayId) const override;
 
@@ -379,8 +377,7 @@
         std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
         buffer_handle_t outbufHandle = nullptr;
         sp<Fence> outbufAcquireFence = Fence::NO_FENCE;
-        mutable std::unordered_map<int32_t,
-                std::shared_ptr<const HWC2::Display::Config>> configMap;
+        std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
 
         bool validateWasSkipped;
         hal::Error presentError;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index a154e02..2382575 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -431,6 +431,7 @@
         HwcConfigIndexType currentConfigId)
       : mKnownFrameRates(constructKnownFrameRates(configs)) {
     LOG_ALWAYS_FATAL_IF(configs.empty());
+    LOG_ALWAYS_FATAL_IF(currentConfigId.value() < 0);
     LOG_ALWAYS_FATAL_IF(currentConfigId.value() >= configs.size());
 
     for (auto configId = HwcConfigIndexType(0); configId.value() < configs.size(); configId++) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0111acc..05b4538 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -863,26 +863,12 @@
     /*
      * H/W composer
      */
-
-    // The current hardware composer interface.
-    //
-    // The following thread safety rules apply when accessing mHwc, either
-    // directly or via getHwComposer():
-    //
-    // 1. When recreating mHwc, acquire mStateLock. Recreating mHwc must only be
-    //    done on the main thread.
-    //
-    // 2. When accessing mHwc on the main thread, it's not necessary to acquire
-    //    mStateLock.
-    //
-    // 3. When accessing mHwc on a thread other than the main thread, we always
+    // The following thread safety rules apply when accessing HWComposer:
+    // 1. When reading display state from HWComposer on the main thread, it's not necessary to
+    //    acquire mStateLock.
+    // 2. When accessing HWComposer on a thread other than the main thread, we always
     //    need to acquire mStateLock. This is because the main thread could be
-    //    in the process of destroying the current mHwc instance.
-    //
-    // The above thread safety rules only apply to SurfaceFlinger.cpp. In
-    // SurfaceFlinger_hwc1.cpp we create mHwc at surface flinger init and never
-    // destroy it, so it's always safe to access mHwc from any thread without
-    // acquiring mStateLock.
+    //    in the process of writing display state, e.g. creating or destroying a display.
     HWComposer& getHwComposer() const;
 
     /*
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 06c0f8e..9ec2d16 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -365,7 +365,7 @@
     static constexpr DisplayType HWC_DISPLAY_TYPE = hwcDisplayType;
 
     // The HWC active configuration id
-    static constexpr int HWC_ACTIVE_CONFIG_ID = 2001;
+    static constexpr hal::HWConfigId HWC_ACTIVE_CONFIG_ID = 2001;
     static constexpr PowerMode INIT_POWER_MODE = hal::PowerMode::ON;
 
     static void injectPendingHotplugEvent(DisplayTransactionTest* test, Connection connection) {
@@ -416,6 +416,45 @@
                                                       ceDisplayArgs);
     }
 
+    static void setupHwcGetConfigsCallExpectations(DisplayTransactionTest* test) {
+        if (HWC_DISPLAY_TYPE == DisplayType::PHYSICAL) {
+            EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
+                    .WillRepeatedly(DoAll(SetArgPointee<1>(std::vector<hal::HWConfigId>{
+                                                  HWC_ACTIVE_CONFIG_ID}),
+                                          Return(Error::NONE)));
+            EXPECT_CALL(*test->mComposer,
+                        getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                            IComposerClient::Attribute::WIDTH, _))
+                    .WillRepeatedly(
+                            DoAll(SetArgPointee<3>(DisplayVariant::WIDTH), Return(Error::NONE)));
+            EXPECT_CALL(*test->mComposer,
+                        getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                            IComposerClient::Attribute::HEIGHT, _))
+                    .WillRepeatedly(
+                            DoAll(SetArgPointee<3>(DisplayVariant::HEIGHT), Return(Error::NONE)));
+            EXPECT_CALL(*test->mComposer,
+                        getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                            IComposerClient::Attribute::VSYNC_PERIOD, _))
+                    .WillRepeatedly(
+                            DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE)));
+            EXPECT_CALL(*test->mComposer,
+                        getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                            IComposerClient::Attribute::DPI_X, _))
+                    .WillRepeatedly(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+            EXPECT_CALL(*test->mComposer,
+                        getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                            IComposerClient::Attribute::DPI_Y, _))
+                    .WillRepeatedly(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+            EXPECT_CALL(*test->mComposer,
+                        getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                            IComposerClient::Attribute::CONFIG_GROUP, _))
+                    .WillRepeatedly(DoAll(SetArgPointee<3>(-1), Return(Error::NONE)));
+        } else {
+            EXPECT_CALL(*test->mComposer, getDisplayConfigs(_, _)).Times(0);
+            EXPECT_CALL(*test->mComposer, getDisplayAttribute(_, _, _, _)).Times(0);
+        }
+    }
+
     static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
         constexpr auto CONNECTION_TYPE =
                 PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal
@@ -427,33 +466,8 @@
 
         EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_))
                 .WillOnce(Return(hal::Error::NONE));
-        EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}),
-                                Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
-                                        IComposerClient::Attribute::WIDTH, _))
-                .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::WIDTH), Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
-                                        IComposerClient::Attribute::HEIGHT, _))
-                .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::HEIGHT), Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
-                                        IComposerClient::Attribute::VSYNC_PERIOD, _))
-                .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
-                                        IComposerClient::Attribute::DPI_X, _))
-                .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
-                                        IComposerClient::Attribute::DPI_Y, _))
-                .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
-                                        IComposerClient::Attribute::CONFIG_GROUP, _))
-                .WillOnce(DoAll(SetArgPointee<3>(-1), Return(Error::NONE)));
+
+        setupHwcGetConfigsCallExpectations(test);
 
         if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
             EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
@@ -560,6 +574,11 @@
                                                       ceDisplayArgs);
     }
 
+    static void setupHwcGetConfigsCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getDisplayConfigs(_, _)).Times(0);
+        EXPECT_CALL(*test->mComposer, getDisplayAttribute(_, _, _, _)).Times(0);
+    }
+
     static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
         EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
     }
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index fa12315..bc1e88a 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -42,7 +42,10 @@
 namespace android {
 namespace {
 
-namespace hal = android::hardware::graphics::composer::hal;
+namespace V2_1 = hardware::graphics::composer::V2_1;
+namespace V2_4 = hardware::graphics::composer::V2_4;
+
+using Hwc2::Config;
 
 using ::testing::_;
 using ::testing::DoAll;
@@ -170,5 +173,88 @@
     EXPECT_EQ(hal::Error::UNSUPPORTED, result);
 }
 
+class HWComposerConfigsTest : public testing::Test {
+public:
+    Hwc2::mock::Composer* mHal = new StrictMock<Hwc2::mock::Composer>();
+    MockHWC2ComposerCallback mCallback;
+
+    void setActiveConfig(Config config) {
+        EXPECT_CALL(*mHal, getActiveConfig(_, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(config), Return(V2_1::Error::NONE)));
+    }
+
+    void setDisplayConfigs(std::vector<Config> configs) {
+        EXPECT_CALL(*mHal, getDisplayConfigs(_, _))
+                .WillOnce(DoAll(SetArgPointee<1>(configs), Return(V2_1::Error::NONE)));
+        EXPECT_CALL(*mHal, getDisplayAttribute(_, _, _, _))
+                .WillRepeatedly(DoAll(SetArgPointee<3>(1), Return(V2_1::Error::NONE)));
+    }
+
+    void testSetActiveConfigWithConstraintsCommon(bool isVsyncPeriodSwitchSupported);
+};
+
+void HWComposerConfigsTest::testSetActiveConfigWithConstraintsCommon(
+        bool isVsyncPeriodSwitchSupported) {
+    EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
+    EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
+    EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_)).WillOnce(Return(V2_4::Error::UNSUPPORTED));
+    EXPECT_CALL(*mHal, registerCallback(_));
+    EXPECT_CALL(*mHal, setVsyncEnabled(_, _)).WillRepeatedly(Return(V2_1::Error::NONE));
+    EXPECT_CALL(*mHal, getDisplayIdentificationData(_, _, _))
+            .WillRepeatedly(Return(V2_1::Error::UNSUPPORTED));
+    EXPECT_CALL(*mHal, setClientTargetSlotCount(_)).WillRepeatedly(Return(V2_1::Error::NONE));
+
+    EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported())
+            .WillRepeatedly(Return(isVsyncPeriodSwitchSupported));
+
+    if (isVsyncPeriodSwitchSupported) {
+        EXPECT_CALL(*mHal, setActiveConfigWithConstraints(_, _, _, _))
+                .WillRepeatedly(Return(V2_4::Error::NONE));
+    } else {
+        EXPECT_CALL(*mHal, setActiveConfig(_, _)).WillRepeatedly(Return(V2_1::Error::NONE));
+    }
+
+    impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
+    hwc.setConfiguration(&mCallback, 123);
+
+    setDisplayConfigs({15});
+    setActiveConfig(15);
+
+    const auto physicalId = PhysicalDisplayId::fromPort(0);
+    const hal::HWDisplayId hwcId = 0;
+    hwc.allocatePhysicalDisplay(hwcId, physicalId);
+
+    hal::VsyncPeriodChangeConstraints constraints;
+    constraints.desiredTimeNanos = systemTime();
+    constraints.seamlessRequired = false;
+
+    hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
+    constexpr size_t kConfigIndex = 0;
+    const auto status =
+            hwc.setActiveConfigWithConstraints(physicalId, kConfigIndex, constraints, &timeline);
+    EXPECT_EQ(NO_ERROR, status);
+
+    const std::vector<Config> kConfigs{7, 8, 9, 10, 11};
+    // Change the set of supported modes.
+    setDisplayConfigs(kConfigs);
+    setActiveConfig(11);
+    hwc.onHotplug(hwcId, hal::Connection::CONNECTED);
+    hwc.allocatePhysicalDisplay(hwcId, physicalId);
+
+    for (size_t configIndex = 0; configIndex < kConfigs.size(); configIndex++) {
+        const auto status =
+                hwc.setActiveConfigWithConstraints(physicalId, configIndex, constraints, &timeline);
+        EXPECT_EQ(NO_ERROR, status) << "Error when switching to config " << configIndex;
+    }
+}
+
+TEST_F(HWComposerConfigsTest, setActiveConfigWithConstraintsWithVsyncSwitchingSupported) {
+    testSetActiveConfigWithConstraintsCommon(/*supported=*/true);
+}
+
+TEST_F(HWComposerConfigsTest, setActiveConfigWithConstraintsWithVsyncSwitchingNotSupported) {
+    testSetActiveConfigWithConstraintsCommon(/*supported=*/false);
+}
+
 } // namespace
-} // namespace android
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
index cd3f6ab..65efc85 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
@@ -144,7 +144,7 @@
     // SF should have a display token.
     const auto displayId = Case::Display::DISPLAY_ID::get();
     ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
-    ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
+    ASSERT_EQ(mFlinger.mutablePhysicalDisplayTokens().count(displayId), 1);
     auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[displayId];
 
     verifyDisplayIsConnected<Case>(displayToken);
@@ -259,14 +259,6 @@
     processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
 }
 
-TEST_F(HandleTransactionLockedTest,
-       processesHotplugConnectPrimaryDisplayWithExternalAlreadyConnected) {
-    // Inject an external display.
-    ExternalDisplayVariant::injectHwcDisplay(this);
-
-    processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
-}
-
 TEST_F(HandleTransactionLockedTest, processesHotplugConnectExternalDisplay) {
     // Inject a primary display.
     PrimaryDisplayVariant::injectHwcDisplay(this);
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index 61f0788..cedb404 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -223,6 +223,7 @@
     // Various native window calls will be made.
     Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
     Case::Display::setupHwcGetActiveConfigCallExpectations(this);
+    Case::Display::setupHwcGetConfigsCallExpectations(this);
     Case::WideColorSupport::setupComposerCallExpectations(this);
     Case::HdrSupport::setupComposerCallExpectations(this);
     Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
@@ -236,6 +237,7 @@
         ASSERT_TRUE(displayId);
         const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
         ASSERT_TRUE(hwcDisplayId);
+        mFlinger.getHwComposer().allocatePhysicalDisplay(*hwcDisplayId, *displayId);
         state.physical = {.id = *displayId, .type = *connectionType, .hwcDisplayId = *hwcDisplayId};
     }
 
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 9224c1b..5a93344 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -561,8 +561,15 @@
                 const auto physicalId = PhysicalDisplayId::tryCast(mDisplayId);
                 LOG_ALWAYS_FATAL_IF(!physicalId);
                 flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, *physicalId);
-                (mIsPrimary ? flinger->mutableInternalHwcDisplayId()
-                            : flinger->mutableExternalHwcDisplayId()) = mHwcDisplayId;
+                if (mIsPrimary) {
+                    flinger->mutableInternalHwcDisplayId() = mHwcDisplayId;
+                } else {
+                    // If there is an external HWC display there should always be an internal ID
+                    // as well. Set it to some arbitrary value.
+                    auto& internalId = flinger->mutableInternalHwcDisplayId();
+                    if (!internalId) internalId = mHwcDisplayId - 1;
+                    flinger->mutableExternalHwcDisplayId() = mHwcDisplayId;
+                }
             }
         }