SF: Extract virtual display allocation from CE

Allocate HAL virtual display and generate HAL/GPU virtual display ID in
SF rather than CE. This centralizes the HAL vs. GPU decision as a first
step in isolating display configuration (e.g. hotplug, modeset) to be a
distinct stage from invalidate/refresh.

Rework SF backend hooks for screen capture. Plumb the PhysicalDisplayId
to be mirrored by the virtual display to Composer::createVirtualDisplay.
This enables the ARC backend to know which display to mirror (instead of
making assumptions about the layer stack) or error out if not mirroring
(previously done through maybeAllocateDisplayIdForVirtualDisplay), such
that SF falls back to creating a GPU virtual display.

Bug: 182939859
Bug: 129481165
Test: Enable overlay display and toggle HAL/GPU
Test: libsurfaceflinger_unittest
Test: libcompositionengine_test
Change-Id: I209b245966e544d5ff55d5d118140cfcfa85db15
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
index 317d333..526e7da 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -21,13 +21,10 @@
 #include <string>
 
 #include <ui/DisplayId.h>
-#include <ui/PixelFormat.h>
 #include <ui/Size.h>
 #include <ui/StaticDisplayInfo.h>
 
-#include "DisplayHardware/DisplayIdentification.h"
 #include "DisplayHardware/PowerAdvisor.h"
-#include "DisplayIdGenerator.h"
 
 namespace android::compositionengine {
 
@@ -37,24 +34,14 @@
  * A parameter object for creating Display instances
  */
 struct DisplayCreationArgs {
-    struct Physical {
-        DisplayId id;
-        ui::DisplayConnectionType type;
-    };
+    DisplayId id;
 
-    // Required for physical displays. Gives the HWC display id for the existing
-    // display along with the connection type.
-    std::optional<Physical> physical;
+    // Unset for virtual displays
+    std::optional<ui::DisplayConnectionType> connectionType;
 
     // Size of the display in pixels
     ui::Size pixels = ui::kInvalidSize;
 
-    // Pixel format of the display
-    ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN);
-
-    // True if virtual displays should be created with the HWC API if possible
-    bool useHwcVirtualDisplays = false;
-
     // True if this display should be considered secure
     bool isSecure = false;
 
@@ -67,9 +54,6 @@
 
     // Debugging. Human readable name for the display.
     std::string name;
-
-    // Generator for IDs of virtual displays, which are backed by the GPU.
-    DisplayIdGenerator<GpuVirtualDisplayId>* gpuVirtualDisplayIdGenerator;
 };
 
 /**
@@ -80,8 +64,13 @@
 public:
     DisplayCreationArgs build() { return std::move(mArgs); }
 
-    DisplayCreationArgsBuilder& setPhysical(DisplayCreationArgs::Physical physical) {
-        mArgs.physical = physical;
+    DisplayCreationArgsBuilder& setId(DisplayId id) {
+        mArgs.id = id;
+        return *this;
+    }
+
+    DisplayCreationArgsBuilder& setConnectionType(ui::DisplayConnectionType connectionType) {
+        mArgs.connectionType = connectionType;
         return *this;
     }
 
@@ -90,22 +79,6 @@
         return *this;
     }
 
-    DisplayCreationArgsBuilder& setPixelFormat(ui::PixelFormat pixelFormat) {
-        mArgs.pixelFormat = pixelFormat;
-        return *this;
-    }
-
-    DisplayCreationArgsBuilder& setUseHwcVirtualDisplays(bool useHwcVirtualDisplays) {
-        mArgs.useHwcVirtualDisplays = useHwcVirtualDisplays;
-        return *this;
-    }
-
-    DisplayCreationArgsBuilder& setGpuVirtualDisplayIdGenerator(
-            DisplayIdGenerator<GpuVirtualDisplayId>& generator) {
-        mArgs.gpuVirtualDisplayIdGenerator = &generator;
-        return *this;
-    }
-
     DisplayCreationArgsBuilder& setIsSecure(bool isSecure) {
         mArgs.isSecure = isSecure;
         return *this;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 54e91ae..bb540ea 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -80,19 +80,13 @@
 
     // Internal
     virtual void setConfiguration(const compositionengine::DisplayCreationArgs&);
-    virtual std::optional<DisplayId> maybeAllocateDisplayIdForVirtualDisplay(ui::Size,
-                                                                             ui::PixelFormat) const;
     std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(const sp<LayerFE>&) const;
 
-    // Testing
-    void setDisplayIdForTesting(DisplayId displayId);
-
 private:
     bool mIsVirtual = false;
     bool mIsDisconnected = false;
     DisplayId mId;
     Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
-    DisplayIdGenerator<GpuVirtualDisplayId>* mGpuVirtualDisplayIdGenerator;
 };
 
 // This template factory function standardizes the implementation details of the
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 1ffb1c8..7d84cb5 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -50,36 +50,14 @@
 Display::~Display() = default;
 
 void Display::setConfiguration(const compositionengine::DisplayCreationArgs& args) {
-    mIsVirtual = !args.physical;
+    mId = args.id;
+    mIsVirtual = !args.connectionType;
     mPowerAdvisor = args.powerAdvisor;
     editState().isSecure = args.isSecure;
     editState().displaySpace.bounds = Rect(args.pixels);
     setLayerStackFilter(args.layerStackId,
-                        args.physical &&
-                                args.physical->type == ui::DisplayConnectionType::Internal);
+                        args.connectionType == ui::DisplayConnectionType::Internal);
     setName(args.name);
-    mGpuVirtualDisplayIdGenerator = args.gpuVirtualDisplayIdGenerator;
-
-    if (args.physical) {
-        mId = args.physical->id;
-    } else {
-        std::optional<DisplayId> id;
-        if (args.useHwcVirtualDisplays) {
-            id = maybeAllocateDisplayIdForVirtualDisplay(args.pixels, args.pixelFormat);
-        }
-        if (!id) {
-            id = mGpuVirtualDisplayIdGenerator->nextId();
-        }
-        LOG_ALWAYS_FATAL_IF(!id, "Failed to generate display ID");
-        mId = *id;
-    }
-}
-
-std::optional<DisplayId> Display::maybeAllocateDisplayIdForVirtualDisplay(
-        ui::Size pixels, ui::PixelFormat pixelFormat) const {
-    auto& hwc = getCompositionEngine().getHwComposer();
-    return hwc.allocateVirtualDisplay(static_cast<uint32_t>(pixels.width),
-                                      static_cast<uint32_t>(pixels.height), &pixelFormat);
 }
 
 bool Display::isValid() const {
@@ -102,23 +80,16 @@
     return mId;
 }
 
-void Display::setDisplayIdForTesting(DisplayId displayId) {
-    mId = displayId;
-}
-
 void Display::disconnect() {
     if (mIsDisconnected) {
         return;
     }
 
     mIsDisconnected = true;
-    if (const auto id = GpuVirtualDisplayId::tryCast(mId)) {
-        mGpuVirtualDisplayIdGenerator->markUnused(*id);
-        return;
+
+    if (const auto id = HalDisplayId::tryCast(mId)) {
+        getCompositionEngine().getHwComposer().disconnectDisplay(*id);
     }
-    const auto halDisplayId = HalDisplayId::tryCast(mId);
-    LOG_FATAL_IF(!halDisplayId);
-    getCompositionEngine().getHwComposer().disconnectDisplay(*halDisplayId);
 }
 
 void Display::setColorTransform(const compositionengine::CompositionRefreshArgs& args) {
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 492db43..5c9421b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -14,10 +14,6 @@
  * limitations under the License.
  */
 
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wextra"
-
 #include <cmath>
 
 #include <compositionengine/DisplayColorProfileCreationArgs.h>
@@ -60,13 +56,12 @@
 using testing::SetArgPointee;
 using testing::StrictMock;
 
-constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(42u);
-// TODO(b/160679868) Use VirtualDisplayId
-constexpr PhysicalDisplayId VIRTUAL_DISPLAY_ID = PhysicalDisplayId::fromPort(43u);
+constexpr PhysicalDisplayId DEFAULT_DISPLAY_ID = PhysicalDisplayId::fromPort(123u);
+constexpr HalVirtualDisplayId HAL_VIRTUAL_DISPLAY_ID{456u};
+constexpr GpuVirtualDisplayId GPU_VIRTUAL_DISPLAY_ID{789u};
 
-constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920;
-constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080;
-constexpr int32_t DEFAULT_LAYER_STACK = 123;
+constexpr ui::Size DEFAULT_RESOLUTION{1920, 1080};
+constexpr uint32_t DEFAULT_LAYER_STACK = 42;
 
 struct Layer {
     Layer() {
@@ -95,8 +90,6 @@
     public:
         using impl::Display::injectOutputLayerForTest;
         virtual void injectOutputLayerForTest(std::unique_ptr<compositionengine::OutputLayer>) = 0;
-
-        using impl::Display::maybeAllocateDisplayIdForVirtualDisplay;
     };
 
     // Uses a special implementation with key internal member functions set up
@@ -170,21 +163,19 @@
 
     DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() {
         return DisplayCreationArgsBuilder()
-                .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
-                .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
-                .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
+                .setId(DEFAULT_DISPLAY_ID)
+                .setConnectionType(ui::DisplayConnectionType::Internal)
+                .setPixels(DEFAULT_RESOLUTION)
                 .setIsSecure(true)
                 .setLayerStackId(DEFAULT_LAYER_STACK)
                 .setPowerAdvisor(&mPowerAdvisor)
                 .build();
     }
 
-    DisplayCreationArgs getDisplayCreationArgsForNonHWCVirtualDisplay() {
+    DisplayCreationArgs getDisplayCreationArgsForGpuVirtualDisplay() {
         return DisplayCreationArgsBuilder()
-                .setUseHwcVirtualDisplays(false)
-                .setGpuVirtualDisplayIdGenerator(mGpuDisplayIdGenerator)
-                .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
-                .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
+                .setId(GPU_VIRTUAL_DISPLAY_ID)
+                .setPixels(DEFAULT_RESOLUTION)
                 .setIsSecure(false)
                 .setLayerStackId(DEFAULT_LAYER_STACK)
                 .setPowerAdvisor(&mPowerAdvisor)
@@ -196,7 +187,6 @@
     StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
     StrictMock<mock::CompositionEngine> mCompositionEngine;
     sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
-    RandomDisplayIdGenerator<GpuVirtualDisplayId> mGpuDisplayIdGenerator;
 };
 
 struct PartialMockDisplayTestCommon : public DisplayTestCommon {
@@ -248,9 +238,9 @@
     EXPECT_EQ(DEFAULT_DISPLAY_ID, display->getId());
 }
 
-TEST_F(DisplayCreationTest, createNonHwcVirtualDisplay) {
-    auto display = impl::createDisplay(mCompositionEngine,
-                                       getDisplayCreationArgsForNonHWCVirtualDisplay());
+TEST_F(DisplayCreationTest, createGpuVirtualDisplay) {
+    auto display =
+            impl::createDisplay(mCompositionEngine, getDisplayCreationArgsForGpuVirtualDisplay());
     EXPECT_FALSE(display->isSecure());
     EXPECT_TRUE(display->isVirtual());
     EXPECT_TRUE(GpuVirtualDisplayId::tryCast(display->getId()));
@@ -263,17 +253,15 @@
 using DisplaySetConfigurationTest = PartialMockDisplayTestCommon;
 
 TEST_F(DisplaySetConfigurationTest, configuresInternalSecurePhysicalDisplay) {
-    mDisplay->setConfiguration(
-            DisplayCreationArgsBuilder()
-                    .setUseHwcVirtualDisplays(true)
-                    .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
-                    .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH))
-                    .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
-                    .setIsSecure(true)
-                    .setLayerStackId(DEFAULT_LAYER_STACK)
-                    .setPowerAdvisor(&mPowerAdvisor)
-                    .setName(getDisplayNameFromCurrentTest())
-                    .build());
+    mDisplay->setConfiguration(DisplayCreationArgsBuilder()
+                                       .setId(DEFAULT_DISPLAY_ID)
+                                       .setConnectionType(ui::DisplayConnectionType::Internal)
+                                       .setPixels(DEFAULT_RESOLUTION)
+                                       .setIsSecure(true)
+                                       .setLayerStackId(DEFAULT_LAYER_STACK)
+                                       .setPowerAdvisor(&mPowerAdvisor)
+                                       .setName(getDisplayNameFromCurrentTest())
+                                       .build());
 
     EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId());
     EXPECT_TRUE(mDisplay->isSecure());
@@ -284,17 +272,15 @@
 }
 
 TEST_F(DisplaySetConfigurationTest, configuresExternalInsecurePhysicalDisplay) {
-    mDisplay->setConfiguration(
-            DisplayCreationArgsBuilder()
-                    .setUseHwcVirtualDisplays(true)
-                    .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::External})
-                    .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH))
-                    .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
-                    .setIsSecure(false)
-                    .setLayerStackId(DEFAULT_LAYER_STACK)
-                    .setPowerAdvisor(&mPowerAdvisor)
-                    .setName(getDisplayNameFromCurrentTest())
-                    .build());
+    mDisplay->setConfiguration(DisplayCreationArgsBuilder()
+                                       .setId(DEFAULT_DISPLAY_ID)
+                                       .setConnectionType(ui::DisplayConnectionType::External)
+                                       .setPixels(DEFAULT_RESOLUTION)
+                                       .setIsSecure(false)
+                                       .setLayerStackId(DEFAULT_LAYER_STACK)
+                                       .setPowerAdvisor(&mPowerAdvisor)
+                                       .setName(getDisplayNameFromCurrentTest())
+                                       .build());
 
     EXPECT_EQ(DEFAULT_DISPLAY_ID, mDisplay->getId());
     EXPECT_FALSE(mDisplay->isSecure());
@@ -304,25 +290,17 @@
     EXPECT_FALSE(mDisplay->isValid());
 }
 
-TEST_F(DisplaySetConfigurationTest, configuresHwcBackedVirtualDisplay) {
-    EXPECT_CALL(mHwComposer,
-                allocateVirtualDisplay(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH,
-                                       Pointee(Eq(static_cast<ui::PixelFormat>(
-                                               PIXEL_FORMAT_RGBA_8888)))))
-            .WillOnce(Return(VIRTUAL_DISPLAY_ID));
+TEST_F(DisplaySetConfigurationTest, configuresHalVirtualDisplay) {
+    mDisplay->setConfiguration(DisplayCreationArgsBuilder()
+                                       .setId(HAL_VIRTUAL_DISPLAY_ID)
+                                       .setPixels(DEFAULT_RESOLUTION)
+                                       .setIsSecure(false)
+                                       .setLayerStackId(DEFAULT_LAYER_STACK)
+                                       .setPowerAdvisor(&mPowerAdvisor)
+                                       .setName(getDisplayNameFromCurrentTest())
+                                       .build());
 
-    mDisplay->setConfiguration(
-            DisplayCreationArgsBuilder()
-                    .setUseHwcVirtualDisplays(true)
-                    .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH))
-                    .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
-                    .setIsSecure(false)
-                    .setLayerStackId(DEFAULT_LAYER_STACK)
-                    .setPowerAdvisor(&mPowerAdvisor)
-                    .setName(getDisplayNameFromCurrentTest())
-                    .build());
-
-    EXPECT_EQ(VIRTUAL_DISPLAY_ID, mDisplay->getId());
+    EXPECT_EQ(HAL_VIRTUAL_DISPLAY_ID, mDisplay->getId());
     EXPECT_FALSE(mDisplay->isSecure());
     EXPECT_TRUE(mDisplay->isVirtual());
     EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId);
@@ -330,47 +308,17 @@
     EXPECT_FALSE(mDisplay->isValid());
 }
 
-TEST_F(DisplaySetConfigurationTest, configuresNonHwcBackedVirtualDisplayIfHwcAllocationFails) {
-    EXPECT_CALL(mHwComposer,
-                allocateVirtualDisplay(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH,
-                                       Pointee(Eq(static_cast<ui::PixelFormat>(
-                                               PIXEL_FORMAT_RGBA_8888)))))
-            .WillOnce(Return(std::nullopt));
+TEST_F(DisplaySetConfigurationTest, configuresGpuVirtualDisplay) {
+    mDisplay->setConfiguration(DisplayCreationArgsBuilder()
+                                       .setId(GPU_VIRTUAL_DISPLAY_ID)
+                                       .setPixels(DEFAULT_RESOLUTION)
+                                       .setIsSecure(false)
+                                       .setLayerStackId(DEFAULT_LAYER_STACK)
+                                       .setPowerAdvisor(&mPowerAdvisor)
+                                       .setName(getDisplayNameFromCurrentTest())
+                                       .build());
 
-    mDisplay->setConfiguration(
-            DisplayCreationArgsBuilder()
-                    .setUseHwcVirtualDisplays(true)
-                    .setGpuVirtualDisplayIdGenerator(mGpuDisplayIdGenerator)
-                    .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH))
-                    .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
-                    .setIsSecure(false)
-                    .setLayerStackId(DEFAULT_LAYER_STACK)
-                    .setPowerAdvisor(&mPowerAdvisor)
-                    .setName(getDisplayNameFromCurrentTest())
-                    .build());
-
-    EXPECT_TRUE(GpuVirtualDisplayId::tryCast(mDisplay->getId()));
-    EXPECT_FALSE(mDisplay->isSecure());
-    EXPECT_TRUE(mDisplay->isVirtual());
-    EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId);
-    EXPECT_FALSE(mDisplay->getState().layerStackInternal);
-    EXPECT_FALSE(mDisplay->isValid());
-}
-
-TEST_F(DisplaySetConfigurationTest, configuresNonHwcBackedVirtualDisplayIfShouldNotUseHwc) {
-    mDisplay->setConfiguration(
-            DisplayCreationArgsBuilder()
-                    .setUseHwcVirtualDisplays(false)
-                    .setGpuVirtualDisplayIdGenerator(mGpuDisplayIdGenerator)
-                    .setPixels(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_WIDTH))
-                    .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
-                    .setIsSecure(false)
-                    .setLayerStackId(DEFAULT_LAYER_STACK)
-                    .setPowerAdvisor(&mPowerAdvisor)
-                    .setName(getDisplayNameFromCurrentTest())
-                    .build());
-
-    EXPECT_TRUE(GpuVirtualDisplayId::tryCast(mDisplay->getId()));
+    EXPECT_EQ(GPU_VIRTUAL_DISPLAY_ID, mDisplay->getId());
     EXPECT_FALSE(mDisplay->isSecure());
     EXPECT_TRUE(mDisplay->isVirtual());
     EXPECT_EQ(DEFAULT_LAYER_STACK, mDisplay->getState().layerStackId);
@@ -477,7 +425,7 @@
 TEST_F(DisplaySetColorModeTest, doesNothingForVirtualDisplay) {
     using ColorProfile = Output::ColorProfile;
 
-    auto args = getDisplayCreationArgsForNonHWCVirtualDisplay();
+    auto args = getDisplayCreationArgsForGpuVirtualDisplay();
     std::shared_ptr<impl::Display> virtualDisplay = impl::createDisplay(mCompositionEngine, args);
 
     mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>();
@@ -557,25 +505,25 @@
 
 using DisplaySetReleasedLayersTest = DisplayWithLayersTestCommon;
 
-TEST_F(DisplaySetReleasedLayersTest, doesNothingIfNotHwcDisplay) {
-    auto args = getDisplayCreationArgsForNonHWCVirtualDisplay();
-    std::shared_ptr<impl::Display> nonHwcDisplay = impl::createDisplay(mCompositionEngine, args);
+TEST_F(DisplaySetReleasedLayersTest, doesNothingIfGpuDisplay) {
+    auto args = getDisplayCreationArgsForGpuVirtualDisplay();
+    std::shared_ptr<impl::Display> gpuDisplay = impl::createDisplay(mCompositionEngine, args);
 
     sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>();
 
     {
         Output::ReleasedLayers releasedLayers;
         releasedLayers.emplace_back(layerXLayerFE);
-        nonHwcDisplay->setReleasedLayers(std::move(releasedLayers));
+        gpuDisplay->setReleasedLayers(std::move(releasedLayers));
     }
 
     CompositionRefreshArgs refreshArgs;
     refreshArgs.layersWithQueuedFrames.push_back(layerXLayerFE);
 
-    nonHwcDisplay->setReleasedLayers(refreshArgs);
+    gpuDisplay->setReleasedLayers(refreshArgs);
 
-    const auto& releasedLayers = nonHwcDisplay->getReleasedLayersForTest();
-    ASSERT_EQ(1, releasedLayers.size());
+    const auto& releasedLayers = gpuDisplay->getReleasedLayersForTest();
+    ASSERT_EQ(1u, releasedLayers.size());
 }
 
 TEST_F(DisplaySetReleasedLayersTest, doesNothingIfNoLayersWithQueuedFrames) {
@@ -591,7 +539,7 @@
     mDisplay->setReleasedLayers(refreshArgs);
 
     const auto& releasedLayers = mDisplay->getReleasedLayersForTest();
-    ASSERT_EQ(1, releasedLayers.size());
+    ASSERT_EQ(1u, releasedLayers.size());
 }
 
 TEST_F(DisplaySetReleasedLayersTest, setReleasedLayers) {
@@ -605,7 +553,7 @@
     mDisplay->setReleasedLayers(refreshArgs);
 
     const auto& releasedLayers = mDisplay->getReleasedLayersForTest();
-    ASSERT_EQ(2, releasedLayers.size());
+    ASSERT_EQ(2u, releasedLayers.size());
     ASSERT_EQ(mLayer1.layerFE.get(), releasedLayers[0].promote().get());
     ASSERT_EQ(mLayer2.layerFE.get(), releasedLayers[1].promote().get());
 }
@@ -616,15 +564,15 @@
 
 using DisplayChooseCompositionStrategyTest = PartialMockDisplayTestCommon;
 
-TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) {
-    auto args = getDisplayCreationArgsForNonHWCVirtualDisplay();
-    std::shared_ptr<Display> nonHwcDisplay =
+TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfGpuDisplay) {
+    auto args = getDisplayCreationArgsForGpuVirtualDisplay();
+    std::shared_ptr<Display> gpuDisplay =
             createPartialMockDisplay<Display>(mCompositionEngine, args);
-    EXPECT_TRUE(GpuVirtualDisplayId::tryCast(nonHwcDisplay->getId()));
+    EXPECT_TRUE(GpuVirtualDisplayId::tryCast(gpuDisplay->getId()));
 
-    nonHwcDisplay->chooseCompositionStrategy();
+    gpuDisplay->chooseCompositionStrategy();
 
-    auto& state = nonHwcDisplay->getState();
+    auto& state = gpuDisplay->getState();
     EXPECT_TRUE(state.usesClientComposition);
     EXPECT_FALSE(state.usesDeviceComposition);
 }
@@ -704,12 +652,12 @@
 
 using DisplayGetSkipColorTransformTest = DisplayWithLayersTestCommon;
 
-TEST_F(DisplayGetSkipColorTransformTest, checksCapabilityIfNonHwcDisplay) {
+TEST_F(DisplayGetSkipColorTransformTest, checksCapabilityIfGpuDisplay) {
     EXPECT_CALL(mHwComposer, hasCapability(hal::Capability::SKIP_CLIENT_COLOR_TRANSFORM))
             .WillOnce(Return(true));
-    auto args = getDisplayCreationArgsForNonHWCVirtualDisplay();
-    auto nonHwcDisplay{impl::createDisplay(mCompositionEngine, args)};
-    EXPECT_TRUE(nonHwcDisplay->getSkipColorTransform());
+    auto args = getDisplayCreationArgsForGpuVirtualDisplay();
+    auto gpuDisplay{impl::createDisplay(mCompositionEngine, args)};
+    EXPECT_TRUE(gpuDisplay->getSkipColorTransform());
 }
 
 TEST_F(DisplayGetSkipColorTransformTest, checksDisplayCapability) {
@@ -856,11 +804,11 @@
 
 using DisplayPresentAndGetFrameFencesTest = DisplayWithLayersTestCommon;
 
-TEST_F(DisplayPresentAndGetFrameFencesTest, returnsNoFencesOnNonHwcDisplay) {
-    auto args = getDisplayCreationArgsForNonHWCVirtualDisplay();
-    auto nonHwcDisplay{impl::createDisplay(mCompositionEngine, args)};
+TEST_F(DisplayPresentAndGetFrameFencesTest, returnsNoFencesOnGpuDisplay) {
+    auto args = getDisplayCreationArgsForGpuVirtualDisplay();
+    auto gpuDisplay{impl::createDisplay(mCompositionEngine, args)};
 
-    auto result = nonHwcDisplay->presentAndGetFrameFences();
+    auto result = gpuDisplay->presentAndGetFrameFences();
 
     ASSERT_TRUE(result.presentFence.get());
     EXPECT_FALSE(result.presentFence->isValid());
@@ -888,9 +836,9 @@
     EXPECT_EQ(presentFence, result.presentFence);
 
     EXPECT_EQ(2u, result.layerFences.size());
-    ASSERT_EQ(1, result.layerFences.count(&mLayer1.hwc2Layer));
+    ASSERT_EQ(1u, result.layerFences.count(&mLayer1.hwc2Layer));
     EXPECT_EQ(layer1Fence, result.layerFences[&mLayer1.hwc2Layer]);
-    ASSERT_EQ(1, result.layerFences.count(&mLayer2.hwc2Layer));
+    ASSERT_EQ(1u, result.layerFences.count(&mLayer2.hwc2Layer));
     EXPECT_EQ(layer2Fence, result.layerFences[&mLayer2.hwc2Layer]);
 }
 
@@ -936,66 +884,66 @@
 }
 
 TEST_F(DisplayFinishFrameTest, skipsCompositionIfNotDirty) {
-    auto args = getDisplayCreationArgsForNonHWCVirtualDisplay();
-    std::shared_ptr<impl::Display> nonHwcDisplay = impl::createDisplay(mCompositionEngine, args);
+    auto args = getDisplayCreationArgsForGpuVirtualDisplay();
+    std::shared_ptr<impl::Display> gpuDisplay = impl::createDisplay(mCompositionEngine, args);
 
     mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
-    nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+    gpuDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
 
     // We expect no calls to queueBuffer if composition was skipped.
     EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(0);
 
-    nonHwcDisplay->editState().isEnabled = true;
-    nonHwcDisplay->editState().usesClientComposition = false;
-    nonHwcDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
-    nonHwcDisplay->editState().dirtyRegion = Region::INVALID_REGION;
+    gpuDisplay->editState().isEnabled = true;
+    gpuDisplay->editState().usesClientComposition = false;
+    gpuDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
+    gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION;
 
     CompositionRefreshArgs refreshArgs;
     refreshArgs.repaintEverything = false;
 
-    nonHwcDisplay->finishFrame(refreshArgs);
+    gpuDisplay->finishFrame(refreshArgs);
 }
 
 TEST_F(DisplayFinishFrameTest, performsCompositionIfDirty) {
-    auto args = getDisplayCreationArgsForNonHWCVirtualDisplay();
-    std::shared_ptr<impl::Display> nonHwcDisplay = impl::createDisplay(mCompositionEngine, args);
+    auto args = getDisplayCreationArgsForGpuVirtualDisplay();
+    std::shared_ptr<impl::Display> gpuDisplay = impl::createDisplay(mCompositionEngine, args);
 
     mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
-    nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+    gpuDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
 
     // We expect a single call to queueBuffer when composition is not skipped.
     EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
 
-    nonHwcDisplay->editState().isEnabled = true;
-    nonHwcDisplay->editState().usesClientComposition = false;
-    nonHwcDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
-    nonHwcDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1));
+    gpuDisplay->editState().isEnabled = true;
+    gpuDisplay->editState().usesClientComposition = false;
+    gpuDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
+    gpuDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1));
 
     CompositionRefreshArgs refreshArgs;
     refreshArgs.repaintEverything = false;
 
-    nonHwcDisplay->finishFrame(refreshArgs);
+    gpuDisplay->finishFrame(refreshArgs);
 }
 
 TEST_F(DisplayFinishFrameTest, performsCompositionIfRepaintEverything) {
-    auto args = getDisplayCreationArgsForNonHWCVirtualDisplay();
-    std::shared_ptr<impl::Display> nonHwcDisplay = impl::createDisplay(mCompositionEngine, args);
+    auto args = getDisplayCreationArgsForGpuVirtualDisplay();
+    std::shared_ptr<impl::Display> gpuDisplay = impl::createDisplay(mCompositionEngine, args);
 
     mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
-    nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+    gpuDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
 
     // We expect a single call to queueBuffer when composition is not skipped.
     EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
 
-    nonHwcDisplay->editState().isEnabled = true;
-    nonHwcDisplay->editState().usesClientComposition = false;
-    nonHwcDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
-    nonHwcDisplay->editState().dirtyRegion = Region::INVALID_REGION;
+    gpuDisplay->editState().isEnabled = true;
+    gpuDisplay->editState().usesClientComposition = false;
+    gpuDisplay->editState().layerStackSpace.content = Rect(0, 0, 1, 1);
+    gpuDisplay->editState().dirtyRegion = Region::INVALID_REGION;
 
     CompositionRefreshArgs refreshArgs;
     refreshArgs.repaintEverything = true;
 
-    nonHwcDisplay->finishFrame(refreshArgs);
+    gpuDisplay->finishFrame(refreshArgs);
 }
 
 /*
@@ -1020,23 +968,23 @@
     NiceMock<mock::CompositionEngine> mCompositionEngine;
     sp<mock::NativeWindow> mNativeWindow = new NiceMock<mock::NativeWindow>();
     sp<mock::DisplaySurface> mDisplaySurface = new NiceMock<mock::DisplaySurface>();
+
     std::shared_ptr<Display> mDisplay = impl::createDisplayTemplated<
             Display>(mCompositionEngine,
                      DisplayCreationArgsBuilder()
-                             .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
-                             .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
-                             .setPixelFormat(static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888))
+                             .setId(DEFAULT_DISPLAY_ID)
+                             .setConnectionType(ui::DisplayConnectionType::Internal)
+                             .setPixels(DEFAULT_RESOLUTION)
                              .setIsSecure(true)
                              .setLayerStackId(DEFAULT_LAYER_STACK)
                              .setPowerAdvisor(&mPowerAdvisor)
-                             .build()
+                             .build());
 
-    );
     impl::RenderSurface* mRenderSurface =
             new impl::RenderSurface{mCompositionEngine, *mDisplay,
                                     RenderSurfaceCreationArgsBuilder()
-                                            .setDisplayWidth(DEFAULT_DISPLAY_WIDTH)
-                                            .setDisplayHeight(DEFAULT_DISPLAY_HEIGHT)
+                                            .setDisplayWidth(DEFAULT_RESOLUTION.width)
+                                            .setDisplayHeight(DEFAULT_RESOLUTION.height)
                                             .setNativeWindow(mNativeWindow)
                                             .setDisplaySurface(mDisplaySurface)
                                             .build()};
@@ -1055,6 +1003,3 @@
 
 } // namespace
 } // namespace android::compositionengine
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index bac894a..ee4f331 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -45,9 +45,13 @@
     MOCK_CONST_METHOD1(hasCapability, bool(hal::Capability));
     MOCK_CONST_METHOD2(hasDisplayCapability, bool(HalDisplayId, hal::DisplayCapability));
 
-    MOCK_METHOD3(allocateVirtualDisplay,
-                 std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
+    MOCK_CONST_METHOD0(getMaxVirtualDisplayCount, size_t());
+    MOCK_CONST_METHOD0(getMaxVirtualDisplayDimension, size_t());
+    MOCK_METHOD4(allocateVirtualDisplay,
+                 bool(HalVirtualDisplayId, ui::Size, ui::PixelFormat*,
+                      std::optional<PhysicalDisplayId>));
     MOCK_METHOD2(allocatePhysicalDisplay, void(hal::HWDisplayId, PhysicalDisplayId));
+
     MOCK_METHOD1(createLayer, HWC2::Layer*(HalDisplayId));
     MOCK_METHOD2(destroyLayer, void(HalDisplayId, HWC2::Layer*));
     MOCK_METHOD3(getDeviceCompositionChanges,
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index bf249cd..33c2563 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -103,15 +103,21 @@
     bool needsFiltering() const;
     ui::LayerStack getLayerStack() const;
 
-    // Returns the physical ID of this display. This function asserts the ID is physical and it
-    // shouldn't be called for other display types, e.g. virtual.
+    DisplayId getId() const;
+
+    // Shorthand to upcast the ID of a display whose type is known as a precondition.
     PhysicalDisplayId getPhysicalId() const {
-        const auto displayIdOpt = PhysicalDisplayId::tryCast(getId());
-        LOG_FATAL_IF(!displayIdOpt);
-        return *displayIdOpt;
+        const auto id = PhysicalDisplayId::tryCast(getId());
+        LOG_FATAL_IF(!id);
+        return *id;
     }
 
-    DisplayId getId() const;
+    VirtualDisplayId getVirtualId() const {
+        const auto id = VirtualDisplayId::tryCast(getId());
+        LOG_FATAL_IF(!id);
+        return *id;
+    }
+
     const wp<IBinder>& getDisplayToken() const { return mDisplayToken; }
     int32_t getSequenceId() const { return mSequenceId; }
 
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 1cbcf59..caf0294 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -211,9 +211,8 @@
     return unwrapRet(ret, 0);
 }
 
-Error Composer::createVirtualDisplay(uint32_t width, uint32_t height,
-            PixelFormat* format, Display* outDisplay)
-{
+Error Composer::createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
+                                     std::optional<Display>, Display* outDisplay) {
     const uint32_t bufferSlotCount = 1;
     Error error = kDefaultError;
     if (mClient_2_2) {
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 0619b8c..b525e63 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -18,6 +18,7 @@
 #define ANDROID_SF_COMPOSER_HAL_H
 
 #include <memory>
+#include <optional>
 #include <string>
 #include <unordered_map>
 #include <utility>
@@ -94,8 +95,8 @@
     virtual Error executeCommands() = 0;
 
     virtual uint32_t getMaxVirtualDisplayCount() = 0;
-    virtual Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
-                                       Display* outDisplay) = 0;
+    virtual Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat*,
+                                       std::optional<Display> mirror, Display* outDisplay) = 0;
     virtual Error destroyVirtualDisplay(Display display) = 0;
 
     virtual Error acceptDisplayChanges(Display display) = 0;
@@ -341,7 +342,7 @@
 
     uint32_t getMaxVirtualDisplayCount() override;
     Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
-                               Display* outDisplay) override;
+                               std::optional<Display> mirror, Display* outDisplay) override;
     Error destroyVirtualDisplay(Display display) override;
 
     Error acceptDisplayChanges(Display display) override;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index b73d032..97cbd07 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -38,7 +38,6 @@
 #include <utils/Trace.h>
 
 #include "../Layer.h" // needed only for debugging
-#include "../SurfaceFlinger.h"
 #include "../SurfaceFlingerProperties.h"
 #include "ComposerHal.h"
 #include "HWC2.h"
@@ -145,8 +144,9 @@
 
 HWComposer::HWComposer(std::unique_ptr<Hwc2::Composer> composer)
       : mComposer(std::move(composer)),
+        mMaxVirtualDisplayDimension(static_cast<size_t>(sysprop::max_virtual_display_dimension(0))),
         mUpdateDeviceProductInfoOnHotplugReconnect(
-                android::sysprop::update_device_product_info_on_hotplug_reconnect(false)) {}
+                sysprop::update_device_product_info_on_hotplug_reconnect(false)) {}
 
 HWComposer::HWComposer(const std::string& composerServiceName)
       : HWComposer(std::make_unique<Hwc2::impl::Composer>(composerServiceName)) {}
@@ -243,38 +243,49 @@
     return true;
 }
 
-std::optional<DisplayId> HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
-                                                            ui::PixelFormat* format) {
-    if (SurfaceFlinger::maxVirtualDisplaySize != 0 &&
-        (width > SurfaceFlinger::maxVirtualDisplaySize ||
-         height > SurfaceFlinger::maxVirtualDisplaySize)) {
-        ALOGE("%s: Display size %ux%u exceeds maximum dimension of %" PRIu64, __FUNCTION__, width,
-              height, SurfaceFlinger::maxVirtualDisplaySize);
-        return {};
+size_t HWComposer::getMaxVirtualDisplayCount() const {
+    return mComposer->getMaxVirtualDisplayCount();
+}
+
+size_t HWComposer::getMaxVirtualDisplayDimension() const {
+    return mMaxVirtualDisplayDimension;
+}
+
+bool HWComposer::allocateVirtualDisplay(HalVirtualDisplayId displayId, ui::Size resolution,
+                                        ui::PixelFormat* format,
+                                        std::optional<PhysicalDisplayId> mirror) {
+    if (!resolution.isValid()) {
+        ALOGE("%s: Invalid resolution %dx%d", __func__, resolution.width, resolution.height);
+        return false;
     }
 
-    const auto displayId = mVirtualIdGenerator.nextId();
-    if (!displayId) {
-        ALOGE("%s: No remaining virtual displays", __FUNCTION__);
-        return {};
+    const uint32_t width = static_cast<uint32_t>(resolution.width);
+    const uint32_t height = static_cast<uint32_t>(resolution.height);
+
+    if (mMaxVirtualDisplayDimension > 0 &&
+        (width > mMaxVirtualDisplayDimension || height > mMaxVirtualDisplayDimension)) {
+        ALOGE("%s: Resolution %ux%u exceeds maximum dimension %zu", __func__, width, height,
+              mMaxVirtualDisplayDimension);
+        return false;
     }
 
-    hal::HWDisplayId hwcDisplayId = 0;
+    std::optional<hal::HWDisplayId> hwcMirrorId;
+    if (mirror) {
+        hwcMirrorId = fromPhysicalDisplayId(*mirror);
+    }
+
+    hal::HWDisplayId hwcDisplayId;
     const auto error = static_cast<hal::Error>(
-            mComposer->createVirtualDisplay(width, height, format, &hwcDisplayId));
-    if (error != hal::Error::NONE) {
-        ALOGE("%s: Failed to create HWC virtual display", __FUNCTION__);
-        mVirtualIdGenerator.markUnused(*displayId);
-        return {};
-    }
+            mComposer->createVirtualDisplay(width, height, format, hwcMirrorId, &hwcDisplayId));
+    RETURN_IF_HWC_ERROR_FOR("createVirtualDisplay", error, displayId, false);
 
     auto display = std::make_unique<HWC2::impl::Display>(*mComposer.get(), mCapabilities,
                                                          hwcDisplayId, hal::DisplayType::VIRTUAL);
     display->setConnected(true);
-    auto& displayData = mDisplayData[*displayId];
+    auto& displayData = mDisplayData[displayId];
     displayData.hwcDisplay = std::move(display);
     displayData.isVirtual = true;
-    return displayId;
+    return true;
 }
 
 void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId,
@@ -666,13 +677,6 @@
 void HWComposer::disconnectDisplay(HalDisplayId displayId) {
     RETURN_IF_INVALID_DISPLAY(displayId);
     auto& displayData = mDisplayData[displayId];
-
-    // If this was a virtual display, add its slot back for reuse by future
-    // virtual displays
-    if (displayData.isVirtual) {
-        mVirtualIdGenerator.markUnused(*HalVirtualDisplayId::tryCast(displayId));
-    }
-
     const auto hwcDisplayId = displayData.hwcDisplay->getId();
 
     // TODO(b/74619554): Select internal/external display from remaining displays.
@@ -979,10 +983,6 @@
     }
 }
 
-uint32_t HWComposer::getMaxVirtualDisplayCount() const {
-    return mComposer->getMaxVirtualDisplayCount();
-}
-
 } // namespace impl
 } // namespace android
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index f532e50..1f81b8d 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -39,7 +39,6 @@
 #include <utils/StrongPointer.h>
 #include <utils/Timers.h>
 
-#include "DisplayIdGenerator.h"
 #include "DisplayIdentification.h"
 #include "DisplayMode.h"
 #include "HWC2.h"
@@ -109,9 +108,16 @@
     virtual bool hasCapability(hal::Capability) const = 0;
     virtual bool hasDisplayCapability(HalDisplayId, hal::DisplayCapability) const = 0;
 
-    // Attempts to allocate a virtual display and returns its ID if created on the HWC device.
-    virtual std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height,
-                                                            ui::PixelFormat*) = 0;
+    virtual size_t getMaxVirtualDisplayCount() const = 0;
+    virtual size_t getMaxVirtualDisplayDimension() const = 0;
+
+    // Attempts to allocate a virtual display on the HWC. The maximum number of virtual displays
+    // supported by the HWC can be queried in advance, but allocation may fail for other reasons.
+    // For virtualized compositors, the PhysicalDisplayId is a hint that this virtual display is
+    // a mirror of a physical display, and that the screen should be captured by the host rather
+    // than guest compositor.
+    virtual bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*,
+                                        std::optional<PhysicalDisplayId> mirror) = 0;
 
     virtual void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) = 0;
 
@@ -254,9 +260,11 @@
     bool hasCapability(hal::Capability) const override;
     bool hasDisplayCapability(HalDisplayId, hal::DisplayCapability) const override;
 
-    // Attempts to allocate a virtual display and returns its ID if created on the HWC device.
-    std::optional<DisplayId> allocateVirtualDisplay(uint32_t width, uint32_t height,
-                                                    ui::PixelFormat*) override;
+    size_t getMaxVirtualDisplayCount() const override;
+    size_t getMaxVirtualDisplayDimension() const override;
+
+    bool allocateVirtualDisplay(HalVirtualDisplayId, ui::Size, ui::PixelFormat*,
+                                std::optional<PhysicalDisplayId>) override;
 
     // Called from SurfaceFlinger, when the state for a new physical display needs to be recreated.
     void allocatePhysicalDisplay(hal::HWDisplayId, PhysicalDisplayId) override;
@@ -402,7 +410,6 @@
 
     void loadCapabilities();
     void loadLayerMetadataSupport();
-    uint32_t getMaxVirtualDisplayCount() const;
 
     std::unordered_map<HalDisplayId, DisplayData> mDisplayData;
 
@@ -416,8 +423,7 @@
     std::optional<hal::HWDisplayId> mExternalHwcDisplayId;
     bool mHasMultiDisplaySupport = false;
 
-    RandomDisplayIdGenerator<HalVirtualDisplayId> mVirtualIdGenerator{getMaxVirtualDisplayCount()};
-
+    const size_t mMaxVirtualDisplayDimension;
     const bool mUpdateDeviceProductInfoOnHotplugReconnect;
 };
 
diff --git a/services/surfaceflinger/DisplayIdGenerator.h b/services/surfaceflinger/DisplayIdGenerator.h
index e7c69a8..9791a25 100644
--- a/services/surfaceflinger/DisplayIdGenerator.h
+++ b/services/surfaceflinger/DisplayIdGenerator.h
@@ -27,23 +27,16 @@
 
 namespace android {
 
-template <typename T>
+// Generates pseudo-random IDs of type GpuVirtualDisplayId or HalVirtualDisplayId.
+template <typename Id>
 class DisplayIdGenerator {
 public:
-    virtual std::optional<T> nextId() = 0;
-    virtual void markUnused(T id) = 0;
-
-protected:
-    ~DisplayIdGenerator() {}
-};
-
-template <typename T>
-class RandomDisplayIdGenerator final : public DisplayIdGenerator<T> {
-public:
-    explicit RandomDisplayIdGenerator(size_t maxIdsCount = std::numeric_limits<size_t>::max())
+    explicit DisplayIdGenerator(size_t maxIdsCount = std::numeric_limits<size_t>::max())
           : mMaxIdsCount(maxIdsCount) {}
 
-    std::optional<T> nextId() override {
+    bool inUse() const { return !mUsedIds.empty(); }
+
+    std::optional<Id> generateId() {
         if (mUsedIds.size() >= mMaxIdsCount) {
             return std::nullopt;
         }
@@ -51,8 +44,7 @@
         constexpr int kMaxAttempts = 1000;
 
         for (int attempts = 0; attempts < kMaxAttempts; attempts++) {
-            const auto baseId = mDistribution(mGenerator);
-            const T id(baseId);
+            const Id id{mDistribution(mGenerator)};
             if (mUsedIds.count(id) == 0) {
                 mUsedIds.insert(id);
                 return id;
@@ -62,14 +54,18 @@
         LOG_ALWAYS_FATAL("Couldn't generate ID after %d attempts", kMaxAttempts);
     }
 
-    void markUnused(T id) override { mUsedIds.erase(id); }
+    void releaseId(Id id) { mUsedIds.erase(id); }
 
 private:
     const size_t mMaxIdsCount;
 
-    std::unordered_set<T> mUsedIds;
+    std::unordered_set<Id> mUsedIds;
+
+    // Pseudo-random with random seed, in contrast to physical display IDs, which are stable
+    // across reboots. The only ISurfaceComposer exposure for these IDs is a restricted API
+    // for screencap, so there is little benefit in making them unpredictable.
     std::default_random_engine mGenerator{std::random_device()()};
-    std::uniform_int_distribution<typename T::BaseId> mDistribution;
+    std::uniform_int_distribution<typename Id::BaseId> mDistribution;
 };
 
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4b0bdcb..377e685 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -294,7 +294,6 @@
 // ---------------------------------------------------------------------------
 int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
 bool SurfaceFlinger::useHwcForRgbToYuv;
-uint64_t SurfaceFlinger::maxVirtualDisplaySize;
 bool SurfaceFlinger::hasSyncFramework;
 int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
 uint32_t SurfaceFlinger::maxGraphicsWidth;
@@ -356,8 +355,6 @@
 
     useHwcForRgbToYuv = force_hwc_copy_for_virtual_displays(false);
 
-    maxVirtualDisplaySize = max_virtual_display_dimension(0);
-
     maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2);
 
     maxGraphicsWidth = std::max(max_graphics_width(0), 0);
@@ -433,10 +430,6 @@
     ALOGI_IF(mPropagateBackpressureClientComposition,
              "Enabling backpressure propagation for Client Composition");
 
-    property_get("debug.sf.enable_hwc_vds", value, "0");
-    mUseHwcVirtualDisplays = atoi(value);
-    ALOGI_IF(mUseHwcVirtualDisplays, "Enabling HWC virtual displays");
-
     property_get("ro.surface_flinger.supports_background_blur", value, "0");
     bool supportsBlurs = atoi(value);
     mSupportsBlur = supportsBlurs;
@@ -574,6 +567,59 @@
     setTransactionFlags(eDisplayTransactionNeeded);
 }
 
+void SurfaceFlinger::enableHalVirtualDisplays(bool enable) {
+    auto& generator = mVirtualDisplayIdGenerators.hal;
+    if (!generator && enable) {
+        ALOGI("Enabling HAL virtual displays");
+        generator.emplace(getHwComposer().getMaxVirtualDisplayCount());
+    } else if (generator && !enable) {
+        ALOGW_IF(generator->inUse(), "Disabling HAL virtual displays while in use");
+        generator.reset();
+    }
+}
+
+VirtualDisplayId SurfaceFlinger::acquireVirtualDisplay(ui::Size resolution, ui::PixelFormat format,
+                                                       ui::LayerStack layerStack) {
+    if (auto& generator = mVirtualDisplayIdGenerators.hal) {
+        if (const auto id = generator->generateId()) {
+            std::optional<PhysicalDisplayId> mirror;
+
+            if (const auto display = findDisplay([layerStack](const auto& display) {
+                    return !display.isVirtual() && display.getLayerStack() == layerStack;
+                })) {
+                mirror = display->getPhysicalId();
+            }
+
+            if (getHwComposer().allocateVirtualDisplay(*id, resolution, &format, mirror)) {
+                return *id;
+            }
+
+            generator->releaseId(*id);
+        } else {
+            ALOGW("%s: Exhausted HAL virtual displays", __func__);
+        }
+
+        ALOGW("%s: Falling back to GPU virtual display", __func__);
+    }
+
+    const auto id = mVirtualDisplayIdGenerators.gpu.generateId();
+    LOG_ALWAYS_FATAL_IF(!id, "Failed to generate ID for GPU virtual display");
+    return *id;
+}
+
+void SurfaceFlinger::releaseVirtualDisplay(VirtualDisplayId displayId) {
+    if (const auto id = HalVirtualDisplayId::tryCast(displayId)) {
+        if (auto& generator = mVirtualDisplayIdGenerators.hal) {
+            generator->releaseId(*id);
+        }
+        return;
+    }
+
+    const auto id = GpuVirtualDisplayId::tryCast(displayId);
+    LOG_ALWAYS_FATAL_IF(!id);
+    mVirtualDisplayIdGenerators.gpu.releaseId(*id);
+}
+
 std::vector<PhysicalDisplayId> SurfaceFlinger::getPhysicalDisplayIds() const {
     Mutex::Autolock lock(mStateLock);
 
@@ -734,6 +780,11 @@
     mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName));
     mCompositionEngine->getHwComposer().setConfiguration(this, getBE().mComposerSequenceId);
     ClientCache::getInstance().setRenderEngine(&getRenderEngine());
+
+    if (base::GetBoolProperty("debug.sf.enable_hwc_vds"s, false)) {
+        enableHalVirtualDisplays(true);
+    }
+
     // Process any initial hotplug and resulting display changes.
     processDisplayHotplugEventsLocked();
     const auto display = getDefaultDisplayDeviceLocked();
@@ -2625,10 +2676,10 @@
         ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
         status = state.surface->query(NATIVE_WINDOW_HEIGHT, &resolution.height);
         ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status);
-        int intPixelFormat;
-        status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat);
+        int format;
+        status = state.surface->query(NATIVE_WINDOW_FORMAT, &format);
         ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
-        pixelFormat = static_cast<ui::PixelFormat>(intPixelFormat);
+        pixelFormat = static_cast<ui::PixelFormat>(format);
     } else {
         // Virtual displays without a surface are dormant:
         // they have external state (layer stack, projection,
@@ -2638,17 +2689,18 @@
 
     compositionengine::DisplayCreationArgsBuilder builder;
     if (const auto& physical = state.physical) {
-        builder.setPhysical({physical->id, physical->type});
+        builder.setId(physical->id);
+        builder.setConnectionType(physical->type);
+    } else {
+        builder.setId(acquireVirtualDisplay(resolution, pixelFormat, state.layerStack));
     }
+
     builder.setPixels(resolution);
-    builder.setPixelFormat(pixelFormat);
     builder.setIsSecure(state.isSecure);
     builder.setLayerStackId(state.layerStack);
     builder.setPowerAdvisor(&mPowerAdvisor);
-    builder.setUseHwcVirtualDisplays(mUseHwcVirtualDisplays);
-    builder.setGpuVirtualDisplayIdGenerator(mGpuVirtualDisplayIdGenerator);
     builder.setName(state.displayName);
-    const auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
+    auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
     compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled);
 
     sp<compositionengine::DisplaySurface> displaySurface;
@@ -2657,33 +2709,30 @@
     sp<IGraphicBufferConsumer> bqConsumer;
     getFactory().createBufferQueue(&bqProducer, &bqConsumer, /*consumerIsSurfaceFlinger =*/false);
 
-    DisplayId displayId = compositionDisplay->getId();
-
     if (state.isVirtual()) {
-        const auto virtualId = VirtualDisplayId::tryCast(displayId);
-        LOG_FATAL_IF(!virtualId);
-        sp<VirtualDisplaySurface> vds =
-                new VirtualDisplaySurface(getHwComposer(), *virtualId, state.surface, bqProducer,
-                                          bqConsumer, state.displayName);
-
-        displaySurface = vds;
-        producer = vds;
+        const auto displayId = VirtualDisplayId::tryCast(compositionDisplay->getId());
+        LOG_FATAL_IF(!displayId);
+        auto surface = sp<VirtualDisplaySurface>::make(getHwComposer(), *displayId, state.surface,
+                                                       bqProducer, bqConsumer, state.displayName);
+        displaySurface = surface;
+        producer = std::move(surface);
     } else {
         ALOGE_IF(state.surface != nullptr,
                  "adding a supported display, but rendering "
                  "surface is provided (%p), ignoring it",
                  state.surface.get());
-        const auto physicalId = PhysicalDisplayId::tryCast(displayId);
-        LOG_FATAL_IF(!physicalId);
-        displaySurface = new FramebufferSurface(getHwComposer(), *physicalId, bqConsumer,
-                                                state.physical->activeMode->getSize(),
-                                                ui::Size(maxGraphicsWidth, maxGraphicsHeight));
+        const auto displayId = PhysicalDisplayId::tryCast(compositionDisplay->getId());
+        LOG_FATAL_IF(!displayId);
+        displaySurface =
+                sp<FramebufferSurface>::make(getHwComposer(), *displayId, bqConsumer,
+                                             state.physical->activeMode->getSize(),
+                                             ui::Size(maxGraphicsWidth, maxGraphicsHeight));
         producer = bqProducer;
     }
 
     LOG_FATAL_IF(!displaySurface);
-    const auto display = setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
-                                                       displaySurface, producer);
+    const auto display = setupNewDisplayDeviceInternal(displayToken, std::move(compositionDisplay),
+                                                       state, displaySurface, producer);
     mDisplays.emplace(displayToken, display);
     if (!state.isVirtual()) {
         dispatchDisplayHotplugEvent(display->getPhysicalId(), true);
@@ -2699,7 +2748,10 @@
     auto display = getDisplayDeviceLocked(displayToken);
     if (display) {
         display->disconnect();
-        if (!display->isVirtual()) {
+
+        if (display->isVirtual()) {
+            releaseVirtualDisplay(display->getVirtualId());
+        } else {
             dispatchDisplayHotplugEvent(display->getPhysicalId(), false);
         }
     }
@@ -2728,17 +2780,26 @@
                                            const DisplayDeviceState& drawingState) {
     const sp<IBinder> currentBinder = IInterface::asBinder(currentState.surface);
     const sp<IBinder> drawingBinder = IInterface::asBinder(drawingState.surface);
+
+    // Recreate the DisplayDevice if the surface or sequence ID changed.
     if (currentBinder != drawingBinder || currentState.sequenceId != drawingState.sequenceId) {
-        // changing the surface is like destroying and recreating the DisplayDevice
         getRenderEngine().cleanFramebufferCache();
+
         if (const auto display = getDisplayDeviceLocked(displayToken)) {
             display->disconnect();
+            if (display->isVirtual()) {
+                releaseVirtualDisplay(display->getVirtualId());
+            }
         }
+
         mDisplays.erase(displayToken);
+
         if (const auto& physical = currentState.physical) {
             getHwComposer().allocatePhysicalDisplay(physical->hwcDisplayId, physical->id);
         }
+
         processDisplayAdded(displayToken, currentState);
+
         if (currentState.physical) {
             const auto display = getDisplayDeviceLocked(displayToken);
             setPowerModeInternal(display, hal::PowerMode::ON);
@@ -4605,7 +4666,8 @@
 
     StringAppendF(&result, " PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset);
     StringAppendF(&result, " FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv);
-    StringAppendF(&result, " MAX_VIRT_DISPLAY_DIM=%" PRIu64, maxVirtualDisplaySize);
+    StringAppendF(&result, " MAX_VIRT_DISPLAY_DIM=%zu",
+                  getHwComposer().getMaxVirtualDisplayDimension());
     StringAppendF(&result, " RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework);
     StringAppendF(&result, " NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64,
                   maxFrameBufferAcquiredBuffers);
@@ -5363,8 +5425,8 @@
                 return NO_ERROR;
             }
             case 1021: { // Disable HWC virtual displays
-                n = data.readInt32();
-                mUseHwcVirtualDisplays = !n;
+                const bool enable = data.readInt32() != 0;
+                static_cast<void>(schedule([this, enable] { enableHalVirtualDisplays(enable); }));
                 return NO_ERROR;
             }
             case 1022: { // Set saturation boost
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4aa047a..b46bd9a 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -228,10 +228,6 @@
     // GL composition.
     static bool useHwcForRgbToYuv;
 
-    // Maximum dimension supported by HWC for virtual display.
-    // Equal to min(max_height, max_width).
-    static uint64_t maxVirtualDisplaySize;
-
     // Controls the number of buffers SurfaceFlinger will allocate for use in
     // FramebufferSurface
     static int64_t maxFrameBufferAcquiredBuffers;
@@ -1084,6 +1080,14 @@
         return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
     }
 
+    // Toggles use of HAL/GPU virtual displays.
+    void enableHalVirtualDisplays(bool);
+
+    // Virtual display lifecycle for ID generation and HAL allocation.
+    VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat, ui::LayerStack)
+            REQUIRES(mStateLock);
+    void releaseVirtualDisplay(VirtualDisplayId);
+
     /*
      * Debugging & dumpsys
      */
@@ -1236,7 +1240,10 @@
     std::unordered_map<PhysicalDisplayId, sp<IBinder>> mPhysicalDisplayTokens
             GUARDED_BY(mStateLock);
 
-    RandomDisplayIdGenerator<GpuVirtualDisplayId> mGpuVirtualDisplayIdGenerator;
+    struct {
+        DisplayIdGenerator<GpuVirtualDisplayId> gpu;
+        std::optional<DisplayIdGenerator<HalVirtualDisplayId>> hal;
+    } mVirtualDisplayIdGenerators;
 
     std::unordered_map<BBinder*, wp<Layer>> mLayersByLocalBinderToken GUARDED_BY(mStateLock);
 
@@ -1259,7 +1266,7 @@
     const std::shared_ptr<TimeStats> mTimeStats;
     const std::unique_ptr<FrameTracer> mFrameTracer;
     const std::unique_ptr<frametimeline::FrameTimeline> mFrameTimeline;
-    bool mUseHwcVirtualDisplays = false;
+
     // If blurs should be enabled on this device.
     bool mSupportsBlur = false;
     // Disable blurs, for debugging
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index e42cf47..fca3bfc 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -105,7 +105,9 @@
 
         mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
         mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
-        setupComposer(0);
+
+        mComposer = new Hwc2::mock::Composer();
+        mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
     }
 
     ~CompositionTest() {
@@ -114,14 +116,6 @@
         ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
     }
 
-    void setupComposer(int virtualDisplayCount) {
-        mComposer = new Hwc2::mock::Composer();
-        EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
-        mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
-
-        Mock::VerifyAndClear(mComposer);
-    }
-
     void setupScheduler() {
         auto eventThread = std::make_unique<mock::EventThread>();
         auto sfEventThread = std::make_unique<mock::EventThread>();
@@ -289,16 +283,16 @@
         const ::testing::TestInfo* const test_info =
                 ::testing::UnitTest::GetInstance()->current_test_info();
 
-        auto ceDisplayArgs =
-                compositionengine::DisplayCreationArgsBuilder()
-                        .setPhysical({DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
-                        .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
-                        .setIsSecure(Derived::IS_SECURE)
-                        .setLayerStackId(DEFAULT_LAYER_STACK)
-                        .setPowerAdvisor(&test->mPowerAdvisor)
-                        .setName(std::string("Injected display for ") +
-                                 test_info->test_case_name() + "." + test_info->name())
-                        .build();
+        auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
+                                     .setId(DEFAULT_DISPLAY_ID)
+                                     .setConnectionType(ui::DisplayConnectionType::Internal)
+                                     .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
+                                     .setIsSecure(Derived::IS_SECURE)
+                                     .setLayerStackId(DEFAULT_LAYER_STACK)
+                                     .setPowerAdvisor(&test->mPowerAdvisor)
+                                     .setName(std::string("Injected display for ") +
+                                              test_info->test_case_name() + "." + test_info->name())
+                                     .build();
 
         auto compositionDisplay =
                 compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp
index 77a3e14..8d4a023 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdGeneratorTest.cpp
@@ -14,76 +14,68 @@
  * limitations under the License.
  */
 
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wextra"
-
 #include <gtest/gtest.h>
+#include <ui/DisplayId.h>
 
+#include <algorithm>
+#include <iterator>
 #include <vector>
 
-#include <ui/DisplayId.h>
 #include "DisplayIdGenerator.h"
 
 namespace android {
 
-template <typename T>
-void testNextId(DisplayIdGenerator<T>& generator) {
-    constexpr int kNumIds = 5;
-    std::vector<T> ids;
-    for (int i = 0; i < kNumIds; i++) {
-        const auto id = generator.nextId();
-        ASSERT_TRUE(id);
-        ids.push_back(*id);
-    }
+template <typename Id>
+void testGenerateId() {
+    DisplayIdGenerator<Id> generator;
+
+    std::vector<std::optional<Id>> ids;
+    std::generate_n(std::back_inserter(ids), 10, [&] { return generator.generateId(); });
 
     // All IDs should be different.
-    for (size_t i = 0; i < kNumIds; i++) {
-        for (size_t j = i + 1; j < kNumIds; j++) {
-            EXPECT_NE(ids[i], ids[j]);
+    for (auto it = ids.begin(); it != ids.end(); ++it) {
+        EXPECT_TRUE(*it);
+
+        for (auto dup = it + 1; dup != ids.end(); ++dup) {
+            EXPECT_NE(*it, *dup);
         }
     }
 }
 
-TEST(DisplayIdGeneratorTest, nextIdGpuVirtual) {
-    RandomDisplayIdGenerator<GpuVirtualDisplayId> generator;
-    testNextId(generator);
+TEST(DisplayIdGeneratorTest, generateGpuVirtualDisplayId) {
+    testGenerateId<GpuVirtualDisplayId>();
 }
 
-TEST(DisplayIdGeneratorTest, nextIdHalVirtual) {
-    RandomDisplayIdGenerator<HalVirtualDisplayId> generator;
-    testNextId(generator);
+TEST(DisplayIdGeneratorTest, generateHalVirtualDisplayId) {
+    testGenerateId<HalVirtualDisplayId>();
 }
 
-TEST(DisplayIdGeneratorTest, markUnused) {
+TEST(DisplayIdGeneratorTest, releaseId) {
     constexpr size_t kMaxIdsCount = 5;
-    RandomDisplayIdGenerator<GpuVirtualDisplayId> generator(kMaxIdsCount);
+    DisplayIdGenerator<GpuVirtualDisplayId> generator(kMaxIdsCount);
 
-    const auto id = generator.nextId();
+    const auto id = generator.generateId();
     EXPECT_TRUE(id);
 
-    for (int i = 1; i < kMaxIdsCount; i++) {
-        EXPECT_TRUE(generator.nextId());
+    for (size_t i = 1; i < kMaxIdsCount; i++) {
+        EXPECT_TRUE(generator.generateId());
     }
 
-    EXPECT_FALSE(generator.nextId());
+    EXPECT_FALSE(generator.generateId());
 
-    generator.markUnused(*id);
-    EXPECT_TRUE(generator.nextId());
+    generator.releaseId(*id);
+    EXPECT_TRUE(generator.generateId());
 }
 
 TEST(DisplayIdGeneratorTest, maxIdsCount) {
     constexpr size_t kMaxIdsCount = 5;
-    RandomDisplayIdGenerator<GpuVirtualDisplayId> generator(kMaxIdsCount);
+    DisplayIdGenerator<GpuVirtualDisplayId> generator(kMaxIdsCount);
 
-    for (int i = 0; i < kMaxIdsCount; i++) {
-        EXPECT_TRUE(generator.nextId());
+    for (size_t i = 0; i < kMaxIdsCount; i++) {
+        EXPECT_TRUE(generator.generateId());
     }
 
-    EXPECT_FALSE(generator.nextId());
+    EXPECT_FALSE(generator.generateId());
 }
 
 } // namespace android
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wextra"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 359e555..60b0f53 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -41,9 +41,6 @@
     mFlinger.mutableUseColorManagement() = false;
     mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
 
-    // Default to using HWC virtual displays
-    mFlinger.mutableUseHwcVirtualDisplays() = true;
-
     mFlinger.setCreateBufferQueueFunction([](auto, auto, auto) {
         ADD_FAILURE() << "Unexpected request to create a buffer queue.";
     });
@@ -85,10 +82,17 @@
 }
 
 void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) {
+    if (mComposer) {
+        // If reinjecting, disable first to prevent the enable below from being a no-op.
+        mFlinger.enableHalVirtualDisplays(false);
+    }
+
     mComposer = new Hwc2::mock::Composer();
-    EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
     mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
 
+    EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+    mFlinger.enableHalVirtualDisplays(true);
+
     Mock::VerifyAndClear(mComposer);
 }
 
@@ -135,18 +139,21 @@
     EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64));
     EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(AnyNumber());
 
-    auto compositionDisplay = compositionengine::impl::
-            createDisplay(mFlinger.getCompositionEngine(),
-                          compositionengine::DisplayCreationArgsBuilder()
-                                  .setPhysical(
-                                          {DEFAULT_DISPLAY_ID, ui::DisplayConnectionType::Internal})
-                                  .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
-                                  .setPowerAdvisor(&mPowerAdvisor)
-                                  .build());
+    constexpr auto kConnectionType = ui::DisplayConnectionType::Internal;
+    constexpr bool kIsPrimary = true;
 
-    auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay,
-                                              ui::DisplayConnectionType::Internal,
-                                              DEFAULT_DISPLAY_HWC_DISPLAY_ID, true /* isPrimary */);
+    auto compositionDisplay =
+            compositionengine::impl::createDisplay(mFlinger.getCompositionEngine(),
+                                                   compositionengine::DisplayCreationArgsBuilder()
+                                                           .setId(DEFAULT_DISPLAY_ID)
+                                                           .setConnectionType(kConnectionType)
+                                                           .setPixels({DEFAULT_DISPLAY_WIDTH,
+                                                                       DEFAULT_DISPLAY_HEIGHT})
+                                                           .setPowerAdvisor(&mPowerAdvisor)
+                                                           .build());
+
+    auto injector = FakeDisplayDeviceInjector(mFlinger, compositionDisplay, kConnectionType,
+                                              DEFAULT_DISPLAY_HWC_DISPLAY_ID, kIsPrimary);
 
     injector.setNativeWindow(mNativeWindow);
     if (injectExtra) {
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index d68fff6..6ce281d 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -263,40 +263,23 @@
 
     static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
         auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder();
-        if (auto displayId = PhysicalDisplayId::tryCast(DISPLAY_ID::get())) {
-            ceDisplayArgs.setPhysical({*displayId, ui::DisplayConnectionType::Internal});
-        } else {
-            // We turn off the use of HwcVirtualDisplays, to prevent Composition Engine
-            // from calling into HWComposer. This way all virtual displays will get
-            // a GpuVirtualDisplayId, even if we are in the HwcVirtualDisplayVariant.
-            // In this case we later override it by calling display.setDisplayIdForTesting().
-            ceDisplayArgs.setUseHwcVirtualDisplays(false);
+        ceDisplayArgs.setId(DISPLAY_ID::get())
+                .setPixels({WIDTH, HEIGHT})
+                .setPowerAdvisor(&test->mPowerAdvisor);
 
-            GpuVirtualDisplayId desiredDisplayId = GpuVirtualDisplayId::tryCast(DISPLAY_ID::get())
-                                                           .value_or(GpuVirtualDisplayId(0));
-
-            ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
-                    .WillByDefault(Return(desiredDisplayId));
-
-            auto& generator = test->mFlinger.gpuVirtualDisplayIdGenerator();
-            ceDisplayArgs.setGpuVirtualDisplayIdGenerator(generator);
+        const auto connectionType = CONNECTION_TYPE::value;
+        if (connectionType) {
+            ceDisplayArgs.setConnectionType(*connectionType);
         }
-        ceDisplayArgs.setPixels({WIDTH, HEIGHT}).setPowerAdvisor(&test->mPowerAdvisor);
 
         auto compositionDisplay =
                 compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
                                                        ceDisplayArgs.build());
 
-        if (HalVirtualDisplayId::tryCast(DISPLAY_ID::get())) {
-            // CompositionEngine has assigned a placeholder GpuVirtualDisplayId and we need to
-            // override it with the correct HalVirtualDisplayId.
-            compositionDisplay->setDisplayIdForTesting(DISPLAY_ID::get());
-        }
-
         auto injector =
                 TestableSurfaceFlinger::FakeDisplayDeviceInjector(test->mFlinger,
                                                                   compositionDisplay,
-                                                                  CONNECTION_TYPE::value,
+                                                                  connectionType,
                                                                   HWC_DISPLAY_ID_OPT::value,
                                                                   static_cast<bool>(PRIMARY));
 
@@ -404,8 +387,8 @@
                 ::testing::UnitTest::GetInstance()->current_test_info();
 
         auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
-                                     .setPhysical({DisplayVariant::DISPLAY_ID::get(),
-                                                   PhysicalDisplay::CONNECTION_TYPE})
+                                     .setId(DisplayVariant::DISPLAY_ID::get())
+                                     .setConnectionType(PhysicalDisplay::CONNECTION_TYPE)
                                      .setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT})
                                      .setIsSecure(static_cast<bool>(DisplayVariant::SECURE))
                                      .setPowerAdvisor(&test->mPowerAdvisor)
@@ -558,17 +541,13 @@
         const ::testing::TestInfo* const test_info =
                 ::testing::UnitTest::GetInstance()->current_test_info();
 
-        ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
-                .WillByDefault(Return(Base::DISPLAY_ID::get()));
-
         auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
+                                     .setId(Base::DISPLAY_ID::get())
                                      .setPixels({Base::WIDTH, Base::HEIGHT})
                                      .setIsSecure(static_cast<bool>(Base::SECURE))
                                      .setPowerAdvisor(&test->mPowerAdvisor)
                                      .setName(std::string("Injected display for ") +
                                               test_info->test_case_name() + "." + test_info->name())
-                                     .setGpuVirtualDisplayIdGenerator(
-                                             test->mFlinger.gpuVirtualDisplayIdGenerator())
                                      .build();
 
         return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
@@ -610,35 +589,22 @@
         const ::testing::TestInfo* const test_info =
                 ::testing::UnitTest::GetInstance()->current_test_info();
 
-        // In order to prevent compostition engine calling into HWComposer, we
-        // 1. turn off the use of HWC virtual displays,
-        // 2. provide a GpuVirtualDisplayIdGenerator which always returns some fake ID
-        // 3. override the ID by calling setDisplayIdForTesting()
-
-        ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
-                .WillByDefault(Return(GpuVirtualDisplayId(0)));
-
+        const auto displayId = Base::DISPLAY_ID::get();
         auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
-                                     .setUseHwcVirtualDisplays(false)
+                                     .setId(displayId)
                                      .setPixels({Base::WIDTH, Base::HEIGHT})
                                      .setIsSecure(static_cast<bool>(Base::SECURE))
                                      .setPowerAdvisor(&test->mPowerAdvisor)
                                      .setName(std::string("Injected display for ") +
                                               test_info->test_case_name() + "." + test_info->name())
-                                     .setGpuVirtualDisplayIdGenerator(
-                                             test->mFlinger.gpuVirtualDisplayIdGenerator())
                                      .build();
 
         auto compositionDisplay =
                 compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
                                                        ceDisplayArgs);
-        compositionDisplay->setDisplayIdForTesting(Base::DISPLAY_ID::get());
 
         // Insert display data so that the HWC thinks it created the virtual display.
-        if (const auto displayId = Base::DISPLAY_ID::get();
-            HalVirtualDisplayId::tryCast(displayId)) {
-            test->mFlinger.mutableHwcDisplayData().try_emplace(displayId);
-        }
+        test->mFlinger.mutableHwcDisplayData().try_emplace(displayId);
 
         return compositionDisplay;
     }
@@ -649,8 +615,8 @@
     }
 
     static void setupHwcVirtualDisplayCreationCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _))
-                .WillOnce(DoAll(SetArgPointee<3>(Self::HWC_DISPLAY_ID), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _, _))
+                .WillOnce(DoAll(SetArgPointee<4>(Self::HWC_DISPLAY_ID), Return(Error::NONE)));
         EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
     }
 };
diff --git a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
index dec0ff5..010c675 100644
--- a/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FpsReporterTest.cpp
@@ -76,11 +76,9 @@
     static constexpr int32_t PRIORITY_UNSET = -1;
 
     void setupScheduler();
-    void setupComposer(uint32_t virtualDisplayCount);
     sp<BufferStateLayer> createBufferStateLayer(LayerMetadata metadata);
 
     TestableSurfaceFlinger mFlinger;
-    Hwc2::mock::Composer* mComposer = nullptr;
     mock::FrameTimeline mFrameTimeline =
             mock::FrameTimeline(std::make_shared<impl::TimeStats>(), 0);
 
@@ -103,7 +101,8 @@
     ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
 
     setupScheduler();
-    setupComposer(0);
+    mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
+
     mFpsListener = new TestableFpsListener();
 }
 
@@ -145,19 +144,11 @@
                             std::move(eventThread), std::move(sfEventThread));
 }
 
-void FpsReporterTest::setupComposer(uint32_t virtualDisplayCount) {
-    mComposer = new Hwc2::mock::Composer();
-    EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
-    mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
-
-    Mock::VerifyAndClear(mComposer);
-}
-
 namespace {
 
 TEST_F(FpsReporterTest, callsListeners) {
     mParent = createBufferStateLayer();
-    const constexpr int32_t kTaskId = 12;
+    constexpr int32_t kTaskId = 12;
     LayerMetadata targetMetadata;
     targetMetadata.setInt32(METADATA_TASK_ID, kTaskId);
     mTarget = createBufferStateLayer(targetMetadata);
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 6b82170..138d5cb 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -78,7 +78,6 @@
     const std::string kMetadata2Name = "com.example.metadata.2";
     constexpr bool kMetadata2Mandatory = true;
 
-    EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
     EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
     EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
             .WillOnce(DoAll(SetArgPointee<0>(std::vector<hal::LayerGenericMetadataKey>{
@@ -101,7 +100,6 @@
 }
 
 TEST_F(HWComposerSetConfigurationTest, handlesUnsupportedCallToGetLayerGenericMetadataKeys) {
-    EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
     EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
     EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
             .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
@@ -176,4 +174,4 @@
 }
 
 } // namespace
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
index 9c6ad06..fd3e564 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -60,7 +60,6 @@
     static constexpr int32_t PRIORITY_UNSET = -1;
 
     void setupScheduler();
-    void setupComposer(uint32_t virtualDisplayCount);
     sp<BufferQueueLayer> createBufferQueueLayer();
     sp<BufferStateLayer> createBufferStateLayer();
     sp<EffectLayer> createEffectLayer();
@@ -69,7 +68,6 @@
     void commitTransaction(Layer* layer);
 
     TestableSurfaceFlinger mFlinger;
-    Hwc2::mock::Composer* mComposer = nullptr;
 
     sp<Client> mClient;
     sp<Layer> mParent;
@@ -83,7 +81,7 @@
     ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
 
     setupScheduler();
-    setupComposer(0);
+    mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
 }
 
 RefreshRateSelectionTest::~RefreshRateSelectionTest() {
@@ -147,14 +145,6 @@
                             std::move(eventThread), std::move(sfEventThread));
 }
 
-void RefreshRateSelectionTest::setupComposer(uint32_t virtualDisplayCount) {
-    mComposer = new Hwc2::mock::Composer();
-    EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
-    mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
-
-    Mock::VerifyAndClear(mComposer);
-}
-
 namespace {
 /* ------------------------------------------------------------------------
  * Test cases
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index c088ddc..46ef750 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -118,14 +118,12 @@
     SetFrameRateTest();
 
     void setupScheduler();
-    void setupComposer(uint32_t virtualDisplayCount);
 
     void addChild(sp<Layer> layer, sp<Layer> child);
     void removeChild(sp<Layer> layer, sp<Layer> child);
     void commitTransaction();
 
     TestableSurfaceFlinger mFlinger;
-    Hwc2::mock::Composer* mComposer = nullptr;
     mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
 
     std::vector<sp<Layer>> mLayers;
@@ -139,10 +137,11 @@
     mFlinger.mutableUseFrameRateApi() = true;
 
     setupScheduler();
-    setupComposer(0);
 
+    mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
     mFlinger.mutableEventQueue().reset(mMessageQueue);
 }
+
 void SetFrameRateTest::addChild(sp<Layer> layer, sp<Layer> child) {
     layer.get()->addChild(child.get());
 }
@@ -184,14 +183,6 @@
                             /*hasMultipleModes*/ true);
 }
 
-void SetFrameRateTest::setupComposer(uint32_t virtualDisplayCount) {
-    mComposer = new Hwc2::mock::Composer();
-    EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
-    mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
-
-    Mock::VerifyAndClear(mComposer);
-}
-
 namespace {
 /* ------------------------------------------------------------------------
  * Test cases
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index d004b9d..f95b878 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -42,7 +42,6 @@
 #include "SurfaceInterceptor.h"
 #include "TestableScheduler.h"
 #include "mock/DisplayHardware/MockComposer.h"
-#include "mock/MockDisplayIdGenerator.h"
 #include "mock/MockFrameTimeline.h"
 #include "mock/MockFrameTracer.h"
 
@@ -185,9 +184,6 @@
 
     SurfaceFlinger* flinger() { return mFlinger.get(); }
     TestableScheduler* scheduler() { return mScheduler; }
-    mock::DisplayIdGenerator<GpuVirtualDisplayId>& gpuVirtualDisplayIdGenerator() {
-        return mGpuVirtualDisplayIdGenerator;
-    }
 
     // Extend this as needed for accessing SurfaceFlinger private (and public)
     // functions.
@@ -308,6 +304,8 @@
         return mFlinger->destroyDisplay(displayToken);
     }
 
+    void enableHalVirtualDisplays(bool enable) { mFlinger->enableHalVirtualDisplays(enable); }
+
     auto setupNewDisplayDeviceInternal(
             const wp<IBinder>& displayToken,
             std::shared_ptr<compositionengine::Display> compositionDisplay,
@@ -436,7 +434,6 @@
     auto& mutablePhysicalDisplayTokens() { return mFlinger->mPhysicalDisplayTokens; }
     auto& mutableTexturePool() { return mFlinger->mTexturePool; }
     auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
-    auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
     auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; }
     auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; }
 
@@ -775,7 +772,6 @@
     surfaceflinger::test::Factory mFactory;
     sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
     TestableScheduler* mScheduler = nullptr;
-    mock::DisplayIdGenerator<GpuVirtualDisplayId> mGpuVirtualDisplayIdGenerator;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
index 25001d3..546bc4a 100644
--- a/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionFrameTracerTest.cpp
@@ -45,7 +45,7 @@
                 ::testing::UnitTest::GetInstance()->current_test_info();
         ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
         setupScheduler();
-        setupComposer(0);
+        mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
     }
 
     ~TransactionFrameTracerTest() {
@@ -91,17 +91,9 @@
                                 std::move(eventThread), std::move(sfEventThread));
     }
 
-    void setupComposer(uint32_t virtualDisplayCount) {
-        mComposer = new Hwc2::mock::Composer();
-        EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
-        mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
-
-        Mock::VerifyAndClear(mComposer);
-    }
-
     TestableSurfaceFlinger mFlinger;
-    Hwc2::mock::Composer* mComposer = nullptr;
     renderengine::mock::RenderEngine mRenderEngine;
+
     FenceToFenceTimeMap fenceFactory;
     client_cache_t mClientCache;
 
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
index b7917aa..c1123cd 100644
--- a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -45,7 +45,7 @@
                 ::testing::UnitTest::GetInstance()->current_test_info();
         ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
         setupScheduler();
-        setupComposer(0);
+        mFlinger.setupComposer(std::make_unique<Hwc2::mock::Composer>());
     }
 
     ~TransactionSurfaceFrameTest() {
@@ -91,17 +91,9 @@
                                 std::move(eventThread), std::move(sfEventThread));
     }
 
-    void setupComposer(uint32_t virtualDisplayCount) {
-        mComposer = new Hwc2::mock::Composer();
-        EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
-        mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
-
-        Mock::VerifyAndClear(mComposer);
-    }
-
     TestableSurfaceFlinger mFlinger;
-    Hwc2::mock::Composer* mComposer = nullptr;
     renderengine::mock::RenderEngine mRenderEngine;
+
     FenceToFenceTimeMap fenceFactory;
     client_cache_t mClientCache;
 
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 1ba3c0f..cb3bd73 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -54,7 +54,8 @@
     MOCK_METHOD0(resetCommands, void());
     MOCK_METHOD0(executeCommands, Error());
     MOCK_METHOD0(getMaxVirtualDisplayCount, uint32_t());
-    MOCK_METHOD4(createVirtualDisplay, Error(uint32_t, uint32_t, PixelFormat*, Display*));
+    MOCK_METHOD5(createVirtualDisplay,
+                 Error(uint32_t, uint32_t, PixelFormat*, std::optional<Display>, Display*));
     MOCK_METHOD1(destroyVirtualDisplay, Error(Display));
     MOCK_METHOD1(acceptDisplayChanges, Error(Display));
     MOCK_METHOD2(createLayer, Error(Display, Layer* outLayer));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDisplayIdGenerator.h b/services/surfaceflinger/tests/unittests/mock/MockDisplayIdGenerator.h
deleted file mode 100644
index cfc37ea..0000000
--- a/services/surfaceflinger/tests/unittests/mock/MockDisplayIdGenerator.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <gmock/gmock.h>
-
-#include "DisplayIdGenerator.h"
-
-namespace android::mock {
-
-template <typename T>
-class DisplayIdGenerator : public android::DisplayIdGenerator<T> {
-public:
-    // Explicit default instantiation is recommended.
-    DisplayIdGenerator() = default;
-    virtual ~DisplayIdGenerator() = default;
-
-    MOCK_METHOD0(nextId, std::optional<T>());
-    MOCK_METHOD1(markUnused, void(T));
-};
-
-} // namespace android::mock