Merge "Cleanup and send janktype as a bitmask to perfetto"
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index f195399..d7f25e1 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -28,8 +28,23 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <stddef.h>
 #include <jni.h>
 
+#ifndef __ANDROID__
+    // Value copied from 'bionic/libc/include/android/api-level.h' which is not available on
+    // non Android systems. It is set to 10000 which is same as __ANDROID_API_FUTURE__ value.
+    #ifndef __ANDROID_API__
+        #define __ANDROID_API__ 10000
+    #endif
+
+    // Value copied from 'bionic/libc/include/android/versioning.h' which is not available on
+    // non Android systems
+    #ifndef __INTRODUCED_IN
+        #define __INTRODUCED_IN(api_level)
+    #endif
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -152,8 +167,6 @@
  */
 int AndroidBitmap_unlockPixels(JNIEnv* env, jobject jbitmap);
 
-#if __ANDROID_API__ >= 30
-
 // Note: these values match android.graphics.Bitmap#compressFormat.
 
 /**
@@ -203,6 +216,8 @@
                                                 const void* data,
                                                 size_t size) __INTRODUCED_IN(30);
 
+#if __ANDROID_API__ >= 30
+
 /**
  *  Compress |pixels| as described by |info|.
  *
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
index 98401f7..c7a8939 100644
--- a/include/android/imagedecoder.h
+++ b/include/android/imagedecoder.h
@@ -51,6 +51,20 @@
 #include <android/rect.h>
 #include <stdint.h>
 
+#ifndef __ANDROID__
+    // Value copied from 'bionic/libc/include/android/api-level.h' which is not available on
+    // non Android systems. It is set to 10000 which is same as __ANDROID_API_FUTURE__ value.
+    #ifndef __ANDROID_API__
+        #define __ANDROID_API__ 10000
+    #endif
+
+    // Value copied from 'bionic/libc/include/android/versioning.h' which is not available on
+    // non Android systems
+    #ifndef __INTRODUCED_IN
+        #define __INTRODUCED_IN(api_level)
+    #endif
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index 53871f2..6b52c0a 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -259,10 +259,13 @@
     const char* getMessage() const { return AStatus_getMessage(get()); }
 
     std::string getDescription() const {
-        const char* cStr = AStatus_getDescription(get());
-        std::string ret = cStr;
-        AStatus_deleteDescription(cStr);
-        return ret;
+        if (__builtin_available(android 30, *)) {
+            const char* cStr = AStatus_getDescription(get());
+            std::string ret = cStr;
+            AStatus_deleteDescription(cStr);
+            return ret;
+        }
+        return "(not available)";
     }
 
     /**
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index a1102e2..05eb64b 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -247,7 +247,7 @@
     // ourselves. The defaults are harmless.
     AIBinder_Class_setOnDump(clazz, ICInterfaceData::onDump);
 #ifdef HAS_BINDER_SHELL_COMMAND
-    if (AIBinder_Class_setHandleShellCommand != nullptr) {
+    if (__builtin_available(android 30, *)) {
         AIBinder_Class_setHandleShellCommand(clazz, ICInterfaceData::handleShellCommand);
     }
 #endif
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 6636a41..2277148 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -51,14 +51,27 @@
 
     binder_status_t writeToParcel(AParcel* parcel) const {
         RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
-        RETURN_ON_FAILURE(AParcel_writeInt32(parcel, AParcel_getDataSize(this->mParcel.get())));
-        RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0,
-                                             AParcel_getDataSize(this->mParcel.get())));
+        if (__builtin_available(android 31, *)) {
+            int32_t size = AParcel_getDataSize(this->mParcel.get());
+            RETURN_ON_FAILURE(AParcel_writeInt32(parcel, size));
+        } else {
+            return STATUS_INVALID_OPERATION;
+        }
+        if (__builtin_available(android 31, *)) {
+            int32_t size = AParcel_getDataSize(this->mParcel.get());
+            RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0, size));
+        } else {
+            return STATUS_INVALID_OPERATION;
+        }
         return STATUS_OK;
     }
 
     binder_status_t readFromParcel(const AParcel* parcel) {
-        AParcel_reset(mParcel.get());
+        if (__builtin_available(android 31, *)) {
+            AParcel_reset(mParcel.get());
+        } else {
+            return STATUS_INVALID_OPERATION;
+        }
 
         RETURN_ON_FAILURE(AParcel_readInt32(parcel, &this->mStability));
         int32_t dataSize;
@@ -74,7 +87,11 @@
             return STATUS_BAD_VALUE;
         }
 
-        status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
+        if (__builtin_available(android 31, *)) {
+            status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
+        } else {
+            status = STATUS_INVALID_OPERATION;
+        }
         if (status != STATUS_OK) {
             return status;
         }
@@ -86,7 +103,11 @@
         if (this->mStability > T::_aidl_stability) {
             return STATUS_BAD_VALUE;
         }
-        AParcel_reset(mParcel.get());
+        if (__builtin_available(android 31, *)) {
+            AParcel_reset(mParcel.get());
+        } else {
+            return STATUS_INVALID_OPERATION;
+        }
         AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
         p.writeToParcel(mParcel.get());
         return STATUS_OK;
@@ -96,9 +117,13 @@
     binder_status_t getParcelable(std::optional<T>* ret) const {
         const std::string parcelableDesc(T::descriptor);
         AParcel_setDataPosition(mParcel.get(), 0);
-        if (AParcel_getDataSize(mParcel.get()) == 0) {
-            *ret = std::nullopt;
-            return STATUS_OK;
+        if (__builtin_available(android 31, *)) {
+            if (AParcel_getDataSize(mParcel.get()) == 0) {
+                *ret = std::nullopt;
+                return STATUS_OK;
+            }
+        } else {
+            return STATUS_INVALID_OPERATION;
         }
         std::string parcelableDescInParcel;
         binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
@@ -115,7 +140,11 @@
         return STATUS_OK;
     }
 
-    void reset() { AParcel_reset(mParcel.get()); }
+    void reset() {
+        if (__builtin_available(android 31, *)) {
+            AParcel_reset(mParcel.get());
+        }
+    }
 
     inline bool operator!=(const AParcelableHolder& rhs) const { return this != &rhs; }
     inline bool operator<(const AParcelableHolder& rhs) const { return this < &rhs; }
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 93c3f32..ab67017 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -1120,7 +1120,6 @@
 // @END-PRIMITIVE-READ-WRITE
 
 #endif  //__ANDROID_API__ >= 29
-#if __ANDROID_API__ >= 31
 /**
  * Reset the parcel to the initial status.
  *
@@ -1166,7 +1165,6 @@
  * \return A parcel which is not related to any IBinder objects.
  */
 AParcel* AParcel_create() __INTRODUCED_IN(31);
-#endif  //__ANDROID_API__ >= 31
 __END_DECLS
 
 /** @} */
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 07e5d86..3011dcc 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -28,6 +28,7 @@
     // TODO(b/153609531): remove when no longer needed.
     native_bridge_supported: true,
     min_sdk_version: "29",
+    host_supported: true,
 }
 
 ndk_library {
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index 0e74c63..d69c7ae 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -79,6 +79,7 @@
     name: "librenderengine_skia_sources",
     srcs: [
         "skia/AutoBackendTexture.cpp",
+        "skia/ColorSpaces.cpp",
         "skia/SkiaRenderEngine.cpp",
         "skia/SkiaGLRenderEngine.cpp",
         "skia/debug/CaptureTimer.cpp",
diff --git a/libs/renderengine/skia/AutoBackendTexture.cpp b/libs/renderengine/skia/AutoBackendTexture.cpp
index 2ffb547..c535597 100644
--- a/libs/renderengine/skia/AutoBackendTexture.cpp
+++ b/libs/renderengine/skia/AutoBackendTexture.cpp
@@ -20,8 +20,7 @@
 #define LOG_TAG "RenderEngine"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include <utils/Trace.h>
-
+#include "ColorSpaces.h"
 #include "log/log_main.h"
 #include "utils/Trace.h"
 
@@ -29,47 +28,6 @@
 namespace renderengine {
 namespace skia {
 
-// Converts an android dataspace to a supported SkColorSpace
-// Supported dataspaces are
-// 1. sRGB
-// 2. Display P3
-// 3. BT2020 PQ
-// 4. BT2020 HLG
-// Unknown primaries are mapped to BT709, and unknown transfer functions
-// are mapped to sRGB.
-static sk_sp<SkColorSpace> toSkColorSpace(ui::Dataspace dataspace) {
-    skcms_Matrix3x3 gamut;
-    switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
-        case HAL_DATASPACE_STANDARD_BT709:
-            gamut = SkNamedGamut::kSRGB;
-            break;
-        case HAL_DATASPACE_STANDARD_BT2020:
-            gamut = SkNamedGamut::kRec2020;
-            break;
-        case HAL_DATASPACE_STANDARD_DCI_P3:
-            gamut = SkNamedGamut::kDisplayP3;
-            break;
-        default:
-            ALOGV("Unsupported Gamut: %d, defaulting to sRGB", dataspace);
-            gamut = SkNamedGamut::kSRGB;
-            break;
-    }
-
-    switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
-        case HAL_DATASPACE_TRANSFER_LINEAR:
-            return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut);
-        case HAL_DATASPACE_TRANSFER_SRGB:
-            return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
-        case HAL_DATASPACE_TRANSFER_ST2084:
-            return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
-        case HAL_DATASPACE_TRANSFER_HLG:
-            return SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut);
-        default:
-            ALOGV("Unsupported Gamma: %d, defaulting to sRGB transfer", dataspace);
-            return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
-    }
-}
-
 AutoBackendTexture::AutoBackendTexture(GrDirectContext* context, AHardwareBuffer* buffer,
                                        bool isRender) {
     ATRACE_CALL();
diff --git a/libs/renderengine/skia/ColorSpaces.cpp b/libs/renderengine/skia/ColorSpaces.cpp
new file mode 100644
index 0000000..ff4d348
--- /dev/null
+++ b/libs/renderengine/skia/ColorSpaces.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#include "ColorSpaces.h"
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+sk_sp<SkColorSpace> toSkColorSpace(ui::Dataspace dataspace) {
+    skcms_Matrix3x3 gamut;
+    switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
+        case HAL_DATASPACE_STANDARD_BT709:
+            gamut = SkNamedGamut::kSRGB;
+            break;
+        case HAL_DATASPACE_STANDARD_BT2020:
+            gamut = SkNamedGamut::kRec2020;
+            break;
+        case HAL_DATASPACE_STANDARD_DCI_P3:
+            gamut = SkNamedGamut::kDisplayP3;
+            break;
+        default:
+            gamut = SkNamedGamut::kSRGB;
+            break;
+    }
+
+    switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) {
+        case HAL_DATASPACE_TRANSFER_LINEAR:
+            return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut);
+        case HAL_DATASPACE_TRANSFER_SRGB:
+            return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
+        case HAL_DATASPACE_TRANSFER_ST2084:
+            return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut);
+        case HAL_DATASPACE_TRANSFER_HLG:
+            return SkColorSpace::MakeRGB(SkNamedTransferFn::kHLG, gamut);
+        default:
+            return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut);
+    }
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/skia/ColorSpaces.h b/libs/renderengine/skia/ColorSpaces.h
new file mode 100644
index 0000000..2cbdeb8
--- /dev/null
+++ b/libs/renderengine/skia/ColorSpaces.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 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 "SkColorSpace.h"
+#include "ui/GraphicTypes.h"
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+// Converts an android dataspace to a supported SkColorSpace
+// Supported dataspaces are
+// 1. sRGB
+// 2. Display P3
+// 3. BT2020 PQ
+// 4. BT2020 HLG
+// Unknown primaries are mapped to BT709, and unknown transfer functions
+// are mapped to sRGB.
+sk_sp<SkColorSpace> toSkColorSpace(ui::Dataspace dataspace);
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index d9495a9..dc04f69 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -30,6 +30,7 @@
 #include <SkColorSpace.h>
 #include <SkImage.h>
 #include <SkImageFilters.h>
+#include <SkRegion.h>
 #include <SkShadowUtils.h>
 #include <SkSurface.h>
 #include <gl/GrGLInterface.h>
@@ -43,6 +44,7 @@
 #include <memory>
 
 #include "../gl/GLExtensions.h"
+#include "ColorSpaces.h"
 #include "SkBlendMode.h"
 #include "SkImageInfo.h"
 #include "filters/BlurFilter.h"
@@ -281,6 +283,44 @@
     if (args.supportsBackgroundBlur) {
         mBlurFilter = new BlurFilter();
     }
+    mCapture = std::make_unique<SkiaCapture>();
+}
+
+SkiaGLRenderEngine::~SkiaGLRenderEngine() {
+    std::lock_guard<std::mutex> lock(mRenderingMutex);
+    mRuntimeEffects.clear();
+    mProtectedTextureCache.clear();
+    mTextureCache.clear();
+
+    if (mBlurFilter) {
+        delete mBlurFilter;
+    }
+
+    mCapture = nullptr;
+
+    mGrContext->flushAndSubmit(true);
+    mGrContext->abandonContext();
+
+    if (mProtectedGrContext) {
+        mProtectedGrContext->flushAndSubmit(true);
+        mProtectedGrContext->abandonContext();
+    }
+
+    if (mPlaceholderSurface != EGL_NO_SURFACE) {
+        eglDestroySurface(mEGLDisplay, mPlaceholderSurface);
+    }
+    if (mProtectedPlaceholderSurface != EGL_NO_SURFACE) {
+        eglDestroySurface(mEGLDisplay, mProtectedPlaceholderSurface);
+    }
+    if (mEGLContext != EGL_NO_CONTEXT) {
+        eglDestroyContext(mEGLDisplay, mEGLContext);
+    }
+    if (mProtectedEGLContext != EGL_NO_CONTEXT) {
+        eglDestroyContext(mEGLDisplay, mProtectedEGLContext);
+    }
+    eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+    eglTerminate(mEGLDisplay);
+    eglReleaseThread();
 }
 
 bool SkiaGLRenderEngine::supportsProtectedContent() const {
@@ -298,6 +338,7 @@
             useProtectedContext ? mProtectedPlaceholderSurface : mPlaceholderSurface;
     const EGLContext context = useProtectedContext ? mProtectedEGLContext : mEGLContext;
     const bool success = eglMakeCurrent(mEGLDisplay, surface, surface, context) == EGL_TRUE;
+
     if (success) {
         mInProtectedContext = useProtectedContext;
     }
@@ -450,6 +491,7 @@
                                         const bool useFramebufferCache,
                                         base::unique_fd&& bufferFence, base::unique_fd* drawFence) {
     ATRACE_NAME("SkiaGL::drawLayers");
+
     std::lock_guard<std::mutex> lock(mRenderingMutex);
     if (layers.empty()) {
         ALOGV("Drawing empty layer stack");
@@ -488,7 +530,7 @@
     if (surfaceTextureRef == nullptr || surfaceTextureRef->getTexture() == nullptr) {
         surfaceTextureRef = std::make_shared<AutoBackendTexture::LocalRef>();
         surfaceTextureRef->setTexture(
-                new AutoBackendTexture(mGrContext.get(), buffer->toAHardwareBuffer(), true));
+                new AutoBackendTexture(grContext.get(), buffer->toAHardwareBuffer(), true));
         if (useFramebufferCache) {
             ALOGD("Adding to cache");
             cache.insert({buffer->getId(), surfaceTextureRef});
@@ -498,10 +540,10 @@
     sk_sp<SkSurface> surface =
             surfaceTextureRef->getTexture()->getOrCreateSurface(mUseColorManagement
                                                                         ? display.outputDataspace
-                                                                        : ui::Dataspace::SRGB,
-                                                                mGrContext.get());
+                                                                        : ui::Dataspace::UNKNOWN,
+                                                                grContext.get());
 
-    SkCanvas* canvas = mCapture.tryCapture(surface.get());
+    SkCanvas* canvas = mCapture->tryCapture(surface.get());
     if (canvas == nullptr) {
         ALOGE("Cannot acquire canvas from Skia.");
         return BAD_VALUE;
@@ -510,7 +552,7 @@
     canvas->clear(SK_ColorTRANSPARENT);
     canvas->save();
 
-    if (mCapture.isCaptureRunning()) {
+    if (mCapture->isCaptureRunning()) {
         // Record display settings when capture is running.
         std::stringstream displaySettings;
         PrintTo(display, &displaySettings);
@@ -546,10 +588,33 @@
     canvas->rotate(toDegrees(display.orientation));
     canvas->translate(-clipWidth / 2, -clipHeight / 2);
     canvas->translate(-display.clip.left, -display.clip.top);
+
+    // TODO: clearRegion was required for SurfaceView when a buffer is not yet available but the
+    // view is still on-screen. The clear region could be re-specified as a black color layer,
+    // however.
+    if (!display.clearRegion.isEmpty()) {
+        size_t numRects = 0;
+        Rect const* rects = display.clearRegion.getArray(&numRects);
+        SkIRect skRects[numRects];
+        for (int i = 0; i < numRects; ++i) {
+            skRects[i] =
+                    SkIRect::MakeLTRB(rects[i].left, rects[i].top, rects[i].right, rects[i].bottom);
+        }
+        SkRegion clearRegion;
+        SkPaint paint;
+        sk_sp<SkShader> shader =
+                SkShaders::Color(SkColor4f{.fR = 0., .fG = 0., .fB = 0., .fA = 1.0},
+                                 toSkColorSpace(mUseColorManagement ? display.outputDataspace
+                                                                    : ui::Dataspace::UNKNOWN));
+        paint.setShader(shader);
+        clearRegion.setRects(skRects, numRects);
+        canvas->drawRegion(clearRegion, paint);
+    }
+
     for (const auto& layer : layers) {
         canvas->save();
 
-        if (mCapture.isCaptureRunning()) {
+        if (mCapture->isCaptureRunning()) {
             // Record the name of the layer if the capture is running.
             std::stringstream layerSettings;
             PrintTo(*layer, &layerSettings);
@@ -588,6 +653,16 @@
             }
         }
 
+        const ui::Dataspace targetDataspace = mUseColorManagement
+                ? (needsLinearEffect(layer->colorTransform, layer->sourceDataspace,
+                                     display.outputDataspace)
+                           // If we need to map to linear space, then mark the source image with the
+                           // same colorspace as the destination surface so that Skia's color
+                           // management is a no-op.
+                           ? display.outputDataspace
+                           : layer->sourceDataspace)
+                : ui::Dataspace::UNKNOWN;
+
         if (layer->source.buffer.buffer) {
             ATRACE_NAME("DrawImage");
             const auto& item = layer->source.buffer;
@@ -597,31 +672,18 @@
                 imageTextureRef = iter->second;
             } else {
                 imageTextureRef = std::make_shared<AutoBackendTexture::LocalRef>();
-                imageTextureRef->setTexture(new AutoBackendTexture(mGrContext.get(),
+                imageTextureRef->setTexture(new AutoBackendTexture(grContext.get(),
                                                                    item.buffer->toAHardwareBuffer(),
                                                                    false));
-                mTextureCache.insert({buffer->getId(), imageTextureRef});
+                mTextureCache.insert({item.buffer->getId(), imageTextureRef});
             }
 
             sk_sp<SkImage> image =
-                    imageTextureRef->getTexture()
-                            ->makeImage(mUseColorManagement
-                                                ? (needsLinearEffect(layer->colorTransform,
-                                                                     layer->sourceDataspace,
-                                                                     display.outputDataspace)
-                                                           // If we need to map to linear space,
-                                                           // then mark the source image with the
-                                                           // same colorspace as the destination
-                                                           // surface so that Skia's color
-                                                           // management is a no-op.
-                                                           ? display.outputDataspace
-                                                           : layer->sourceDataspace)
-                                                : ui::Dataspace::SRGB,
-                                        item.isOpaque ? kOpaque_SkAlphaType
-                                                      : (item.usePremultipliedAlpha
-                                                                 ? kPremul_SkAlphaType
-                                                                 : kUnpremul_SkAlphaType),
-                                        mGrContext.get());
+                    imageTextureRef->getTexture()->makeImage(targetDataspace,
+                                                             item.usePremultipliedAlpha
+                                                                     ? kPremul_SkAlphaType
+                                                                     : kUnpremul_SkAlphaType,
+                                                             grContext.get());
 
             auto texMatrix = getSkM44(item.textureTransform).asM33();
             // textureTansform was intended to be passed directly into a shader, so when
@@ -650,11 +712,35 @@
                 shader = image->makeShader(SkSamplingOptions(), matrix);
             }
 
+            // Handle opaque images - it's a little nonstandard how we do this.
+            // Fundamentally we need to support SurfaceControl.Builder#setOpaque:
+            // https://developer.android.com/reference/android/view/SurfaceControl.Builder#setOpaque(boolean)
+            // The important language is that when isOpaque is set, opacity is not sampled from the
+            // alpha channel, but blending may still be supported on a transaction via setAlpha. So,
+            // here's the conundrum:
+            // 1. We can't force the SkImage alpha type to kOpaque_SkAlphaType, because it's treated
+            // as an internal hint - composition is undefined when there are alpha bits present.
+            // 2. We can try to lie about the pixel layout, but that only works for RGBA8888
+            // buffers, i.e., treating them as RGBx8888 instead. But we can't do the same for
+            // RGBA1010102 because RGBx1010102 is not supported as a pixel layout for SkImages. It's
+            // also not clear what to use for F16 either, and lying about the pixel layout is a bit
+            // of a hack anyways.
+            // 3. We can't change the blendmode to src, because while this satisfies the requirement
+            // for ignoring the alpha channel, it doesn't quite satisfy the blending requirement
+            // because src always clobbers the destination content.
+            //
+            // So, what we do here instead is an additive blend mode where we compose the input
+            // image with a solid black. This might need to be reassess if this does not support
+            // FP16 incredibly well, but FP16 end-to-end isn't well supported anyway at the moment.
+            if (item.isOpaque) {
+                shader = SkShaders::Blend(SkBlendMode::kPlus, shader,
+                                          SkShaders::Color(SkColors::kBlack,
+                                                           toSkColorSpace(targetDataspace)));
+            }
+
             paint.setShader(
                     createRuntimeEffectShader(shader, layer, display,
                                               !item.isOpaque && item.usePremultipliedAlpha));
-
-            // Make sure to take into the account the alpha set on the layer.
             paint.setAlphaf(layer->alpha);
         } else {
             ATRACE_NAME("DrawColor");
@@ -662,8 +748,8 @@
             sk_sp<SkShader> shader = SkShaders::Color(SkColor4f{.fR = color.r,
                                                                 .fG = color.g,
                                                                 .fB = color.b,
-                                                                layer->alpha},
-                                                      nullptr);
+                                                                .fA = layer->alpha},
+                                                      toSkColorSpace(targetDataspace));
             paint.setShader(createRuntimeEffectShader(shader, layer, display,
                                                       /* undoPremultipliedAlpha */ false));
         }
@@ -671,31 +757,6 @@
         sk_sp<SkColorFilter> filter =
                 SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform));
 
-        // Handle opaque images - it's a little nonstandard how we do this.
-        // Fundamentally we need to support SurfaceControl.Builder#setOpaque:
-        // https://developer.android.com/reference/android/view/SurfaceControl.Builder#setOpaque(boolean)
-        // The important language is that when isOpaque is set, opacity is not sampled from the
-        // alpha channel, but blending may still be supported on a transaction via setAlpha. So,
-        // here's the conundrum:
-        // 1. We can't force the SkImage alpha type to kOpaque_SkAlphaType, because it's treated as
-        // an internal hint - composition is undefined when there are alpha bits present.
-        // 2. We can try to lie about the pixel layout, but that only works for RGBA8888 buffers,
-        // i.e., treating them as RGBx8888 instead. But we can't do the same for RGBA1010102 because
-        // RGBx1010102 is not supported as a pixel layout for SkImages. It's also not clear what to
-        // use for F16 either, and lying about the pixel layout is a bit of a hack anyways.
-        // 3. We can't change the blendmode to src, because while this satisfies the requirement for
-        // ignoring the alpha channel, it doesn't quite satisfy the blending requirement because
-        // src always clobbers the destination content.
-        //
-        // So, what we do here instead is an additive blend mode where we compose the input image
-        // with a solid black. This might need to be reassess if this does not support FP16
-        // incredibly well, but FP16 end-to-end isn't well supported anyway at the moment.
-        if (layer->source.buffer.buffer && layer->source.buffer.isOpaque) {
-            filter = SkColorFilters::Compose(filter,
-                                             SkColorFilters::Blend(SK_ColorBLACK,
-                                                                   SkBlendMode::kPlus));
-        }
-
         paint.setColorFilter(filter);
 
         for (const auto effectRegion : layer->blurRegions) {
@@ -721,7 +782,7 @@
         canvas->restore();
     }
     canvas->restore();
-    mCapture.endCapture();
+    mCapture->endCapture();
     {
         ATRACE_NAME("flush surface");
         surface->flush();
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 5384ec8..ed62a2a 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -34,9 +34,9 @@
 #include "SkImageInfo.h"
 #include "SkiaRenderEngine.h"
 #include "android-base/macros.h"
+#include "debug/SkiaCapture.h"
 #include "filters/BlurFilter.h"
-#include "skia/debug/SkiaCapture.h"
-#include "skia/filters/LinearEffect.h"
+#include "filters/LinearEffect.h"
 
 namespace android {
 namespace renderengine {
@@ -48,7 +48,7 @@
     SkiaGLRenderEngine(const RenderEngineCreationArgs& args, EGLDisplay display, EGLContext ctxt,
                        EGLSurface placeholder, EGLContext protectedContext,
                        EGLSurface protectedPlaceholder);
-    ~SkiaGLRenderEngine() override{};
+    ~SkiaGLRenderEngine() override EXCLUDES(mRenderingMutex);
 
     void unbindExternalTextureBuffer(uint64_t bufferId) override;
     status_t drawLayers(const DisplaySettings& display,
@@ -127,7 +127,7 @@
 
     bool mInProtectedContext = false;
     // Object to capture commands send to Skia.
-    SkiaCapture mCapture;
+    std::unique_ptr<SkiaCapture> mCapture;
 };
 
 } // namespace skia
diff --git a/libs/renderengine/skia/filters/LinearEffect.cpp b/libs/renderengine/skia/filters/LinearEffect.cpp
index 7680649..84af016 100644
--- a/libs/renderengine/skia/filters/LinearEffect.cpp
+++ b/libs/renderengine/skia/filters/LinearEffect.cpp
@@ -454,11 +454,18 @@
 
     effectBuilder.child("input") = shader;
 
-    ColorSpace inputColorSpace = toColorSpace(linearEffect.inputDataspace);
-    ColorSpace outputColorSpace = toColorSpace(linearEffect.outputDataspace);
+    if (linearEffect.inputDataspace == linearEffect.outputDataspace) {
+        effectBuilder.uniform("in_rgbToXyz") = mat4();
+        effectBuilder.uniform("in_xyzToRgb") = colorTransform;
+    } else {
+        ColorSpace inputColorSpace = toColorSpace(linearEffect.inputDataspace);
+        ColorSpace outputColorSpace = toColorSpace(linearEffect.outputDataspace);
 
-    effectBuilder.uniform("in_rgbToXyz") = mat4(inputColorSpace.getRGBtoXYZ());
-    effectBuilder.uniform("in_xyzToRgb") = colorTransform * mat4(outputColorSpace.getXYZtoRGB());
+        effectBuilder.uniform("in_rgbToXyz") = mat4(inputColorSpace.getRGBtoXYZ());
+        effectBuilder.uniform("in_xyzToRgb") =
+                colorTransform * mat4(outputColorSpace.getXYZtoRGB());
+    }
+
     effectBuilder.uniform("in_displayMaxLuminance") = maxDisplayLuminance;
     effectBuilder.uniform("in_inputMaxLuminance") =
             std::min(maxMasteringLuminance, maxContentLuminance);
diff --git a/libs/renderengine/tests/Android.bp b/libs/renderengine/tests/Android.bp
index bcf389b..51c7028 100644
--- a/libs/renderengine/tests/Android.bp
+++ b/libs/renderengine/tests/Android.bp
@@ -14,17 +14,21 @@
 
 cc_test {
     name: "librenderengine_test",
-    defaults: ["surfaceflinger_defaults"],
+    defaults: ["skia_deps", "surfaceflinger_defaults"],
     test_suites: ["device-tests"],
     srcs: [
         "RenderEngineTest.cpp",
         "RenderEngineThreadedTest.cpp",
     ],
+    include_dirs: [
+        "external/skia/src/gpu",
+    ],
     static_libs: [
         "libgmock",
         "librenderengine",
         "librenderengine_mocks",
     ],
+
     shared_libs: [
         "libbase",
         "libcutils",
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 2b8063e..58afe6e 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -22,16 +22,18 @@
 #pragma clang diagnostic ignored "-Wconversion"
 #pragma clang diagnostic ignored "-Wextra"
 
-#include <chrono>
-#include <condition_variable>
-#include <fstream>
-
 #include <cutils/properties.h>
 #include <gtest/gtest.h>
 #include <renderengine/RenderEngine.h>
 #include <sync/sync.h>
 #include <ui/PixelFormat.h>
+
+#include <chrono>
+#include <condition_variable>
+#include <fstream>
+
 #include "../gl/GLESRenderEngine.h"
+#include "../skia/SkiaGLRenderEngine.h"
 #include "../threaded/RenderEngineThreaded.h"
 
 constexpr int DEFAULT_DISPLAY_WIDTH = 128;
@@ -46,14 +48,26 @@
     virtual ~RenderEngineFactory() = default;
 
     virtual std::string name() = 0;
-    virtual std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() = 0;
+    virtual renderengine::RenderEngine::RenderEngineType type() = 0;
+    virtual std::unique_ptr<renderengine::RenderEngine> createRenderEngine() = 0;
+    virtual std::unique_ptr<renderengine::gl::GLESRenderEngine> createGLESRenderEngine() {
+        return nullptr;
+    }
 };
 
 class GLESRenderEngineFactory : public RenderEngineFactory {
 public:
     std::string name() override { return "GLESRenderEngineFactory"; }
 
-    std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() override {
+    renderengine::RenderEngine::RenderEngineType type() {
+        return renderengine::RenderEngine::RenderEngineType::GLES;
+    }
+
+    std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override {
+        return createGLESRenderEngine();
+    }
+
+    std::unique_ptr<renderengine::gl::GLESRenderEngine> createGLESRenderEngine() {
         renderengine::RenderEngineCreationArgs reCreationArgs =
                 renderengine::RenderEngineCreationArgs::Builder()
                         .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
@@ -63,7 +77,7 @@
                         .setPrecacheToneMapperShaderOnly(false)
                         .setSupportsBackgroundBlur(true)
                         .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
-                        .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::GLES)
+                        .setRenderEngineType(type())
                         .build();
         return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
     }
@@ -73,7 +87,15 @@
 public:
     std::string name() override { return "GLESCMRenderEngineFactory"; }
 
-    std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() override {
+    renderengine::RenderEngine::RenderEngineType type() {
+        return renderengine::RenderEngine::RenderEngineType::GLES;
+    }
+
+    std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override {
+        return createGLESRenderEngine();
+    }
+
+    std::unique_ptr<renderengine::gl::GLESRenderEngine> createGLESRenderEngine() override {
         renderengine::RenderEngineCreationArgs reCreationArgs =
                 renderengine::RenderEngineCreationArgs::Builder()
                         .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
@@ -82,7 +104,7 @@
                         .setPrecacheToneMapperShaderOnly(false)
                         .setSupportsBackgroundBlur(true)
                         .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
-                        .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::GLES)
+                        .setRenderEngineType(type())
                         .setUseColorManagerment(true)
                         .build();
         return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
@@ -91,9 +113,13 @@
 
 class SkiaGLESRenderEngineFactory : public RenderEngineFactory {
 public:
-    std::string name() override { return "SkiaGLESRenderEngineFactory"; }
+    std::string name() override { return "SkiaGLRenderEngineFactory"; }
 
-    std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() override {
+    renderengine::RenderEngine::RenderEngineType type() {
+        return renderengine::RenderEngine::RenderEngineType::SKIA_GL;
+    }
+
+    std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override {
         renderengine::RenderEngineCreationArgs reCreationArgs =
                 renderengine::RenderEngineCreationArgs::Builder()
                         .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
@@ -102,17 +128,21 @@
                         .setPrecacheToneMapperShaderOnly(false)
                         .setSupportsBackgroundBlur(true)
                         .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
-                        .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::SKIA_GL)
+                        .setRenderEngineType(type())
                         .build();
-        return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
+        return renderengine::skia::SkiaGLRenderEngine::create(reCreationArgs);
     }
 };
 
 class SkiaGLESCMRenderEngineFactory : public RenderEngineFactory {
 public:
-    std::string name() override { return "SkiaGLESCMRenderEngineFactory"; }
+    std::string name() override { return "SkiaGLCMRenderEngineFactory"; }
 
-    std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() override {
+    renderengine::RenderEngine::RenderEngineType type() {
+        return renderengine::RenderEngine::RenderEngineType::SKIA_GL;
+    }
+
+    std::unique_ptr<renderengine::RenderEngine> createRenderEngine() override {
         renderengine::RenderEngineCreationArgs reCreationArgs =
                 renderengine::RenderEngineCreationArgs::Builder()
                         .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
@@ -121,10 +151,10 @@
                         .setPrecacheToneMapperShaderOnly(false)
                         .setSupportsBackgroundBlur(true)
                         .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
-                        .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::SKIA_GL)
+                        .setRenderEngineType(type())
                         .setUseColorManagerment(true)
                         .build();
-        return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
+        return renderengine::skia::SkiaGLRenderEngine::create(reCreationArgs);
     }
 };
 
@@ -134,7 +164,7 @@
         return new GraphicBuffer(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
                                  HAL_PIXEL_FORMAT_RGBA_8888, 1,
                                  GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
-                                         GRALLOC_USAGE_HW_RENDER,
+                                         GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE,
                                  "output");
     }
 
@@ -159,7 +189,9 @@
         }
         for (uint32_t texName : mTexNames) {
             mRE->deleteTextures(1, &texName);
-            EXPECT_FALSE(mRE->isTextureNameKnownForTesting(texName));
+            if (mGLESRE != nullptr) {
+                EXPECT_FALSE(mGLESRE->isTextureNameKnownForTesting(texName));
+            }
         }
         const ::testing::TestInfo* const test_info =
                 ::testing::UnitTest::GetInstance()->current_test_info();
@@ -351,12 +383,11 @@
     }
 
     void invokeDraw(renderengine::DisplaySettings settings,
-                    std::vector<const renderengine::LayerSettings*> layers,
-                    sp<GraphicBuffer> buffer) {
+                    std::vector<const renderengine::LayerSettings*> layers) {
         base::unique_fd fence;
         status_t status =
-                mRE->drawLayers(settings, layers, buffer, true, base::unique_fd(), &fence);
-        mCurrentBuffer = buffer;
+                mRE->drawLayers(settings, layers, mBuffer, true, base::unique_fd(), &fence);
+        mCurrentBuffer = mBuffer;
 
         int fd = fence.release();
         if (fd >= 0) {
@@ -365,17 +396,15 @@
         }
 
         ASSERT_EQ(NO_ERROR, status);
-        if (layers.size() > 0) {
-            ASSERT_TRUE(mRE->isFramebufferImageCachedForTesting(buffer->getId()));
+        if (layers.size() > 0 && mGLESRE != nullptr) {
+            ASSERT_TRUE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
         }
     }
 
     void drawEmptyLayers() {
         renderengine::DisplaySettings settings;
         std::vector<const renderengine::LayerSettings*> layers;
-        // Meaningless buffer since we don't do any drawing
-        sp<GraphicBuffer> buffer = new GraphicBuffer();
-        invokeDraw(settings, layers, buffer);
+        invokeDraw(settings, layers);
     }
 
     template <typename SourceVariant>
@@ -471,7 +500,12 @@
                                  const renderengine::ShadowSettings& shadow,
                                  const ubyte4& backgroundColor);
 
-    std::unique_ptr<renderengine::gl::GLESRenderEngine> mRE;
+    void initializeRenderEngine();
+
+    std::unique_ptr<renderengine::RenderEngine> mRE;
+    // GLESRenderEngine for testing GLES-specific behavior.
+    // Owened by mRE, but this is downcasted.
+    renderengine::gl::GLESRenderEngine* mGLESRE = nullptr;
 
     // Dumb hack to avoid NPE in the EGL driver: the GraphicBuffer needs to
     // be freed *after* RenderEngine is destroyed, so that the EGL image is
@@ -483,6 +517,21 @@
     std::vector<uint32_t> mTexNames;
 };
 
+void RenderEngineTest::initializeRenderEngine() {
+    const auto& renderEngineFactory = GetParam();
+    if (renderEngineFactory->type() == renderengine::RenderEngine::RenderEngineType::GLES) {
+        // Only GLESRenderEngine exposes test-only methods. Provide a pointer to the
+        // GLESRenderEngine if we're using it so that we don't need to dynamic_cast
+        // every time.
+        std::unique_ptr<renderengine::gl::GLESRenderEngine> renderEngine =
+                renderEngineFactory->createGLESRenderEngine();
+        mGLESRE = renderEngine.get();
+        mRE = std::move(renderEngine);
+    } else {
+        mRE = renderEngineFactory->createRenderEngine();
+    }
+}
+
 struct ColorSourceVariant {
     static void fillColor(renderengine::LayerSettings& layer, half r, half g, half b,
                           RenderEngineTest* /*fixture*/) {
@@ -509,7 +558,7 @@
     static uint8_t getAlphaChannel() {
         // The isOpaque bit will override the alpha channel, so this should be
         // arbitrary.
-        return 10;
+        return 50;
     }
 };
 
@@ -563,7 +612,7 @@
 
     layers.push_back(&layer);
 
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 }
 
 template <typename SourceVariant>
@@ -606,7 +655,7 @@
     layer.alpha = 1.0f;
 
     layers.push_back(&layer);
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 }
 
 template <typename SourceVariant>
@@ -659,7 +708,7 @@
     layers.push_back(&layerTwo);
     layers.push_back(&layerThree);
 
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 }
 
 template <typename SourceVariant>
@@ -747,7 +796,7 @@
 
     layers.push_back(&layer);
 
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 }
 
 template <typename SourceVariant>
@@ -786,7 +835,7 @@
 
     layers.push_back(&layer);
 
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 }
 
 template <typename SourceVariant>
@@ -816,7 +865,7 @@
 
     layers.push_back(&layer);
 
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 }
 
 template <typename SourceVariant>
@@ -844,7 +893,7 @@
 
     layers.push_back(&layer);
 
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 }
 
 template <typename SourceVariant>
@@ -904,7 +953,7 @@
     blurLayer.alpha = 0;
     layers.push_back(&blurLayer);
 
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 
     expectBufferColor(Rect(center - 1, center - 5, center, center + 5), 150, 150, 0, 255,
                       50 /* tolerance */);
@@ -929,7 +978,7 @@
     layerOne.alpha = 0.2;
 
     layersFirst.push_back(&layerOne);
-    invokeDraw(settings, layersFirst, mBuffer);
+    invokeDraw(settings, layersFirst);
     expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 51, 0, 0, 51);
     expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
                            DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -945,7 +994,7 @@
     layerTwo.alpha = 1.0f;
 
     layersSecond.push_back(&layerTwo);
-    invokeDraw(settings, layersSecond, mBuffer);
+    invokeDraw(settings, layersSecond);
 
     expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3), 0, 0, 0, 0);
     expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH / 3 + 1, DEFAULT_DISPLAY_HEIGHT / 3 + 1,
@@ -997,7 +1046,7 @@
 
     layers.push_back(&layer);
 
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 }
 
 void RenderEngineTest::fillBufferTextureTransform() {
@@ -1036,7 +1085,7 @@
 
     layers.push_back(&layer);
 
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 }
 
 void RenderEngineTest::fillBufferWithPremultiplyAlpha() {
@@ -1075,7 +1124,7 @@
 
     layers.push_back(&layer);
 
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 }
 
 void RenderEngineTest::fillBufferWithoutPremultiplyAlpha() {
@@ -1093,7 +1142,7 @@
     // fake layer, without bounds should not render anything
     renderengine::LayerSettings layer;
     layers.push_back(&layer);
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 }
 
 void RenderEngineTest::clearRegion() {
@@ -1140,7 +1189,7 @@
                              casterColor.b / 255.0f, this);
     layers.push_back(&layer);
 
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 }
 
 void RenderEngineTest::drawShadowWithoutCaster(const FloatRect& castingBounds,
@@ -1171,7 +1220,7 @@
     shadowLayer.shadow = shadow;
     layers.push_back(&shadowLayer);
 
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 }
 
 INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest,
@@ -1181,8 +1230,7 @@
                                          std::make_shared<SkiaGLESCMRenderEngineFactory>()));
 
 TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+    initializeRenderEngine();
     drawEmptyLayers();
 }
 
@@ -1210,16 +1258,15 @@
     std::vector<const renderengine::LayerSettings*> layers;
     layers.push_back(&bgLayer);
 
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 
     // Expect to see full opaque pixel (with inverted red from the transform).
-    expectBufferColor(Rect(0, 0, 1, 1), 0.f, backgroundColor.g, backgroundColor.b,
+    expectBufferColor(Rect(0, 0, 10, 10), 0.f, backgroundColor.g, backgroundColor.b,
                       backgroundColor.a);
 }
 
 TEST_P(RenderEngineTest, drawLayers_nullOutputBuffer) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+    initializeRenderEngine();
 
     renderengine::DisplaySettings settings;
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1235,8 +1282,7 @@
 }
 
 TEST_P(RenderEngineTest, drawLayers_nullOutputFence) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+    initializeRenderEngine();
 
     renderengine::DisplaySettings settings;
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1258,7 +1304,13 @@
 
 TEST_P(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) {
     const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+
+    if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+        // GLES-specific test
+        return;
+    }
+
+    initializeRenderEngine();
 
     renderengine::DisplaySettings settings;
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1275,355 +1327,264 @@
     status_t status = mRE->drawLayers(settings, layers, mBuffer, false, base::unique_fd(), nullptr);
     mCurrentBuffer = mBuffer;
     ASSERT_EQ(NO_ERROR, status);
-    ASSERT_FALSE(mRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
+    ASSERT_FALSE(mGLESRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
     expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillRedBuffer<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillGreenBuffer<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBlueBuffer<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillRedTransparentBuffer<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferPhysicalOffset<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferCheckersRotate0<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferCheckersRotate90<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferCheckersRotate180<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferCheckersRotate270<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferLayerTransform<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferColorTransform<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferWithRoundedCorners<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferColorTransformZeroLayerAlpha<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferAndBlurBackground<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_overlayCorners_colorSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     overlayCorners<ColorSourceVariant>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillRedBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillGreenBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBlueBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillRedTransparentBuffer<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferPhysicalOffset<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferCheckersRotate0<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferCheckersRotate90<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferCheckersRotate180<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferCheckersRotate270<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferLayerTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferColorTransform<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
-TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
 
+TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_opaqueBufferSource) {
+    initializeRenderEngine();
     fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferAndBlurBackground<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_overlayCorners_opaqueBufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     overlayCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillRedBuffer_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillRedBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillGreenBuffer_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillGreenBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBlueBuffer_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBlueBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillRedTransparentBuffer_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillRedTransparentBuffer<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferPhysicalOffset_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferPhysicalOffset<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate0_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferCheckersRotate0<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate90_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferCheckersRotate90<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate180_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferCheckersRotate180<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferCheckersRotate270_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferCheckersRotate270<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferLayerTransform_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferLayerTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransform_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferColorTransform<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferRoundedCorners_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferAndBlurBackground<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_overlayCorners_bufferSource) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     overlayCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferTextureTransform) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferTextureTransform();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBuffer_premultipliesAlpha) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferWithPremultiplyAlpha();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillBuffer_withoutPremultiplyingAlpha) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     fillBufferWithoutPremultiplyAlpha();
 }
 
 TEST_P(RenderEngineTest, drawLayers_clearRegion) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
-
+    initializeRenderEngine();
     clearRegion();
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillsBufferAndCachesImages) {
     const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+
+    if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+        // GLES-specific test
+        return;
+    }
+
+    initializeRenderEngine();
 
     renderengine::DisplaySettings settings;
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1637,26 +1598,32 @@
     BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
 
     layers.push_back(&layer);
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
     uint64_t bufferId = layer.source.buffer.buffer->getId();
-    EXPECT_TRUE(mRE->isImageCachedForTesting(bufferId));
+    EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId));
     std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
-            mRE->unbindExternalTextureBufferForTesting(bufferId);
+            mGLESRE->unbindExternalTextureBufferForTesting(bufferId);
     std::lock_guard<std::mutex> lock(barrier->mutex);
     ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
                                             [&]() REQUIRES(barrier->mutex) {
                                                 return barrier->isOpen;
                                             }));
-    EXPECT_FALSE(mRE->isImageCachedForTesting(bufferId));
+    EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId));
     EXPECT_EQ(NO_ERROR, barrier->result);
 }
 
 TEST_P(RenderEngineTest, cacheExternalBuffer_withNullBuffer) {
     const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+
+    if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+        // GLES-specific test
+        return;
+    }
+
+    initializeRenderEngine();
 
     std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
-            mRE->cacheExternalTextureBufferForTesting(nullptr);
+            mGLESRE->cacheExternalTextureBufferForTesting(nullptr);
     std::lock_guard<std::mutex> lock(barrier->mutex);
     ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
                                             [&]() REQUIRES(barrier->mutex) {
@@ -1668,12 +1635,18 @@
 
 TEST_P(RenderEngineTest, cacheExternalBuffer_cachesImages) {
     const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+
+    if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+        // GLES-specific test
+        return;
+    }
+
+    initializeRenderEngine();
 
     sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
     uint64_t bufferId = buf->getId();
     std::shared_ptr<renderengine::gl::ImageManager::Barrier> barrier =
-            mRE->cacheExternalTextureBufferForTesting(buf);
+            mGLESRE->cacheExternalTextureBufferForTesting(buf);
     {
         std::lock_guard<std::mutex> lock(barrier->mutex);
         ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
@@ -1682,8 +1655,8 @@
                                                 }));
         EXPECT_EQ(NO_ERROR, barrier->result);
     }
-    EXPECT_TRUE(mRE->isImageCachedForTesting(bufferId));
-    barrier = mRE->unbindExternalTextureBufferForTesting(bufferId);
+    EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId));
+    barrier = mGLESRE->unbindExternalTextureBufferForTesting(bufferId);
     {
         std::lock_guard<std::mutex> lock(barrier->mutex);
         ASSERT_TRUE(barrier->condition.wait_for(barrier->mutex, std::chrono::seconds(5),
@@ -1692,12 +1665,11 @@
                                                 }));
         EXPECT_EQ(NO_ERROR, barrier->result);
     }
-    EXPECT_FALSE(mRE->isImageCachedForTesting(bufferId));
+    EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId));
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillShadow_castsWithoutCasterLayer) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+    initializeRenderEngine();
 
     const ubyte4 backgroundColor(255, 255, 255, 255);
     const float shadowLength = 5.0f;
@@ -1712,8 +1684,7 @@
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillShadow_casterLayerMinSize) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+    initializeRenderEngine();
 
     const ubyte4 casterColor(255, 0, 0, 255);
     const ubyte4 backgroundColor(255, 255, 255, 255);
@@ -1732,8 +1703,7 @@
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillShadow_casterColorLayer) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+    initializeRenderEngine();
 
     const ubyte4 casterColor(255, 0, 0, 255);
     const ubyte4 backgroundColor(255, 255, 255, 255);
@@ -1753,8 +1723,7 @@
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillShadow_casterOpaqueBufferLayer) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+    initializeRenderEngine();
 
     const ubyte4 casterColor(255, 0, 0, 255);
     const ubyte4 backgroundColor(255, 255, 255, 255);
@@ -1775,8 +1744,7 @@
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillShadow_casterWithRoundedCorner) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+    initializeRenderEngine();
 
     const ubyte4 casterColor(255, 0, 0, 255);
     const ubyte4 backgroundColor(255, 255, 255, 255);
@@ -1798,8 +1766,7 @@
 }
 
 TEST_P(RenderEngineTest, drawLayers_fillShadow_translucentCasterWithAlpha) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+    initializeRenderEngine();
 
     const ubyte4 casterColor(255, 0, 0, 255);
     const ubyte4 backgroundColor(255, 255, 255, 255);
@@ -1827,7 +1794,13 @@
 
 TEST_P(RenderEngineTest, cleanupPostRender_cleansUpOnce) {
     const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+
+    if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+        // GLES-specific test
+        return;
+    }
+
+    initializeRenderEngine();
 
     renderengine::DisplaySettings settings;
     settings.physicalDisplay = fullscreenRect();
@@ -1859,7 +1832,13 @@
 
 TEST_P(RenderEngineTest, cleanupPostRender_whenCleaningAll_replacesTextureMemory) {
     const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+
+    if (renderEngineFactory->type() != renderengine::RenderEngine::RenderEngineType::GLES) {
+        // GLES-specific test
+        return;
+    }
+
+    initializeRenderEngine();
 
     renderengine::DisplaySettings settings;
     settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
@@ -1883,20 +1862,19 @@
 
     uint64_t bufferId = layer.source.buffer.buffer->getId();
     uint32_t texName = layer.source.buffer.textureName;
-    EXPECT_TRUE(mRE->isImageCachedForTesting(bufferId));
-    EXPECT_EQ(bufferId, mRE->getBufferIdForTextureNameForTesting(texName));
+    EXPECT_TRUE(mGLESRE->isImageCachedForTesting(bufferId));
+    EXPECT_EQ(bufferId, mGLESRE->getBufferIdForTextureNameForTesting(texName));
 
     EXPECT_TRUE(mRE->cleanupPostRender(renderengine::RenderEngine::CleanupMode::CLEAN_ALL));
 
     // Now check that our view of memory is good.
-    EXPECT_FALSE(mRE->isImageCachedForTesting(bufferId));
-    EXPECT_EQ(std::nullopt, mRE->getBufferIdForTextureNameForTesting(bufferId));
-    EXPECT_TRUE(mRE->isTextureNameKnownForTesting(texName));
+    EXPECT_FALSE(mGLESRE->isImageCachedForTesting(bufferId));
+    EXPECT_EQ(std::nullopt, mGLESRE->getBufferIdForTextureNameForTesting(bufferId));
+    EXPECT_TRUE(mGLESRE->isTextureNameKnownForTesting(texName));
 }
 
 TEST_P(RenderEngineTest, testRoundedCornersCrop) {
-    const auto& renderEngineFactory = GetParam();
-    mRE = renderEngineFactory->createRenderEngine();
+    initializeRenderEngine();
 
     renderengine::DisplaySettings settings;
     settings.physicalDisplay = fullscreenRect();
@@ -1931,7 +1909,7 @@
 
     layers.push_back(&greenLayer);
 
-    invokeDraw(settings, layers, mBuffer);
+    invokeDraw(settings, layers);
 
     // Corners should be ignored...
     // Screen size: width is 128, height is 256.
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index e64a9f1..d0ba8fe 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -87,20 +87,17 @@
     MOCK_METHOD2(setVsyncEnabled, void(PhysicalDisplayId, hal::Vsync));
     MOCK_CONST_METHOD1(getRefreshTimestamp, nsecs_t(PhysicalDisplayId));
     MOCK_CONST_METHOD1(isConnected, bool(PhysicalDisplayId));
-    MOCK_CONST_METHOD1(
-            getConfigs,
-            std::vector<std::shared_ptr<const HWC2::Display::Config>>(PhysicalDisplayId));
-    MOCK_CONST_METHOD1(getActiveConfig,
-                       std::shared_ptr<const HWC2::Display::Config>(PhysicalDisplayId));
-    MOCK_CONST_METHOD1(getActiveConfigIndex, int(PhysicalDisplayId));
+    MOCK_CONST_METHOD1(getModes, DisplayModes(PhysicalDisplayId));
+    MOCK_CONST_METHOD1(getActiveMode, DisplayModePtr(PhysicalDisplayId));
     MOCK_CONST_METHOD1(getColorModes, std::vector<ui::ColorMode>(PhysicalDisplayId));
     MOCK_METHOD3(setActiveColorMode, status_t(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent));
     MOCK_CONST_METHOD0(isUsingVrComposer, bool());
     MOCK_CONST_METHOD1(getDisplayConnectionType, DisplayConnectionType(PhysicalDisplayId));
     MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(PhysicalDisplayId));
     MOCK_CONST_METHOD1(getDisplayVsyncPeriod, nsecs_t(PhysicalDisplayId));
-    MOCK_METHOD4(setActiveConfigWithConstraints,
-                 status_t(PhysicalDisplayId, size_t, const hal::VsyncPeriodChangeConstraints&,
+    MOCK_METHOD4(setActiveModeWithConstraints,
+                 status_t(PhysicalDisplayId, HwcConfigIndexType,
+                          const hal::VsyncPeriodChangeConstraints&,
                           hal::VsyncPeriodChangeTimeline*));
     MOCK_METHOD2(setAutoLowLatencyMode, status_t(PhysicalDisplayId, bool));
     MOCK_METHOD2(getSupportedContentTypes,
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index cbc201f..8551365 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -210,7 +210,7 @@
     result.append("   ");
     StringAppendF(&result, "powerMode=%s (%d), ", to_string(mPowerMode).c_str(),
                   static_cast<int32_t>(mPowerMode));
-    StringAppendF(&result, "activeConfig=%d, ", mActiveConfig.value());
+    StringAppendF(&result, "activeConfig=%zu, ", mActiveConfig.value());
     StringAppendF(&result, "deviceProductInfo=");
     if (mDeviceProductInfo) {
         mDeviceProductInfo->dump(result);
diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h
new file mode 100644
index 0000000..69fd00e
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h
@@ -0,0 +1,131 @@
+/*
+ * 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 "DisplayHardware/Hal.h"
+#include "Scheduler/HwcStrongTypes.h"
+
+#include <android/configuration.h>
+#include <utils/Timers.h>
+
+#include <memory>
+#include <vector>
+
+namespace android {
+
+namespace hal = android::hardware::graphics::composer::hal;
+
+class DisplayMode;
+using DisplayModePtr = std::shared_ptr<const DisplayMode>;
+using DisplayModes = std::vector<DisplayModePtr>;
+
+class DisplayMode {
+public:
+    class Builder {
+    public:
+        explicit Builder(hal::HWConfigId id) : mDisplayMode(new DisplayMode(id)) {}
+
+        DisplayModePtr build() {
+            return std::const_pointer_cast<const DisplayMode>(std::move(mDisplayMode));
+        }
+
+        Builder& setId(HwcConfigIndexType id) {
+            mDisplayMode->mId = id;
+            return *this;
+        }
+
+        Builder& setWidth(int32_t width) {
+            mDisplayMode->mWidth = width;
+            return *this;
+        }
+
+        Builder& setHeight(int32_t height) {
+            mDisplayMode->mHeight = height;
+            return *this;
+        }
+
+        Builder& setVsyncPeriod(int32_t vsyncPeriod) {
+            mDisplayMode->mVsyncPeriod = vsyncPeriod;
+            return *this;
+        }
+
+        Builder& setDpiX(int32_t dpiX) {
+            if (dpiX == -1) {
+                mDisplayMode->mDpiX = getDefaultDensity();
+            } else {
+                mDisplayMode->mDpiX = dpiX / 1000.0f;
+            }
+            return *this;
+        }
+
+        Builder& setDpiY(int32_t dpiY) {
+            if (dpiY == -1) {
+                mDisplayMode->mDpiY = getDefaultDensity();
+            } else {
+                mDisplayMode->mDpiY = dpiY / 1000.0f;
+            }
+            return *this;
+        }
+
+        Builder& setConfigGroup(int32_t configGroup) {
+            mDisplayMode->mConfigGroup = configGroup;
+            return *this;
+        }
+
+    private:
+        float getDefaultDensity() {
+            // Default density is based on TVs: 1080p displays get XHIGH density, lower-
+            // resolution displays get TV density. Maybe eventually we'll need to update
+            // it for 4k displays, though hopefully those will just report accurate DPI
+            // information to begin with. This is also used for virtual displays and
+            // older HWC implementations, so be careful about orientation.
+
+            auto longDimension = std::max(mDisplayMode->mWidth, mDisplayMode->mHeight);
+            if (longDimension >= 1080) {
+                return ACONFIGURATION_DENSITY_XHIGH;
+            } else {
+                return ACONFIGURATION_DENSITY_TV;
+            }
+        }
+        std::shared_ptr<DisplayMode> mDisplayMode;
+    };
+
+    HwcConfigIndexType getId() const { return mId; }
+    hal::HWConfigId getHwcId() const { return mHwcId; }
+
+    int32_t getWidth() const { return mWidth; }
+    int32_t getHeight() const { return mHeight; }
+    nsecs_t getVsyncPeriod() const { return mVsyncPeriod; }
+    float getDpiX() const { return mDpiX; }
+    float getDpiY() const { return mDpiY; }
+    int32_t getConfigGroup() const { return mConfigGroup; }
+
+private:
+    explicit DisplayMode(hal::HWConfigId id) : mHwcId(id) {}
+
+    hal::HWConfigId mHwcId;
+    HwcConfigIndexType mId;
+
+    int32_t mWidth = -1;
+    int32_t mHeight = -1;
+    nsecs_t mVsyncPeriod = -1;
+    float mDpiX = -1;
+    float mDpiY = -1;
+    int32_t mConfigGroup = -1;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 14b54cd..3e856bb 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -77,9 +77,8 @@
     mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
                                        GRALLOC_USAGE_HW_RENDER |
                                        GRALLOC_USAGE_HW_COMPOSER);
-    const auto& activeConfig = mHwc.getActiveConfig(displayId);
-    ui::Size limitedSize =
-            limitFramebufferSize(activeConfig->getWidth(), activeConfig->getHeight());
+    const auto& activeMode = mHwc.getActiveMode(displayId);
+    ui::Size limitedSize = limitFramebufferSize(activeMode->getWidth(), activeMode->getHeight());
     mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
     mConsumer->setMaxAcquiredBufferCount(
             SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 426092d..71a3276 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -68,33 +68,6 @@
 // Display methods
 Display::~Display() = default;
 
-Display::Config::Config(Display& display, HWConfigId id)
-      : mDisplay(display),
-        mId(id),
-        mWidth(-1),
-        mHeight(-1),
-        mVsyncPeriod(-1),
-        mDpiX(-1),
-        mDpiY(-1) {}
-
-Display::Config::Builder::Builder(Display& display, HWConfigId id)
-      : mConfig(new Config(display, id)) {}
-
-float Display::Config::Builder::getDefaultDensity() {
-    // Default density is based on TVs: 1080p displays get XHIGH density, lower-
-    // resolution displays get TV density. Maybe eventually we'll need to update
-    // it for 4k displays, though hopefully those will just report accurate DPI
-    // information to begin with. This is also used for virtual displays and
-    // older HWC implementations, so be careful about orientation.
-
-    auto longDimension = std::max(mConfig->mWidth, mConfig->mHeight);
-    if (longDimension >= 1080) {
-        return ACONFIGURATION_DENSITY_XHIGH;
-    } else {
-        return ACONFIGURATION_DENSITY_TV;
-    }
-}
-
 namespace impl {
 
 Display::Display(android::Hwc2::Composer& composer,
@@ -162,93 +135,12 @@
     return Error::NONE;
 }
 
-Error Display::getActiveConfig(
-        std::shared_ptr<const Display::Config>* outConfig) const
-{
-    ALOGV("[%" PRIu64 "] getActiveConfig", mId);
-    HWConfigId configId = 0;
-    auto intError = mComposer.getActiveConfig(mId, &configId);
-    auto error = static_cast<Error>(intError);
-
-    if (error != Error::NONE) {
-        ALOGE("Unable to get active config for mId:[%" PRIu64 "]", mId);
-        *outConfig = nullptr;
-        return error;
-    }
-
-    if (mConfigs.count(configId) != 0) {
-        *outConfig = mConfigs.at(configId);
-    } else {
-        ALOGE("[%" PRIu64 "] getActiveConfig returned unknown config %u", mId,
-                configId);
-        // Return no error, but the caller needs to check for a null pointer to
-        // detect this case
-        *outConfig = nullptr;
-    }
-
-    return Error::NONE;
-}
-
 bool Display::isVsyncPeriodSwitchSupported() const {
     ALOGV("[%" PRIu64 "] isVsyncPeriodSwitchSupported()", mId);
 
     return mComposer.isVsyncPeriodSwitchSupported();
 }
 
-Error Display::getDisplayVsyncPeriod(nsecs_t* outVsyncPeriod) const {
-    ALOGV("[%" PRIu64 "] getDisplayVsyncPeriod", mId);
-
-    Error error;
-
-    if (isVsyncPeriodSwitchSupported()) {
-        Hwc2::VsyncPeriodNanos vsyncPeriodNanos = 0;
-        auto intError = mComposer.getDisplayVsyncPeriod(mId, &vsyncPeriodNanos);
-        error = static_cast<Error>(intError);
-        *outVsyncPeriod = static_cast<nsecs_t>(vsyncPeriodNanos);
-    } else {
-        // Get the default vsync period
-        std::shared_ptr<const Display::Config> config;
-        error = getActiveConfig(&config);
-        if (error != Error::NONE) {
-            return error;
-        }
-        if (!config) {
-            // HWC has updated the display modes and hasn't notified us yet.
-            return Error::BAD_CONFIG;
-        }
-
-        *outVsyncPeriod = config->getVsyncPeriod();
-    }
-
-    return error;
-}
-
-Error Display::getActiveConfigIndex(int* outIndex) const {
-    ALOGV("[%" PRIu64 "] getActiveConfigIndex", mId);
-    HWConfigId configId = 0;
-    auto intError = mComposer.getActiveConfig(mId, &configId);
-    auto error = static_cast<Error>(intError);
-
-    if (error != Error::NONE) {
-        ALOGE("Unable to get active config for mId:[%" PRIu64 "]", mId);
-        *outIndex = -1;
-        return error;
-    }
-
-    auto pos = mConfigs.find(configId);
-    if (pos != mConfigs.end()) {
-        *outIndex = std::distance(mConfigs.begin(), pos);
-        ALOGV("[%" PRIu64 "] index = %d", mId, *outIndex);
-    } else {
-        ALOGE("[%" PRIu64 "] getActiveConfig returned unknown config %u", mId, configId);
-        // Return no error, but the caller needs to check for a negative index
-        // to detect this case
-        *outIndex = -1;
-    }
-
-    return Error::NONE;
-}
-
 Error Display::getChangedCompositionTypes(std::unordered_map<HWC2::Layer*, Composition>* outTypes) {
     std::vector<Hwc2::Layer> layerIds;
     std::vector<Hwc2::IComposerClient::Composition> types;
@@ -335,15 +227,6 @@
     return static_cast<Error>(intError);
 }
 
-std::vector<std::shared_ptr<const Display::Config>> Display::getConfigs() const
-{
-    std::vector<std::shared_ptr<const Config>> configs;
-    for (const auto& element : mConfigs) {
-        configs.emplace_back(element.second);
-    }
-    return configs;
-}
-
 Error Display::getName(std::string* outName) const
 {
     auto intError = mComposer.getDisplayName(mId, outName);
@@ -486,16 +369,10 @@
     return Error::NONE;
 }
 
-Error Display::setActiveConfigWithConstraints(
-        const std::shared_ptr<const HWC2::Display::Config>& config,
-        const VsyncPeriodChangeConstraints& constraints, VsyncPeriodChangeTimeline* outTimeline) {
+Error Display::setActiveConfigWithConstraints(hal::HWConfigId configId,
+                                              const VsyncPeriodChangeConstraints& constraints,
+                                              VsyncPeriodChangeTimeline* outTimeline) {
     ALOGV("[%" PRIu64 "] setActiveConfigWithConstraints", mId);
-    if (config->getDisplayId() != mId) {
-        ALOGE("setActiveConfigWithConstraints received config %u for the wrong display %" PRIu64
-              " (expected %" PRIu64 ")",
-              config->getId(), config->getDisplayId(), mId);
-        return Error::BAD_CONFIG;
-    }
 
     if (isVsyncPeriodSwitchSupported()) {
         Hwc2::IComposerClient::VsyncPeriodChangeConstraints hwc2Constraints;
@@ -503,9 +380,8 @@
         hwc2Constraints.seamlessRequired = constraints.seamlessRequired;
 
         Hwc2::VsyncPeriodChangeTimeline vsyncPeriodChangeTimeline = {};
-        auto intError =
-                mComposer.setActiveConfigWithConstraints(mId, config->getId(), hwc2Constraints,
-                                                         &vsyncPeriodChangeTimeline);
+        auto intError = mComposer.setActiveConfigWithConstraints(mId, configId, hwc2Constraints,
+                                                                 &vsyncPeriodChangeTimeline);
         outTimeline->newVsyncAppliedTimeNanos = vsyncPeriodChangeTimeline.newVsyncAppliedTimeNanos;
         outTimeline->refreshRequired = vsyncPeriodChangeTimeline.refreshRequired;
         outTimeline->refreshTimeNanos = vsyncPeriodChangeTimeline.refreshTimeNanos;
@@ -519,25 +395,13 @@
         ALOGE("setActiveConfigWithConstraints received constraints that can't be satisfied");
     }
 
-    auto intError_2_4 = mComposer.setActiveConfig(mId, config->getId());
+    auto intError_2_4 = mComposer.setActiveConfig(mId, configId);
     outTimeline->newVsyncAppliedTimeNanos = std::max(now, constraints.desiredTimeNanos);
     outTimeline->refreshRequired = true;
     outTimeline->refreshTimeNanos = now;
     return static_cast<Error>(intError_2_4);
 }
 
-Error Display::setActiveConfig(const std::shared_ptr<const Config>& config)
-{
-    if (config->getDisplayId() != mId) {
-        ALOGE("setActiveConfig received config %u for the wrong display %"
-                PRIu64 " (expected %" PRIu64 ")", config->getId(),
-                config->getDisplayId(), mId);
-        return Error::BAD_CONFIG;
-    }
-    auto intError = mComposer.setActiveConfig(mId, config->getId());
-    return static_cast<Error>(intError);
-}
-
 Error Display::setClientTarget(uint32_t slot, const sp<GraphicBuffer>& target,
         const sp<Fence>& acquireFence, Dataspace dataspace)
 {
@@ -681,58 +545,10 @@
 void Display::setConnected(bool connected) {
     if (!mIsConnected && connected) {
         mComposer.setClientTargetSlotCount(mId);
-        if (mType == DisplayType::PHYSICAL) {
-            loadConfigs();
-        }
     }
     mIsConnected = connected;
 }
 
-int32_t Display::getAttribute(HWConfigId configId, Attribute attribute) {
-    int32_t value = 0;
-    auto intError = mComposer.getDisplayAttribute(mId, configId, attribute, &value);
-    auto error = static_cast<Error>(intError);
-    if (error != Error::NONE) {
-        ALOGE("getDisplayAttribute(%" PRIu64 ", %u, %s) failed: %s (%d)", mId,
-                configId, to_string(attribute).c_str(),
-                to_string(error).c_str(), intError);
-        return -1;
-    }
-    return value;
-}
-
-void Display::loadConfig(HWConfigId configId) {
-    ALOGV("[%" PRIu64 "] loadConfig(%u)", mId, configId);
-
-    auto config = Config::Builder(*this, configId)
-                          .setWidth(getAttribute(configId, hal::Attribute::WIDTH))
-                          .setHeight(getAttribute(configId, hal::Attribute::HEIGHT))
-                          .setVsyncPeriod(getAttribute(configId, hal::Attribute::VSYNC_PERIOD))
-                          .setDpiX(getAttribute(configId, hal::Attribute::DPI_X))
-                          .setDpiY(getAttribute(configId, hal::Attribute::DPI_Y))
-                          .setConfigGroup(getAttribute(configId, hal::Attribute::CONFIG_GROUP))
-                          .build();
-    mConfigs.emplace(configId, std::move(config));
-}
-
-void Display::loadConfigs()
-{
-    ALOGV("[%" PRIu64 "] loadConfigs", mId);
-
-    std::vector<HWConfigId> configIds;
-    auto intError = mComposer.getDisplayConfigs(mId, &configIds);
-    auto error = static_cast<Error>(intError);
-    if (error != Error::NONE) {
-        ALOGE("[%" PRIu64 "] getDisplayConfigs [2] failed: %s (%d)", mId,
-                to_string(error).c_str(), intError);
-        return;
-    }
-
-    for (auto configId : configIds) {
-        loadConfig(configId);
-    }
-}
-
 // Other Display methods
 
 HWC2::Layer* Display::getLayerById(HWLayerId id) const {
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 89df84b..4c7f284 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -79,80 +79,6 @@
 public:
     virtual ~Display();
 
-    class Config {
-    public:
-        class Builder
-        {
-        public:
-            Builder(Display& display, hal::HWConfigId id);
-
-            std::shared_ptr<const Config> build() {
-                return std::const_pointer_cast<const Config>(
-                        std::move(mConfig));
-            }
-
-            Builder& setWidth(int32_t width) {
-                mConfig->mWidth = width;
-                return *this;
-            }
-            Builder& setHeight(int32_t height) {
-                mConfig->mHeight = height;
-                return *this;
-            }
-            Builder& setVsyncPeriod(int32_t vsyncPeriod) {
-                mConfig->mVsyncPeriod = vsyncPeriod;
-                return *this;
-            }
-            Builder& setDpiX(int32_t dpiX) {
-                if (dpiX == -1) {
-                    mConfig->mDpiX = getDefaultDensity();
-                } else {
-                    mConfig->mDpiX = dpiX / 1000.0f;
-                }
-                return *this;
-            }
-            Builder& setDpiY(int32_t dpiY) {
-                if (dpiY == -1) {
-                    mConfig->mDpiY = getDefaultDensity();
-                } else {
-                    mConfig->mDpiY = dpiY / 1000.0f;
-                }
-                return *this;
-            }
-            Builder& setConfigGroup(int32_t configGroup) {
-                mConfig->mConfigGroup = configGroup;
-                return *this;
-            }
-
-        private:
-            float getDefaultDensity();
-            std::shared_ptr<Config> mConfig;
-        };
-
-        hal::HWDisplayId getDisplayId() const { return mDisplay.getId(); }
-        hal::HWConfigId getId() const { return mId; }
-
-        int32_t getWidth() const { return mWidth; }
-        int32_t getHeight() const { return mHeight; }
-        nsecs_t getVsyncPeriod() const { return mVsyncPeriod; }
-        float getDpiX() const { return mDpiX; }
-        float getDpiY() const { return mDpiY; }
-        int32_t getConfigGroup() const { return mConfigGroup; }
-
-    private:
-        Config(Display& display, hal::HWConfigId id);
-
-        Display& mDisplay;
-        hal::HWConfigId mId;
-
-        int32_t mWidth;
-        int32_t mHeight;
-        nsecs_t mVsyncPeriod;
-        float mDpiX;
-        float mDpiY;
-        int32_t mConfigGroup;
-    };
-
     virtual hal::HWDisplayId getId() const = 0;
     virtual bool isConnected() const = 0;
     virtual void setConnected(bool connected) = 0; // For use by Device only
@@ -162,9 +88,6 @@
     [[clang::warn_unused_result]] virtual hal::Error acceptChanges() = 0;
     [[clang::warn_unused_result]] virtual hal::Error createLayer(Layer** outLayer) = 0;
     [[clang::warn_unused_result]] virtual hal::Error destroyLayer(Layer* layer) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getActiveConfig(
-            std::shared_ptr<const Config>* outConfig) const = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getActiveConfigIndex(int* outIndex) const = 0;
     [[clang::warn_unused_result]] virtual hal::Error getChangedCompositionTypes(
             std::unordered_map<Layer*, hal::Composition>* outTypes) = 0;
     [[clang::warn_unused_result]] virtual hal::Error getColorModes(
@@ -176,10 +99,6 @@
     [[clang::warn_unused_result]] virtual hal::Error getDataspaceSaturationMatrix(
             hal::Dataspace dataspace, android::mat4* outMatrix) = 0;
 
-    // Doesn't call into the HWC2 device, so no errors are possible
-    [[clang::warn_unused_result]] virtual std::vector<std::shared_ptr<const Config>> getConfigs()
-            const = 0;
-
     [[clang::warn_unused_result]] virtual hal::Error getName(std::string* outName) const = 0;
     [[clang::warn_unused_result]] virtual hal::Error getRequests(
             hal::DisplayRequest* outDisplayRequests,
@@ -201,8 +120,6 @@
             std::unordered_map<Layer*, android::sp<android::Fence>>* outFences) const = 0;
     [[clang::warn_unused_result]] virtual hal::Error present(
             android::sp<android::Fence>* outPresentFence) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error setActiveConfig(
-            const std::shared_ptr<const Config>& config) = 0;
     [[clang::warn_unused_result]] virtual hal::Error setClientTarget(
             uint32_t slot, const android::sp<android::GraphicBuffer>& target,
             const android::sp<android::Fence>& acquireFence, hal::Dataspace dataspace) = 0;
@@ -222,11 +139,8 @@
             android::sp<android::Fence>* outPresentFence, uint32_t* state) = 0;
     [[clang::warn_unused_result]] virtual std::future<hal::Error> setDisplayBrightness(
             float brightness) = 0;
-    [[clang::warn_unused_result]] virtual hal::Error getDisplayVsyncPeriod(
-            nsecs_t* outVsyncPeriod) const = 0;
     [[clang::warn_unused_result]] virtual hal::Error setActiveConfigWithConstraints(
-            const std::shared_ptr<const HWC2::Display::Config>& config,
-            const hal::VsyncPeriodChangeConstraints& constraints,
+            hal::HWConfigId configId, const hal::VsyncPeriodChangeConstraints& constraints,
             hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
     [[clang::warn_unused_result]] virtual hal::Error setAutoLowLatencyMode(bool on) = 0;
     [[clang::warn_unused_result]] virtual hal::Error getSupportedContentTypes(
@@ -248,8 +162,6 @@
     hal::Error acceptChanges() override;
     hal::Error createLayer(Layer** outLayer) override;
     hal::Error destroyLayer(Layer*) override;
-    hal::Error getActiveConfig(std::shared_ptr<const Config>* outConfig) const override;
-    hal::Error getActiveConfigIndex(int* outIndex) const override;
     hal::Error getChangedCompositionTypes(
             std::unordered_map<Layer*, hal::Composition>* outTypes) override;
     hal::Error getColorModes(std::vector<hal::ColorMode>* outModes) const override;
@@ -259,9 +171,6 @@
                                 std::vector<hal::RenderIntent>* outRenderIntents) const override;
     hal::Error getDataspaceSaturationMatrix(hal::Dataspace, android::mat4* outMatrix) override;
 
-    // Doesn't call into the HWC2 device, so no errors are possible
-    std::vector<std::shared_ptr<const Config>> getConfigs() const override;
-
     hal::Error getName(std::string* outName) const override;
     hal::Error getRequests(
             hal::DisplayRequest* outDisplayRequests,
@@ -279,7 +188,6 @@
     hal::Error getReleaseFences(
             std::unordered_map<Layer*, android::sp<android::Fence>>* outFences) const override;
     hal::Error present(android::sp<android::Fence>* outPresentFence) override;
-    hal::Error setActiveConfig(const std::shared_ptr<const HWC2::Display::Config>& config) override;
     hal::Error setClientTarget(uint32_t slot, const android::sp<android::GraphicBuffer>& target,
                                const android::sp<android::Fence>& acquireFence,
                                hal::Dataspace dataspace) override;
@@ -294,11 +202,9 @@
                                  android::sp<android::Fence>* outPresentFence,
                                  uint32_t* state) override;
     std::future<hal::Error> setDisplayBrightness(float brightness) override;
-    hal::Error getDisplayVsyncPeriod(nsecs_t* outVsyncPeriod) const override;
-    hal::Error setActiveConfigWithConstraints(
-            const std::shared_ptr<const HWC2::Display::Config>& config,
-            const hal::VsyncPeriodChangeConstraints& constraints,
-            hal::VsyncPeriodChangeTimeline* outTimeline) override;
+    hal::Error setActiveConfigWithConstraints(hal::HWConfigId configId,
+                                              const hal::VsyncPeriodChangeConstraints& constraints,
+                                              hal::VsyncPeriodChangeTimeline* outTimeline) override;
     hal::Error setAutoLowLatencyMode(bool on) override;
     hal::Error getSupportedContentTypes(
             std::vector<hal::ContentType>* outSupportedContentTypes) const override;
@@ -315,9 +221,6 @@
     virtual bool isVsyncPeriodSwitchSupported() const override;
 
 private:
-    int32_t getAttribute(hal::HWConfigId, hal::Attribute);
-    void loadConfig(hal::HWConfigId);
-    void loadConfigs();
 
     // This may fail (and return a null pointer) if no layer with this ID exists
     // on this display
@@ -338,7 +241,6 @@
     bool mIsConnected = false;
 
     std::unordered_map<hal::HWLayerId, std::unique_ptr<Layer>> mLayers;
-    std::unordered_map<hal::HWConfigId, std::shared_ptr<const Config>> mConfigs;
 
     std::once_flag mDisplayCapabilityQueryFlag;
     std::unordered_set<hal::DisplayCapability> mDisplayCapabilities;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 6f3987f..ca67935 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -281,6 +281,8 @@
 
 void HWComposer::allocatePhysicalDisplay(hal::HWDisplayId hwcDisplayId,
                                          PhysicalDisplayId displayId) {
+    mPhysicalDisplayIdMap[hwcDisplayId] = displayId;
+
     if (!mInternalHwcDisplayId) {
         mInternalHwcDisplayId = hwcDisplayId;
     } else if (mInternalHwcDisplayId != hwcDisplayId && !mExternalHwcDisplayId) {
@@ -293,8 +295,41 @@
                                                   hal::DisplayType::PHYSICAL);
     newDisplay->setConnected(true);
     displayData.hwcDisplay = std::move(newDisplay);
-    displayData.configs = displayData.hwcDisplay->getConfigs();
-    mPhysicalDisplayIdMap[hwcDisplayId] = displayId;
+    loadModes(displayData, hwcDisplayId);
+}
+
+int32_t HWComposer::getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId configId,
+                                 hal::Attribute attribute) {
+    int32_t value = 0;
+    auto error = static_cast<hal::Error>(
+            mComposer->getDisplayAttribute(hwcDisplayId, configId, attribute, &value));
+
+    RETURN_IF_HWC_ERROR_FOR("getDisplayAttribute", error, *toPhysicalDisplayId(hwcDisplayId), -1);
+    return value;
+}
+
+void HWComposer::loadModes(DisplayData& displayData, hal::HWDisplayId hwcDisplayId) {
+    ALOGV("[HWC display %" PRIu64 "] %s", hwcDisplayId, __FUNCTION__);
+
+    std::vector<hal::HWConfigId> configIds;
+    auto error = static_cast<hal::Error>(mComposer->getDisplayConfigs(hwcDisplayId, &configIds));
+    RETURN_IF_HWC_ERROR_FOR("getDisplayConfigs", error, *toPhysicalDisplayId(hwcDisplayId));
+
+    displayData.modes.clear();
+    for (auto configId : configIds) {
+        auto mode = DisplayMode::Builder(configId)
+                            .setId(HwcConfigIndexType(displayData.modes.size()))
+                            .setWidth(getAttribute(hwcDisplayId, configId, hal::Attribute::WIDTH))
+                            .setHeight(getAttribute(hwcDisplayId, configId, hal::Attribute::HEIGHT))
+                            .setVsyncPeriod(getAttribute(hwcDisplayId, configId,
+                                                         hal::Attribute::VSYNC_PERIOD))
+                            .setDpiX(getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X))
+                            .setDpiY(getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y))
+                            .setConfigGroup(getAttribute(hwcDisplayId, configId,
+                                                         hal::Attribute::CONFIG_GROUP))
+                            .build();
+        displayData.modes.push_back(std::move(mode));
+    }
 }
 
 HWC2::Layer* HWComposer::createLayer(HalDisplayId displayId) {
@@ -330,34 +365,38 @@
     return mDisplayData.at(displayId).hwcDisplay->isConnected();
 }
 
-std::vector<std::shared_ptr<const HWC2::Display::Config>> HWComposer::getConfigs(
-        PhysicalDisplayId displayId) const {
+DisplayModes HWComposer::getModes(PhysicalDisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, {});
 
-    // We cache the configs when the DisplayData is created on hotplug. If the configs need to
+    // We cache the modes when the DisplayData is created on hotplug. If the modes need to
     // change HWC will send a hotplug event which will recreate displayData.
-    return mDisplayData.at(displayId).configs;
+    return mDisplayData.at(displayId).modes;
 }
 
-std::shared_ptr<const HWC2::Display::Config> HWComposer::getActiveConfig(
-        PhysicalDisplayId displayId) const {
+DisplayModePtr HWComposer::getActiveMode(PhysicalDisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
 
-    std::shared_ptr<const HWC2::Display::Config> config;
-    auto error = mDisplayData.at(displayId).hwcDisplay->getActiveConfig(&config);
+    const auto hwcId = *fromPhysicalDisplayId(displayId);
+    ALOGV("[%" PRIu64 "] getActiveMode", hwcId);
+    hal::HWConfigId configId;
+    auto error = static_cast<hal::Error>(mComposer->getActiveConfig(hwcId, &configId));
+
+    const auto& modes = mDisplayData.at(displayId).modes;
     if (error == hal::Error::BAD_CONFIG) {
-        LOG_DISPLAY_ERROR(displayId, "No active config");
+        LOG_DISPLAY_ERROR(displayId, "No active mode");
         return nullptr;
     }
 
     RETURN_IF_HWC_ERROR(error, displayId, nullptr);
 
-    if (!config) {
-        LOG_DISPLAY_ERROR(displayId, "Unknown config");
+    const auto it = std::find_if(modes.begin(), modes.end(),
+                                 [configId](auto mode) { return mode->getHwcId() == configId; });
+    if (it == modes.end()) {
+        LOG_DISPLAY_ERROR(displayId, "Unknown mode");
         return nullptr;
     }
 
-    return config;
+    return *it;
 }
 
 // Composer 2.4
@@ -385,30 +424,24 @@
 nsecs_t HWComposer::getDisplayVsyncPeriod(PhysicalDisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, 0);
 
-    nsecs_t vsyncPeriodNanos;
-    auto error = mDisplayData.at(displayId).hwcDisplay->getDisplayVsyncPeriod(&vsyncPeriodNanos);
-    RETURN_IF_HWC_ERROR(error, displayId, 0);
-    return vsyncPeriodNanos;
-}
-
-int HWComposer::getActiveConfigIndex(PhysicalDisplayId displayId) const {
-    RETURN_IF_INVALID_DISPLAY(displayId, -1);
-
-    int index;
-    auto error = mDisplayData.at(displayId).hwcDisplay->getActiveConfigIndex(&index);
-    if (error == hal::Error::BAD_CONFIG) {
-        LOG_DISPLAY_ERROR(displayId, "No active config");
-        return -1;
+    if (isVsyncPeriodSwitchSupported(displayId)) {
+        const auto hwcId = *fromPhysicalDisplayId(displayId);
+        Hwc2::VsyncPeriodNanos vsyncPeriodNanos = 0;
+        auto error =
+                static_cast<hal::Error>(mComposer->getDisplayVsyncPeriod(hwcId, &vsyncPeriodNanos));
+        RETURN_IF_HWC_ERROR(error, displayId, 0);
+        return static_cast<nsecs_t>(vsyncPeriodNanos);
     }
 
-    RETURN_IF_HWC_ERROR(error, displayId, -1);
+    // Get the default vsync period
+    auto mode = getActiveMode(displayId);
 
-    if (index < 0) {
-        LOG_DISPLAY_ERROR(displayId, "Unknown config");
-        return -1;
+    if (!mode) {
+        // HWC has updated the display modes and hasn't notified us yet.
+        RETURN_IF_HWC_ERROR(hal::Error::BAD_CONFIG, displayId, 0);
     }
 
-    return index;
+    return mode->getVsyncPeriod();
 }
 
 std::vector<ui::ColorMode> HWComposer::getColorModes(PhysicalDisplayId displayId) const {
@@ -640,21 +673,21 @@
     return NO_ERROR;
 }
 
-status_t HWComposer::setActiveConfigWithConstraints(
-        PhysicalDisplayId displayId, size_t configId,
+status_t HWComposer::setActiveModeWithConstraints(
+        PhysicalDisplayId displayId, HwcConfigIndexType modeId,
         const hal::VsyncPeriodChangeConstraints& constraints,
         hal::VsyncPeriodChangeTimeline* outTimeline) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
     auto& displayData = mDisplayData[displayId];
-    if (configId >= displayData.configs.size()) {
-        LOG_DISPLAY_ERROR(displayId, ("Invalid config " + std::to_string(configId)).c_str());
+    if (modeId.value() >= displayData.modes.size()) {
+        LOG_DISPLAY_ERROR(displayId, ("Invalid mode " + std::to_string(modeId.value())).c_str());
         return BAD_INDEX;
     }
 
-    auto error =
-            displayData.hwcDisplay->setActiveConfigWithConstraints(displayData.configs[configId],
-                                                                   constraints, outTimeline);
+    const auto hwcConfigId = displayData.modes[modeId.value()]->getHwcId();
+    auto error = displayData.hwcDisplay->setActiveConfigWithConstraints(hwcConfigId, constraints,
+                                                                        outTimeline);
     RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
     return NO_ERROR;
 }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 7e1da252..2b3d2d4 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -41,6 +41,7 @@
 
 #include "DisplayIdGenerator.h"
 #include "DisplayIdentification.h"
+#include "DisplayMode.h"
 #include "HWC2.h"
 #include "Hal.h"
 
@@ -184,12 +185,9 @@
     virtual nsecs_t getRefreshTimestamp(PhysicalDisplayId) const = 0;
     virtual bool isConnected(PhysicalDisplayId) const = 0;
 
-    virtual std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(
-            PhysicalDisplayId) const = 0;
+    virtual DisplayModes getModes(PhysicalDisplayId) const = 0;
 
-    virtual std::shared_ptr<const HWC2::Display::Config> getActiveConfig(
-            PhysicalDisplayId) const = 0;
-    virtual int getActiveConfigIndex(PhysicalDisplayId) const = 0;
+    virtual DisplayModePtr getActiveMode(PhysicalDisplayId) const = 0;
 
     virtual std::vector<ui::ColorMode> getColorModes(PhysicalDisplayId) const = 0;
 
@@ -200,9 +198,9 @@
     virtual DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const = 0;
     virtual bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const = 0;
     virtual nsecs_t getDisplayVsyncPeriod(PhysicalDisplayId) const = 0;
-    virtual status_t setActiveConfigWithConstraints(
-            PhysicalDisplayId, size_t configId, const hal::VsyncPeriodChangeConstraints&,
-            hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
+    virtual status_t setActiveModeWithConstraints(PhysicalDisplayId, HwcConfigIndexType,
+                                                  const hal::VsyncPeriodChangeConstraints&,
+                                                  hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
     virtual status_t setAutoLowLatencyMode(PhysicalDisplayId, bool on) = 0;
     virtual status_t getSupportedContentTypes(
             PhysicalDisplayId, std::vector<hal::ContentType>* outSupportedContentTypes) = 0;
@@ -319,11 +317,9 @@
     nsecs_t getRefreshTimestamp(PhysicalDisplayId) const override;
     bool isConnected(PhysicalDisplayId) const override;
 
-    std::vector<std::shared_ptr<const HWC2::Display::Config>> getConfigs(
-            PhysicalDisplayId) const override;
+    DisplayModes getModes(PhysicalDisplayId) const override;
 
-    std::shared_ptr<const HWC2::Display::Config> getActiveConfig(PhysicalDisplayId) const override;
-    int getActiveConfigIndex(PhysicalDisplayId) const override;
+    DisplayModePtr getActiveMode(PhysicalDisplayId) const override;
 
     std::vector<ui::ColorMode> getColorModes(PhysicalDisplayId) const override;
 
@@ -332,10 +328,10 @@
     // Composer 2.4
     DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override;
     bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const override;
-    nsecs_t getDisplayVsyncPeriod(PhysicalDisplayId) const override;
-    status_t setActiveConfigWithConstraints(PhysicalDisplayId, size_t configId,
-                                            const hal::VsyncPeriodChangeConstraints&,
-                                            hal::VsyncPeriodChangeTimeline* outTimeline) override;
+    nsecs_t getDisplayVsyncPeriod(PhysicalDisplayId displayId) const override;
+    status_t setActiveModeWithConstraints(PhysicalDisplayId, HwcConfigIndexType,
+                                          const hal::VsyncPeriodChangeConstraints&,
+                                          hal::VsyncPeriodChangeTimeline* outTimeline) override;
     status_t setAutoLowLatencyMode(PhysicalDisplayId, bool) override;
     status_t getSupportedContentTypes(PhysicalDisplayId, std::vector<hal::ContentType>*) override;
     status_t setContentType(PhysicalDisplayId, hal::ContentType) override;
@@ -362,14 +358,6 @@
     // For unit tests
     friend TestableSurfaceFlinger;
 
-    std::optional<DisplayIdentificationInfo> onHotplugConnect(hal::HWDisplayId);
-    std::optional<DisplayIdentificationInfo> onHotplugDisconnect(hal::HWDisplayId);
-    bool shouldIgnoreHotplugConnect(hal::HWDisplayId, bool hasDisplayIdentificationData) const;
-
-    void loadCapabilities();
-    void loadLayerMetadataSupport();
-    uint32_t getMaxVirtualDisplayCount() const;
-
     struct DisplayData {
         bool isVirtual = false;
         std::unique_ptr<HWC2::Display> hwcDisplay;
@@ -377,7 +365,7 @@
         std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
         buffer_handle_t outbufHandle = nullptr;
         sp<Fence> outbufAcquireFence = Fence::NO_FENCE;
-        std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
+        DisplayModes modes;
 
         bool validateWasSkipped;
         hal::Error presentError;
@@ -391,6 +379,18 @@
         nsecs_t lastHwVsync GUARDED_BY(lastHwVsyncLock) = 0;
     };
 
+    std::optional<DisplayIdentificationInfo> onHotplugConnect(hal::HWDisplayId);
+    std::optional<DisplayIdentificationInfo> onHotplugDisconnect(hal::HWDisplayId);
+    bool shouldIgnoreHotplugConnect(hal::HWDisplayId, bool hasDisplayIdentificationData) const;
+
+    int32_t getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId configId,
+                         hal::Attribute attribute);
+    void loadModes(DisplayData& displayData, hal::HWDisplayId hwcDisplayId);
+
+    void loadCapabilities();
+    void loadLayerMetadataSupport();
+    uint32_t getMaxVirtualDisplayCount() const;
+
     std::unordered_map<HalDisplayId, DisplayData> mDisplayData;
 
     std::unique_ptr<android::Hwc2::Composer> mComposer;
diff --git a/services/surfaceflinger/Scheduler/HwcStrongTypes.h b/services/surfaceflinger/Scheduler/HwcStrongTypes.h
index 8ba4f20..b6a33a2 100644
--- a/services/surfaceflinger/Scheduler/HwcStrongTypes.h
+++ b/services/surfaceflinger/Scheduler/HwcStrongTypes.h
@@ -18,9 +18,11 @@
 
 #include "StrongTyping.h"
 
+#include <cstddef>
+
 namespace android {
 
 // Strong types for the different indexes as they are referring to a different base.
-using HwcConfigIndexType = StrongTyping<int, struct HwcConfigIndexTypeTag, Compare, Add, Hash>;
+using HwcConfigIndexType = StrongTyping<size_t, struct HwcConfigIndexTypeTag, Compare, Add, Hash>;
 
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 0fa71f1..4324855 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -54,7 +54,7 @@
             break;
         case LayerUpdateType::SetFrameRate:
         case LayerUpdateType::Buffer:
-            FrameTimeData frameTime = {.presetTime = lastPresentTime,
+            FrameTimeData frameTime = {.presentTime = lastPresentTime,
                                        .queueTime = mLastUpdatedTime,
                                        .pendingConfigChange = pendingConfigChange};
             mFrameTimes.push_back(frameTime);
@@ -74,7 +74,7 @@
 bool LayerInfo::isFrequent(nsecs_t now) const {
     // If we know nothing about this layer we consider it as frequent as it might be the start
     // of an animation.
-    if (mFrameTimes.size() < FREQUENT_LAYER_WINDOW_SIZE) {
+    if (mFrameTimes.size() < kFrequentLayerWindowSize) {
         return true;
     }
 
@@ -87,14 +87,14 @@
     }
 
     const auto numFrames = std::distance(it, mFrameTimes.end());
-    if (numFrames < FREQUENT_LAYER_WINDOW_SIZE) {
+    if (numFrames < kFrequentLayerWindowSize) {
         return false;
     }
 
     // Layer is considered frequent if the average frame rate is higher than the threshold
     const auto totalTime = mFrameTimes.back().queueTime - it->queueTime;
     return Fps::fromPeriodNsecs(totalTime / (numFrames - 1))
-            .greaterThanOrEqualWithMargin(MIN_FPS_FOR_FREQUENT_LAYER);
+            .greaterThanOrEqualWithMargin(kMinFpsForFrequentLayer);
 }
 
 bool LayerInfo::isAnimating(nsecs_t now) const {
@@ -124,32 +124,21 @@
 }
 
 std::optional<nsecs_t> LayerInfo::calculateAverageFrameTime() const {
-    nsecs_t totalPresentTimeDeltas = 0;
-    nsecs_t totalQueueTimeDeltas = 0;
-    bool missingPresentTime = false;
-    int numFrames = 0;
-    for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
-        // Ignore frames captured during a config change
-        if (it->pendingConfigChange || (it + 1)->pendingConfigChange) {
-            return std::nullopt;
-        }
+    // Ignore frames captured during a config change
+    const bool isDuringConfigChange =
+            std::any_of(mFrameTimes.begin(), mFrameTimes.end(),
+                        [](auto frame) { return frame.pendingConfigChange; });
+    if (isDuringConfigChange) {
+        return std::nullopt;
+    }
 
-        totalQueueTimeDeltas +=
-                std::max(((it + 1)->queueTime - it->queueTime), kMinPeriodBetweenFrames);
-        numFrames++;
-
-        if (!missingPresentTime && (it->presetTime == 0 || (it + 1)->presetTime == 0)) {
-            missingPresentTime = true;
-            // If there are no presentation timestamps and we haven't calculated
-            // one in the past then we can't calculate the refresh rate
-            if (!mLastRefreshRate.reported.isValid()) {
-                return std::nullopt;
-            }
-            continue;
-        }
-
-        totalPresentTimeDeltas +=
-                std::max(((it + 1)->presetTime - it->presetTime), kMinPeriodBetweenFrames);
+    const bool isMissingPresentTime =
+            std::any_of(mFrameTimes.begin(), mFrameTimes.end(),
+                        [](auto frame) { return frame.presentTime == 0; });
+    if (isMissingPresentTime && !mLastRefreshRate.reported.isValid()) {
+        // If there are no presentation timestamps and we haven't calculated
+        // one in the past then we can't calculate the refresh rate
+        return std::nullopt;
     }
 
     // Calculate the average frame time based on presentation timestamps. If those
@@ -160,9 +149,35 @@
     // presentation timestamps we look at the queue time to see if the current refresh rate still
     // matches the content.
 
-    const auto averageFrameTime =
-            static_cast<float>(missingPresentTime ? totalQueueTimeDeltas : totalPresentTimeDeltas) /
-            numFrames;
+    auto getFrameTime = isMissingPresentTime ? [](FrameTimeData data) { return data.queueTime; }
+                                             : [](FrameTimeData data) { return data.presentTime; };
+
+    nsecs_t totalDeltas = 0;
+    int numDeltas = 0;
+    auto prevFrame = mFrameTimes.begin();
+    for (auto it = mFrameTimes.begin() + 1; it != mFrameTimes.end(); ++it) {
+        const auto currDelta = getFrameTime(*it) - getFrameTime(*prevFrame);
+        if (currDelta < kMinPeriodBetweenFrames) {
+            // Skip this frame, but count the delta into the next frame
+            continue;
+        }
+
+        prevFrame = it;
+
+        if (currDelta > kMaxPeriodBetweenFrames) {
+            // Skip this frame and the current delta.
+            continue;
+        }
+
+        totalDeltas += currDelta;
+        numDeltas++;
+    }
+
+    if (numDeltas == 0) {
+        return std::nullopt;
+    }
+
+    const auto averageFrameTime = static_cast<double>(totalDeltas) / static_cast<double>(numDeltas);
     return static_cast<nsecs_t>(averageFrameTime);
 }
 
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index 427cc9e..e32ba09 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -49,12 +49,13 @@
     // Layer is considered frequent if the earliest value in the window of most recent present times
     // is within a threshold. If a layer is infrequent, its average refresh rate is disregarded in
     // favor of a low refresh rate.
-    static constexpr size_t FREQUENT_LAYER_WINDOW_SIZE = 3;
-    static constexpr Fps MIN_FPS_FOR_FREQUENT_LAYER{10.0f};
-    static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS =
-            std::chrono::nanoseconds(MIN_FPS_FOR_FREQUENT_LAYER.getPeriodNsecs()) + 1ms;
+    static constexpr size_t kFrequentLayerWindowSize = 3;
+    static constexpr Fps kMinFpsForFrequentLayer{10.0f};
+    static constexpr auto kMaxPeriodForFrequentLayerNs =
+            std::chrono::nanoseconds(kMinFpsForFrequentLayer.getPeriodNsecs()) + 1ms;
 
     friend class LayerHistoryTest;
+    friend class LayerInfoTest;
 
 public:
     // Holds information about the layer vote
@@ -121,7 +122,7 @@
 private:
     // Used to store the layer timestamps
     struct FrameTimeData {
-        nsecs_t presetTime; // desiredPresentTime, if provided
+        nsecs_t presentTime; // desiredPresentTime, if provided
         nsecs_t queueTime;  // buffer queue time
         bool pendingConfigChange;
     };
@@ -196,6 +197,10 @@
     // Used for sanitizing the heuristic data. If two frames are less than
     // this period apart from each other they'll be considered as duplicates.
     static constexpr nsecs_t kMinPeriodBetweenFrames = Fps(120.f).getPeriodNsecs();
+    // Used for sanitizing the heuristic data. If two frames are more than
+    // this period apart from each other, the interval between them won't be
+    // taken into account when calculating average frame rate.
+    static constexpr nsecs_t kMaxPeriodBetweenFrames = kMinFpsForFrequentLayer.getPeriodNsecs();
     LayerHistory::LayerVoteType mDefaultVote;
 
     LayerVote mLayerVote;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 975754b..b02596a 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -40,8 +40,7 @@
                               to_string(layer.desiredRefreshRate).c_str());
 }
 
-std::vector<Fps> constructKnownFrameRates(
-        const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
+std::vector<Fps> constructKnownFrameRates(const DisplayModes& configs) {
     std::vector<Fps> knownFrameRates = {Fps(24.0f), Fps(30.0f), Fps(45.0f), Fps(60.0f), Fps(72.0f)};
     knownFrameRates.reserve(knownFrameRates.size() + configs.size());
 
@@ -65,8 +64,8 @@
 using RefreshRate = RefreshRateConfigs::RefreshRate;
 
 std::string RefreshRate::toString() const {
-    return base::StringPrintf("{id=%d, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
-                              getConfigId().value(), hwcConfig->getId(), getFps().getValue(),
+    return base::StringPrintf("{id=%zu, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
+                              getConfigId().value(), hwcConfig->getHwcId(), getFps().getValue(),
                               hwcConfig->getWidth(), hwcConfig->getHeight(), getConfigGroup());
 }
 
@@ -88,7 +87,7 @@
 }
 
 std::string RefreshRateConfigs::Policy::toString() const {
-    return base::StringPrintf("default config ID: %d, allowGroupSwitching = %d"
+    return base::StringPrintf("default config ID: %zu, allowGroupSwitching = %d"
                               ", primary range: %s, app request range: %s",
                               defaultConfig.value(), allowGroupSwitching,
                               primaryRange.toString().c_str(), appRequestRange.toString().c_str());
@@ -560,19 +559,16 @@
     mCurrentRefreshRate = mRefreshRates.at(configId).get();
 }
 
-RefreshRateConfigs::RefreshRateConfigs(
-        const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
-        HwcConfigIndexType currentConfigId)
+RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& configs,
+                                       HwcConfigIndexType currentConfigId)
       : mKnownFrameRates(constructKnownFrameRates(configs)) {
     updateDisplayConfigs(configs, currentConfigId);
 }
 
-void RefreshRateConfigs::updateDisplayConfigs(
-        const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
-        HwcConfigIndexType currentConfigId) {
+void RefreshRateConfigs::updateDisplayConfigs(const DisplayModes& configs,
+                                              HwcConfigIndexType currentConfigId) {
     std::lock_guard lock(mLock);
     LOG_ALWAYS_FATAL_IF(configs.empty());
-    LOG_ALWAYS_FATAL_IF(currentConfigId.value() < 0);
     LOG_ALWAYS_FATAL_IF(currentConfigId.value() >= configs.size());
 
     mRefreshRates.clear();
@@ -684,7 +680,7 @@
     outRefreshRates->reserve(mRefreshRates.size());
     for (const auto& [type, refreshRate] : mRefreshRates) {
         if (shouldAddRefreshRate(*refreshRate)) {
-            ALOGV("getSortedRefreshRateListLocked: config %d added to list policy",
+            ALOGV("getSortedRefreshRateListLocked: config %zu added to list policy",
                   refreshRate->configId.value());
             outRefreshRates->push_back(refreshRate.get());
         }
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 4b99145..a5d37c2 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -24,6 +24,7 @@
 #include <optional>
 #include <type_traits>
 
+#include "DisplayHardware/DisplayMode.h"
 #include "DisplayHardware/HWComposer.h"
 #include "Fps.h"
 #include "HwcStrongTypes.h"
@@ -64,8 +65,7 @@
         };
 
     public:
-        RefreshRate(HwcConfigIndexType configId,
-                    std::shared_ptr<const HWC2::Display::Config> config, Fps fps, ConstructorTag)
+        RefreshRate(HwcConfigIndexType configId, DisplayModePtr config, Fps fps, ConstructorTag)
               : configId(configId), hwcConfig(config), fps(std::move(fps)) {}
 
         HwcConfigIndexType getConfigId() const { return configId; }
@@ -101,7 +101,7 @@
         // on the device.
         const HwcConfigIndexType configId;
         // The config itself
-        std::shared_ptr<const HWC2::Display::Config> hwcConfig;
+        DisplayModePtr hwcConfig;
         // Refresh rate in frames per second
         const Fps fps{0.0f};
     };
@@ -296,12 +296,10 @@
     // Returns a known frame rate that is the closest to frameRate
     Fps findClosestKnownFrameRate(Fps frameRate) const;
 
-    RefreshRateConfigs(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
-                       HwcConfigIndexType currentConfigId);
+    RefreshRateConfigs(const DisplayModes& configs, HwcConfigIndexType currentConfigId);
 
-    void updateDisplayConfigs(
-            const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
-            HwcConfigIndexType currentConfig) EXCLUDES(mLock);
+    void updateDisplayConfigs(const DisplayModes& configs, HwcConfigIndexType currentConfig)
+            EXCLUDES(mLock);
 
     // Returns whether switching configs (refresh rate or resolution) is possible.
     // TODO(b/158780872): Consider HAL support, and skip frame rate detection if the configs only
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 49e3903..92786fd 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -564,21 +564,23 @@
 void Scheduler::registerLayer(Layer* layer) {
     if (!mLayerHistory) return;
 
+    scheduler::LayerHistory::LayerVoteType voteType;
+
     if (layer->getWindowType() == InputWindowInfo::Type::STATUS_BAR) {
-        mLayerHistory->registerLayer(layer, scheduler::LayerHistory::LayerVoteType::NoVote);
+        voteType = scheduler::LayerHistory::LayerVoteType::NoVote;
     } else if (!mOptions.useContentDetection) {
         // If the content detection feature is off, all layers are registered at Max. We still keep
         // the layer history, since we use it for other features (like Frame Rate API), so layers
         // still need to be registered.
-        mLayerHistory->registerLayer(layer, scheduler::LayerHistory::LayerVoteType::Max);
+        voteType = scheduler::LayerHistory::LayerVoteType::Max;
+    } else if (layer->getWindowType() == InputWindowInfo::Type::WALLPAPER) {
+        // Running Wallpaper at Min is considered as part of content detection.
+        voteType = scheduler::LayerHistory::LayerVoteType::Min;
     } else {
-        if (layer->getWindowType() == InputWindowInfo::Type::WALLPAPER) {
-            // Running Wallpaper at Min is considered as part of content detection.
-            mLayerHistory->registerLayer(layer, scheduler::LayerHistory::LayerVoteType::Min);
-        } else {
-            mLayerHistory->registerLayer(layer, scheduler::LayerHistory::LayerVoteType::Heuristic);
-        }
+        voteType = scheduler::LayerHistory::LayerVoteType::Heuristic;
     }
+
+    mLayerHistory->registerLayer(layer, voteType);
 }
 
 void Scheduler::recordLayerHistory(Layer* layer, nsecs_t presentTime,
diff --git a/services/surfaceflinger/Scheduler/StrongTyping.h b/services/surfaceflinger/Scheduler/StrongTyping.h
index 6a60257..a05c123 100644
--- a/services/surfaceflinger/Scheduler/StrongTyping.h
+++ b/services/surfaceflinger/Scheduler/StrongTyping.h
@@ -62,8 +62,8 @@
 
 template <typename T, typename W, template <typename> class... Ability>
 struct StrongTyping : Ability<StrongTyping<T, W, Ability...>>... {
-    StrongTyping() : mValue(0) {}
-    explicit StrongTyping(T const& value) : mValue(value) {}
+    constexpr StrongTyping() = default;
+    constexpr explicit StrongTyping(T const& value) : mValue(value) {}
     StrongTyping(StrongTyping const&) = default;
     StrongTyping& operator=(StrongTyping const&) = default;
     explicit inline operator T() const { return mValue; }
@@ -75,7 +75,7 @@
     }
 
 private:
-    T mValue;
+    T mValue{0};
 };
 } // namespace android
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2e00ca8..a6531e1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -226,7 +226,7 @@
     ~UnnecessaryLock() RELEASE() {}
 };
 
-// TODO(b/141333600): Consolidate with HWC2::Display::Config::Builder::getDefaultDensity.
+// TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity.
 constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV;
 
 float getDensityFromProperty(const char* property, bool required) {
@@ -904,14 +904,14 @@
 
     configs->clear();
 
-    for (const auto& hwConfig : getHwComposer().getConfigs(*displayId)) {
+    for (const auto& mode : getHwComposer().getModes(*displayId)) {
         DisplayConfig config;
 
-        auto width = hwConfig->getWidth();
-        auto height = hwConfig->getHeight();
+        auto width = mode->getWidth();
+        auto height = mode->getHeight();
 
-        auto xDpi = hwConfig->getDpiX();
-        auto yDpi = hwConfig->getDpiY();
+        auto xDpi = mode->getDpiX();
+        auto yDpi = mode->getDpiY();
 
         if (isInternal &&
             (internalDisplayOrientation == ui::ROTATION_90 ||
@@ -930,14 +930,14 @@
             config.yDpi = yDpi;
         }
 
-        const nsecs_t period = hwConfig->getVsyncPeriod();
+        const nsecs_t period = mode->getVsyncPeriod();
         config.refreshRate = Fps::fromPeriodNsecs(period).getValue();
 
         const auto vsyncConfigSet =
                 mVsyncConfiguration->getConfigsForRefreshRate(Fps(config.refreshRate));
         config.appVsyncOffset = vsyncConfigSet.late.appOffset;
         config.sfVsyncOffset = vsyncConfigSet.late.sfOffset;
-        config.configGroup = hwConfig->getConfigGroup();
+        config.configGroup = mode->getConfigGroup();
 
         // This is how far in advance a buffer must be queued for
         // presentation at a given time.  If you want a buffer to appear
@@ -1128,7 +1128,7 @@
 
     auto refreshRate =
             mRefreshRateConfigs->getRefreshRateFromConfigId(desiredActiveConfig->configId);
-    ALOGV("performSetActiveConfig changing active config to %d(%s)",
+    ALOGV("performSetActiveConfig changing active config to %zu(%s)",
           refreshRate.getConfigId().value(), refreshRate.getName().c_str());
     const auto display = getDefaultDisplayDeviceLocked();
     if (!display || display->getActiveConfig() == desiredActiveConfig->configId) {
@@ -1158,13 +1158,12 @@
 
     hal::VsyncPeriodChangeTimeline outTimeline;
     auto status =
-            getHwComposer().setActiveConfigWithConstraints(displayId,
-                                                           mUpcomingActiveConfig.configId.value(),
-                                                           constraints, &outTimeline);
+            getHwComposer().setActiveModeWithConstraints(displayId, mUpcomingActiveConfig.configId,
+                                                         constraints, &outTimeline);
     if (status != NO_ERROR) {
-        // setActiveConfigWithConstraints may fail if a hotplug event is just about
+        // setActiveModeWithConstraints may fail if a hotplug event is just about
         // to be sent. We just log the error in this case.
-        ALOGW("setActiveConfigWithConstraints failed: %d", status);
+        ALOGW("setActiveModeWithConstraints failed: %d", status);
         return;
     }
 
@@ -1618,7 +1617,7 @@
 
     // Don't do any updating if the current fps is the same as the new one.
     if (!isDisplayConfigAllowed(refreshRate.getConfigId())) {
-        ALOGV("Skipping config %d as it is not part of allowed configs",
+        ALOGV("Skipping config %zu as it is not part of allowed configs",
               refreshRate.getConfigId().value());
         return;
     }
@@ -1663,7 +1662,7 @@
 }
 
 void SurfaceFlinger::onSeamlessPossible(int32_t /*sequenceId*/, hal::HWDisplayId /*display*/) {
-    // TODO(b/142753666): use constraints when calling to setActiveConfigWithConstrains and
+    // TODO(b/142753666): use constraints when calling to setActiveModeWithConstraints and
     // use this callback to know when to retry in case of SEAMLESS_NOT_POSSIBLE.
 }
 
@@ -1914,17 +1913,19 @@
 
 bool SurfaceFlinger::handleMessageTransaction() {
     ATRACE_CALL();
-
-    if (getTransactionFlags(eTransactionFlushNeeded)) {
-        flushPendingTransactionQueues();
-        flushTransactionQueue();
-    }
     uint32_t transactionFlags = peekTransactionFlags();
+
+    bool flushedATransaction = flushTransactionQueues();
+
     bool runHandleTransaction =
-            ((transactionFlags & (~eTransactionFlushNeeded)) != 0) || mForceTraversal;
+            (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) ||
+            flushedATransaction ||
+            mForceTraversal;
 
     if (runHandleTransaction) {
         handleTransaction(eTransactionMask);
+    } else {
+        getTransactionFlags(eTransactionFlushNeeded);
     }
 
     if (transactionFlushNeeded()) {
@@ -2472,7 +2473,7 @@
                                                     Dataspace::UNKNOWN});
     if (!state.isVirtual()) {
         const auto physicalId = display->getPhysicalId();
-        auto activeConfigId = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(physicalId));
+        auto activeConfigId = getHwComposer().getActiveMode(physicalId)->getId();
         display->setActiveConfig(activeConfigId);
         display->setDeviceProductInfo(state.physical->deviceProductInfo);
     }
@@ -2492,7 +2493,7 @@
     ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN);
     if (state.physical) {
         const auto& activeConfig =
-                getCompositionEngine().getHwComposer().getActiveConfig(state.physical->id);
+                getCompositionEngine().getHwComposer().getActiveMode(state.physical->id);
         width = activeConfig->getWidth();
         height = activeConfig->getHeight();
         pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888);
@@ -2619,9 +2620,9 @@
             // TODO(b/175678251) Call a listener instead.
             if (currentState.physical->hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
                 const auto displayId = currentState.physical->id;
-                const auto configs = getHwComposer().getConfigs(displayId);
-                const auto currentConfig =
-                        HwcConfigIndexType(getHwComposer().getActiveConfigIndex(displayId));
+                const auto configs = getHwComposer().getModes(displayId);
+                const auto currentConfig = getHwComposer().getActiveMode(displayId)->getId();
+                // TODO(b/175678215) Handle the case when currentConfig is not in configs
                 mRefreshRateConfigs->updateDisplayConfigs(configs, currentConfig);
                 mVsyncConfiguration->reset();
                 updatePhaseConfiguration(mRefreshRateConfigs->getCurrentRefreshRate());
@@ -2829,6 +2830,7 @@
         });
     }
 
+    commitInputWindowCommands();
     commitTransaction();
 }
 
@@ -2869,6 +2871,11 @@
                                                                      : nullptr);
 }
 
+void SurfaceFlinger::commitInputWindowCommands() {
+    mInputWindowCommands.merge(mPendingInputWindowCommands);
+    mPendingInputWindowCommands.clear();
+}
+
 void SurfaceFlinger::updateCursorAsync() {
     compositionengine::CompositionRefreshArgs refreshArgs;
     for (const auto& [_, display] : ON_MAIN_THREAD(mDisplays)) {
@@ -2907,11 +2914,9 @@
         return;
     }
 
-    auto currentConfig = HwcConfigIndexType(getHwComposer().getActiveConfigIndex(primaryDisplayId));
-    mRefreshRateConfigs =
-            std::make_unique<scheduler::RefreshRateConfigs>(getHwComposer().getConfigs(
-                                                                    primaryDisplayId),
-                                                            currentConfig);
+    auto currentConfig = getHwComposer().getActiveMode(primaryDisplayId)->getId();
+    const auto modes = getHwComposer().getModes(primaryDisplayId);
+    mRefreshRateConfigs = std::make_unique<scheduler::RefreshRateConfigs>(modes, currentConfig);
     const auto& currRefreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(currentConfig);
     mRefreshRateStats =
             std::make_unique<scheduler::RefreshRateStats>(*mTimeStats, currRefreshRate.getFps(),
@@ -3232,55 +3237,55 @@
     mForceTraversal = true;
 }
 
-void SurfaceFlinger::flushPendingTransactionQueues() {
+bool SurfaceFlinger::flushTransactionQueues() {
     // to prevent onHandleDestroyed from being called while the lock is held,
     // we must keep a copy of the transactions (specifically the composer
     // states) around outside the scope of the lock
     std::vector<const TransactionState> transactions;
+    bool flushedATransaction = false;
     {
-        Mutex::Autolock _l(mQueueLock);
+        Mutex::Autolock _l(mStateLock);
 
-        auto it = mPendingTransactionQueues.begin();
-        while (it != mPendingTransactionQueues.end()) {
+        auto it = mTransactionQueues.begin();
+        while (it != mTransactionQueues.end()) {
             auto& [applyToken, transactionQueue] = *it;
 
             while (!transactionQueue.empty()) {
                 const auto& transaction = transactionQueue.front();
                 if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime,
                                                    transaction.states)) {
+                    setTransactionFlags(eTransactionFlushNeeded);
                     break;
                 }
                 transactions.push_back(transaction);
+                applyTransactionState(transaction.frameTimelineVsyncId, transaction.states,
+                                      transaction.displays, transaction.flags,
+                                      mPendingInputWindowCommands, transaction.desiredPresentTime,
+                                      transaction.isAutoTimestamp, transaction.buffer,
+                                      transaction.postTime, transaction.privileged,
+                                      transaction.hasListenerCallbacks,
+                                      transaction.listenerCallbacks, transaction.originPid,
+                                      transaction.originUid, transaction.id, /*isMainThread*/ true);
                 transactionQueue.pop();
+                flushedATransaction = true;
             }
 
             if (transactionQueue.empty()) {
-                it = mPendingTransactionQueues.erase(it);
-                mTransactionQueueCV.broadcast();
+                it = mTransactionQueues.erase(it);
+                mTransactionCV.broadcast();
             } else {
                 it = std::next(it, 1);
             }
         }
     }
-
-    {
-        Mutex::Autolock _l(mStateLock);
-        for (const auto& transaction : transactions) {
-            applyTransactionState(transaction.frameTimelineVsyncId, transaction.states,
-                                  transaction.displays, transaction.flags, mInputWindowCommands,
-                                  transaction.desiredPresentTime, transaction.isAutoTimestamp,
-                                  transaction.buffer, transaction.postTime, transaction.privileged,
-                                  transaction.hasListenerCallbacks, transaction.listenerCallbacks,
-                                  transaction.originPid, transaction.originUid, transaction.id);
-        }
-    }
+    return flushedATransaction;
 }
 
 bool SurfaceFlinger::transactionFlushNeeded() {
-    Mutex::Autolock _l(mQueueLock);
-    return !mPendingTransactionQueues.empty();
+    return !mTransactionQueues.empty();
 }
 
+
 bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
                                                    const Vector<ComposerState>& states,
                                                    bool updateTransactionCounters) {
@@ -3302,8 +3307,6 @@
         if (s.acquireFence && s.acquireFence->getStatus() == Fence::Status::Unsignaled) {
           ready = false;
         }
-
-        Mutex::Autolock _l(mStateLock);
         sp<Layer> layer = nullptr;
         if (s.surface) {
             layer = fromHandleLocked(s.surface).promote();
@@ -3316,8 +3319,9 @@
             ready = false;
         }
         if (updateTransactionCounters) {
-            // See BufferStateLayer::mPendingBufferTransactions
-            if (layer) layer->incrementPendingBufferCount();
+              // See BufferStateLayer::mPendingBufferTransactions
+              if (layer) layer->incrementPendingBufferCount();
+
         }
     }
     return ready;
@@ -3334,153 +3338,90 @@
     const int64_t postTime = systemTime();
 
     bool privileged = callingThreadHasUnscopedSurfaceFlingerAccess();
-    {
-        Mutex::Autolock _l(mQueueLock);
 
-        // If its TransactionQueue already has a pending TransactionState or if it is pending
-        auto itr = mPendingTransactionQueues.find(applyToken);
-        // if this is an animation frame, wait until prior animation frame has
-        // been applied by SF
-        if (flags & eAnimation) {
-            while (itr != mPendingTransactionQueues.end() ||
-                   (!mTransactionQueue.empty() && mAnimTransactionPending)) {
-                status_t err = mTransactionQueueCV.waitRelative(mQueueLock, s2ns(5));
-                if (CC_UNLIKELY(err != NO_ERROR)) {
-                    ALOGW_IF(err == TIMED_OUT,
-                             "setTransactionState timed out "
-                             "waiting for animation frame to apply");
-                    break;
-                }
-                itr = mPendingTransactionQueues.find(applyToken);
+    Mutex::Autolock _l(mStateLock);
+
+    // If its TransactionQueue already has a pending TransactionState or if it is pending
+    auto itr = mTransactionQueues.find(applyToken);
+    // if this is an animation frame, wait until prior animation frame has
+    // been applied by SF
+    if (flags & eAnimation) {
+        while (itr != mTransactionQueues.end()) {
+            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+            if (CC_UNLIKELY(err != NO_ERROR)) {
+                ALOGW_IF(err == TIMED_OUT,
+                         "setTransactionState timed out "
+                         "waiting for animation frame to apply");
+                break;
             }
+            itr = mTransactionQueues.find(applyToken);
         }
-
-        const bool pendingTransactions = itr != mPendingTransactionQueues.end();
-        // Expected present time is computed and cached on invalidate, so it may be stale.
-        if (!pendingTransactions) {
-            const auto now = systemTime();
-            const bool nextVsyncPending = now < mExpectedPresentTime.load();
-            const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now);
-            mExpectedPresentTime = calculateExpectedPresentTime(stats);
-            // The transaction might arrive just before the next vsync but after
-            // invalidate was called. In that case we need to get the next vsync
-            // afterwards.
-            if (nextVsyncPending) {
-                mExpectedPresentTime += stats.vsyncPeriod;
-            }
-        }
-
-        // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag
-        if (flags & eEarlyWakeup) {
-            ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]");
-        }
-
-        if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) {
-            ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags");
-            flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd);
-        }
-
-        IPCThreadState* ipc = IPCThreadState::self();
-        const int originPid = ipc->getCallingPid();
-        const int originUid = ipc->getCallingUid();
-
-        // Call transactionIsReadyToBeApplied first in case we need to incrementPendingBufferCount
-        // if the transaction contains a buffer.
-        if (!transactionIsReadyToBeApplied(isAutoTimestamp ? 0 : desiredPresentTime, states,
-                                           true) ||
-            pendingTransactions) {
-            mPendingTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays,
-                                                          flags, inputWindowCommands,
-                                                          desiredPresentTime, isAutoTimestamp,
-                                                          uncacheBuffer, postTime, privileged,
-                                                          hasListenerCallbacks, listenerCallbacks,
-                                                          originPid, originUid, transactionId);
-
-            setTransactionFlags(eTransactionFlushNeeded);
-            return NO_ERROR;
-        }
-
-        mTransactionQueue.emplace_back(frameTimelineVsyncId, states, displays, flags,
-                                       inputWindowCommands, desiredPresentTime, isAutoTimestamp,
-                                       uncacheBuffer, postTime, privileged, hasListenerCallbacks,
-                                       listenerCallbacks, originPid, originUid, transactionId);
     }
 
-    const auto schedule = [](uint32_t flags) {
-        if (flags & eEarlyWakeup) return TransactionSchedule::Early;
-        if (flags & eExplicitEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
-        if (flags & eExplicitEarlyWakeupStart) return TransactionSchedule::EarlyStart;
-        return TransactionSchedule::Late;
-    }(flags);
-    setTransactionFlags(eTransactionFlushNeeded, schedule);
+    const bool pendingTransactions = itr != mTransactionQueues.end();
+    // Expected present time is computed and cached on invalidate, so it may be stale.
+    if (!pendingTransactions) {
+        const auto now = systemTime();
+        const bool nextVsyncPending = now < mExpectedPresentTime.load();
+        const DisplayStatInfo stats = mScheduler->getDisplayStatInfo(now);
+        mExpectedPresentTime = calculateExpectedPresentTime(stats);
+        // The transaction might arrive just before the next vsync but after
+        // invalidate was called. In that case we need to get the next vsync
+        // afterwards.
+        if (nextVsyncPending) {
+            mExpectedPresentTime += stats.vsyncPeriod;
+        }
+    }
 
-    // if this is a synchronous transaction, wait for it to take effect
-    // before returning.
-    const bool synchronous = flags & eSynchronous;
-    const bool syncInput = inputWindowCommands.syncInputWindows;
-    if (!synchronous && !syncInput) {
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int originPid = ipc->getCallingPid();
+    const int originUid = ipc->getCallingUid();
+
+    // Call transactionIsReadyToBeApplied first in case we need to incrementPendingBufferCount
+    // if the transaction contains a buffer.
+    if (!transactionIsReadyToBeApplied(isAutoTimestamp ? 0 : desiredPresentTime, states, true) ||
+        pendingTransactions) {
+        mTransactionQueues[applyToken].emplace(frameTimelineVsyncId, states, displays, flags,
+                                               desiredPresentTime, isAutoTimestamp, uncacheBuffer,
+                                               postTime, privileged, hasListenerCallbacks,
+                                               listenerCallbacks, originPid, originUid,
+                                               transactionId);
+        setTransactionFlags(eTransactionFlushNeeded);
         return NO_ERROR;
     }
 
-    // Handle synchronous cases.
-    {
-        Mutex::Autolock _l(mStateLock);
-        if (synchronous) {
-            mTransactionPending = true;
-        }
-        if (syncInput) {
-            mPendingSyncInputWindows = true;
-        }
+    applyTransactionState(frameTimelineVsyncId, states, displays, flags, inputWindowCommands,
+                          desiredPresentTime, isAutoTimestamp, uncacheBuffer, postTime, privileged,
+                          hasListenerCallbacks, listenerCallbacks, originPid, originUid,
+                          transactionId, /*isMainThread*/ false);
+    return NO_ERROR;
+}
 
-        // applyTransactionState can be called by either the main SF thread or by
-        // another process through setTransactionState.  While a given process may wish
-        // to wait on synchronous transactions, the main SF thread should never
-        // be blocked.  Therefore, we only wait if isMainThread is false.
-        while (mTransactionPending || mPendingSyncInputWindows) {
+void SurfaceFlinger::applyTransactionState(
+        int64_t frameTimelineVsyncId, const Vector<ComposerState>& states,
+        const Vector<DisplayState>& displays, uint32_t flags,
+        const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime,
+        bool isAutoTimestamp, const client_cache_t& uncacheBuffer, const int64_t postTime,
+        bool privileged, bool hasListenerCallbacks,
+        const std::vector<ListenerCallbacks>& listenerCallbacks, int originPid, int originUid,
+        uint64_t transactionId, bool isMainThread) {
+    uint32_t transactionFlags = 0;
+
+    if (flags & eAnimation) {
+        // For window updates that are part of an animation we must wait for
+        // previous animation "frames" to be handled.
+        while (!isMainThread && mAnimTransactionPending) {
             status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
             if (CC_UNLIKELY(err != NO_ERROR)) {
                 // just in case something goes wrong in SF, return to the
-                // called after a few seconds.
-                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
-                mTransactionPending = false;
-                mPendingSyncInputWindows = false;
+                // caller after a few seconds.
+                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out "
+                        "waiting for previous animation frame");
+                mAnimTransactionPending = false;
                 break;
             }
         }
     }
-    return NO_ERROR;
-}
-
-void SurfaceFlinger::flushTransactionQueue() {
-    std::vector<TransactionState> transactionQueue;
-    {
-        Mutex::Autolock _l(mQueueLock);
-        if (!mTransactionQueue.empty()) {
-            transactionQueue.swap(mTransactionQueue);
-        }
-        mTransactionQueueCV.broadcast();
-    }
-
-    Mutex::Autolock _l(mStateLock);
-    for (const auto& t : transactionQueue) {
-        applyTransactionState(t.frameTimelineVsyncId, t.states, t.displays, t.flags,
-                              t.inputWindowCommands, t.desiredPresentTime, t.isAutoTimestamp,
-                              t.buffer, t.postTime, t.privileged, t.hasListenerCallbacks,
-                              t.listenerCallbacks, t.originPid, t.originUid, t.id);
-    }
-}
-
-void SurfaceFlinger::applyTransactionState(int64_t frameTimelineVsyncId,
-                                           const Vector<ComposerState>& states,
-                                           const Vector<DisplayState>& displays, uint32_t flags,
-                                           const InputWindowCommands& inputWindowCommands,
-                                           const int64_t desiredPresentTime, bool isAutoTimestamp,
-                                           const client_cache_t& uncacheBuffer,
-                                           const int64_t postTime, bool privileged,
-                                           bool hasListenerCallbacks,
-                                           const std::vector<ListenerCallbacks>& listenerCallbacks,
-                                           int originPid, int originUid, uint64_t transactionId) {
-    uint32_t transactionFlags = 0;
 
     for (const DisplayState& display : displays) {
         transactionFlags |= setDisplayStateLocked(display);
@@ -3539,25 +3480,80 @@
         transactionFlags = eTransactionNeeded;
     }
 
+    // If we are on the main thread, we are about to preform a traversal. Clear the traversal bit
+    // so we don't have to wake up again next frame to preform an uneeded traversal.
+    if (isMainThread && (transactionFlags & eTraversalNeeded)) {
+        transactionFlags = transactionFlags & (~eTraversalNeeded);
+        mForceTraversal = true;
+    }
+
+    const auto schedule = [](uint32_t flags) {
+        if (flags & eEarlyWakeup) return TransactionSchedule::Early;
+        if (flags & eExplicitEarlyWakeupEnd) return TransactionSchedule::EarlyEnd;
+        if (flags & eExplicitEarlyWakeupStart) return TransactionSchedule::EarlyStart;
+        return TransactionSchedule::Late;
+    }(flags);
+
     if (transactionFlags) {
         if (mInterceptor->isEnabled()) {
             mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags,
                                           originPid, originUid, transactionId);
         }
 
-        // We are on the main thread, we are about to preform a traversal. Clear the traversal bit
-        // so we don't have to wake up again next frame to preform an unnecessary traversal.
-        if (transactionFlags & eTraversalNeeded) {
-            transactionFlags = transactionFlags & (~eTraversalNeeded);
-            mForceTraversal = true;
+        // TODO(b/159125966): Remove eEarlyWakeup completly as no client should use this flag
+        if (flags & eEarlyWakeup) {
+            ALOGW("eEarlyWakeup is deprecated. Use eExplicitEarlyWakeup[Start|End]");
         }
-        if (transactionFlags) {
-            setTransactionFlags(transactionFlags);
+
+        if (!privileged && (flags & (eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd))) {
+            ALOGE("Only WindowManager is allowed to use eExplicitEarlyWakeup[Start|End] flags");
+            flags &= ~(eExplicitEarlyWakeupStart | eExplicitEarlyWakeupEnd);
         }
 
+        // this triggers the transaction
+        setTransactionFlags(transactionFlags, schedule);
+
         if (flags & eAnimation) {
             mAnimTransactionPending = true;
         }
+
+        // if this is a synchronous transaction, wait for it to take effect
+        // before returning.
+        const bool synchronous = flags & eSynchronous;
+        const bool syncInput = inputWindowCommands.syncInputWindows;
+        if (!synchronous && !syncInput) {
+            return;
+        }
+
+        if (synchronous) {
+            mTransactionPending = true;
+        }
+        if (syncInput) {
+            mPendingSyncInputWindows = true;
+        }
+
+
+        // applyTransactionState can be called by either the main SF thread or by
+        // another process through setTransactionState.  While a given process may wish
+        // to wait on synchronous transactions, the main SF thread should never
+        // be blocked.  Therefore, we only wait if isMainThread is false.
+        while (!isMainThread && (mTransactionPending || mPendingSyncInputWindows)) {
+            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+            if (CC_UNLIKELY(err != NO_ERROR)) {
+                // just in case something goes wrong in SF, return to the
+                // called after a few seconds.
+                ALOGW_IF(err == TIMED_OUT, "setTransactionState timed out!");
+                mTransactionPending = false;
+                mPendingSyncInputWindows = false;
+                break;
+            }
+        }
+    } else {
+        // Update VsyncModulator state machine even if transaction is not needed.
+        if (schedule == TransactionSchedule::EarlyStart ||
+            schedule == TransactionSchedule::EarlyEnd) {
+            modulateVsync(&VsyncModulator::setTransactionSchedule, schedule);
+        }
     }
 }
 
@@ -3949,7 +3945,7 @@
 }
 
 uint32_t SurfaceFlinger::addInputWindowCommands(const InputWindowCommands& inputWindowCommands) {
-    bool hasChanges = mInputWindowCommands.merge(inputWindowCommands);
+    bool hasChanges = mPendingInputWindowCommands.merge(inputWindowCommands);
     return hasChanges ? eTraversalNeeded : 0;
 }
 
@@ -4214,11 +4210,9 @@
     d.width = 0;
     d.height = 0;
     displays.add(d);
-
-    // This called on the main thread, apply it directly.
-    applyTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0,
-                          mInputWindowCommands, systemTime(), true, {}, systemTime(), true, false,
-                          {}, getpid(), getuid(), 0 /* Undefined transactionId */);
+    setTransactionState(ISurfaceComposer::INVALID_VSYNC_ID, state, displays, 0, nullptr,
+                        mPendingInputWindowCommands, systemTime(), true, {}, false, {},
+                        0 /* Undefined transactionId */);
 
     setPowerModeInternal(display, hal::PowerMode::ON);
     const nsecs_t vsyncPeriod = mRefreshRateConfigs->getCurrentRefreshRate().getVsyncPeriod();
@@ -4797,7 +4791,7 @@
 
     if (const auto displayId = getInternalDisplayIdLocked();
         displayId && getHwComposer().isConnected(*displayId)) {
-        const auto activeConfig = getHwComposer().getActiveConfig(*displayId);
+        const auto activeConfig = getHwComposer().getActiveMode(*displayId);
         std::string fps, xDpi, yDpi;
         if (activeConfig) {
             const auto vsyncPeriod = getHwComposer().getDisplayVsyncPeriod(*displayId);
@@ -5327,7 +5321,7 @@
                     ALOGE("No internal display found.");
                     return NO_ERROR;
                 }
-                const auto numConfigs = getHwComposer().getConfigs(*displayId).size();
+                const auto numConfigs = getHwComposer().getModes(*displayId).size();
                 if (newConfigId >= 0 && newConfigId < numConfigs) {
                     const auto displayToken = getInternalDisplayToken();
                     status_t result = setActiveConfig(displayToken, newConfigId);
@@ -5395,7 +5389,7 @@
 
 void SurfaceFlinger::repaintEverything() {
     mRepaintEverything = true;
-    setTransactionFlags(eTransactionNeeded);
+    signalTransaction();
 }
 
 void SurfaceFlinger::repaintEverythingForHWC() {
@@ -6017,7 +6011,7 @@
 
     if (!display->isPrimary()) {
         // TODO(b/144711714): For non-primary displays we should be able to set an active config
-        // as well. For now, just call directly to setActiveConfigWithConstraints but ideally
+        // as well. For now, just call directly to setActiveModeWithConstraints but ideally
         // it should go thru setDesiredActiveConfig, similar to primary display.
         ALOGV("setAllowedDisplayConfigsInternal for non-primary display");
         const auto displayId = display->getPhysicalId();
@@ -6027,8 +6021,8 @@
         constraints.seamlessRequired = false;
 
         hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
-        if (getHwComposer().setActiveConfigWithConstraints(displayId, policy->defaultConfig.value(),
-                                                           constraints, &timeline) < 0) {
+        if (getHwComposer().setActiveModeWithConstraints(displayId, policy->defaultConfig,
+                                                         constraints, &timeline) < 0) {
             return BAD_VALUE;
         }
         if (timeline.refreshRequired) {
@@ -6037,7 +6031,7 @@
 
         display->setActiveConfig(policy->defaultConfig);
         const nsecs_t vsyncPeriod = getHwComposer()
-                                            .getConfigs(displayId)[policy->defaultConfig.value()]
+                                            .getModes(displayId)[policy->defaultConfig.value()]
                                             ->getVsyncPeriod();
         mScheduler->onNonPrimaryDisplayConfigChanged(mAppConnectionHandle, displayId,
                                                      policy->defaultConfig, vsyncPeriod);
@@ -6077,16 +6071,16 @@
             ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId)
             // NOTE: Choose the default config ID, if Scheduler doesn't have one in mind.
             : mRefreshRateConfigs->getRefreshRateFromConfigId(currentPolicy.defaultConfig);
-    ALOGV("trying to switch to Scheduler preferred config %d (%s)",
+    ALOGV("trying to switch to Scheduler preferred config %zu (%s)",
           preferredRefreshRate.getConfigId().value(), preferredRefreshRate.getName().c_str());
 
     if (isDisplayConfigAllowed(preferredRefreshRate.getConfigId())) {
-        ALOGV("switching to Scheduler preferred config %d",
+        ALOGV("switching to Scheduler preferred config %zu",
               preferredRefreshRate.getConfigId().value());
         setDesiredActiveConfig(
                 {preferredRefreshRate.getConfigId(), Scheduler::ConfigEvent::Changed});
     } else {
-        LOG_ALWAYS_FATAL("Desired config not allowed: %d",
+        LOG_ALWAYS_FATAL("Desired config not allowed: %zu",
                          preferredRefreshRate.getConfigId().value());
     }
 
@@ -6158,9 +6152,10 @@
         return INVALID_OPERATION;
     } else {
         const auto displayId = display->getPhysicalId();
-        *outDefaultConfig = getHwComposer().getActiveConfigIndex(displayId);
+        const auto activeMode = getHwComposer().getActiveMode(displayId);
+        *outDefaultConfig = activeMode->getId().value();
         *outAllowGroupSwitching = false;
-        auto vsyncPeriod = getHwComposer().getActiveConfig(displayId)->getVsyncPeriod();
+        auto vsyncPeriod = activeMode->getVsyncPeriod();
         *outPrimaryRefreshRateMin = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
         *outPrimaryRefreshRateMax = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
         *outAppRequestRefreshRateMin = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index bae15dc..7253593 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -436,16 +436,15 @@
     struct TransactionState {
         TransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& composerStates,
                          const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
-                         const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
-                         bool isAutoTimestamp, const client_cache_t& uncacheBuffer,
-                         int64_t postTime, bool privileged, bool hasListenerCallbacks,
+                         int64_t desiredPresentTime, bool isAutoTimestamp,
+                         const client_cache_t& uncacheBuffer, int64_t postTime, bool privileged,
+                         bool hasListenerCallbacks,
                          std::vector<ListenerCallbacks> listenerCallbacks, int originPid,
                          int originUid, uint64_t transactionId)
               : frameTimelineVsyncId(frameTimelineVsyncId),
                 states(composerStates),
                 displays(displayStates),
                 flags(transactionFlags),
-                inputWindowCommands(inputWindowCommands),
                 desiredPresentTime(desiredPresentTime),
                 isAutoTimestamp(isAutoTimestamp),
                 buffer(uncacheBuffer),
@@ -461,7 +460,6 @@
         Vector<ComposerState> states;
         Vector<DisplayState> displays;
         uint32_t flags;
-        InputWindowCommands inputWindowCommands;
         const int64_t desiredPresentTime;
         const bool isAutoTimestamp;
         client_cache_t buffer;
@@ -727,7 +725,6 @@
     /*
      * Transactions
      */
-    void flushTransactionQueue();
     void applyTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& state,
                                const Vector<DisplayState>& displays, uint32_t flags,
                                const InputWindowCommands& inputWindowCommands,
@@ -735,12 +732,10 @@
                                const client_cache_t& uncacheBuffer, const int64_t postTime,
                                bool privileged, bool hasListenerCallbacks,
                                const std::vector<ListenerCallbacks>& listenerCallbacks,
-                               int originPid, int originUid, uint64_t transactionId)
-            REQUIRES(mStateLock);
+                               int originPid, int originUid, uint64_t transactionId,
+                               bool isMainThread = false) REQUIRES(mStateLock);
     // Returns true if at least one transaction was flushed
     bool flushTransactionQueues();
-    // flush pending transaction that was presented after desiredPresentTime.
-    void flushPendingTransactionQueues();
     // Returns true if there is at least one transaction that needs to be flushed
     bool transactionFlushNeeded();
     uint32_t getTransactionFlags(uint32_t flags);
@@ -758,7 +753,7 @@
     void commitOffscreenLayers();
     bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
                                        const Vector<ComposerState>& states,
-                                       bool updateTransactionCounters = false);
+                                       bool updateTransactionCounters = false) REQUIRES(mStateLock);
     uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
     uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
             REQUIRES(mStateLock);
@@ -1175,11 +1170,8 @@
     uint32_t mTexturePoolSize = 0;
     std::vector<uint32_t> mTexturePool;
 
-    mutable Mutex mQueueLock;
-    Condition mTransactionQueueCV;
-    std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash>
-            mPendingTransactionQueues GUARDED_BY(mQueueLock);
-    std::vector<TransactionState> mTransactionQueue GUARDED_BY(mQueueLock);
+    std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mTransactionQueues;
+
     /*
      * Feature prototyping
      */
@@ -1256,6 +1248,7 @@
     const float mEmulatedDisplayDensity;
 
     sp<os::IInputFlinger> mInputFlinger;
+    InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock);
     // Should only be accessed by the main thread.
     InputWindowCommands mInputWindowCommands;
 
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index 3ef63d5..a361b1e 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -68,9 +68,6 @@
                                        Rect(displayState.layerStackSpaceRect), Rect(resolution));
                 t.apply();
                 SurfaceComposerClient::Transaction().apply(true);
-                // wait for 3 vsyncs to ensure the buffer is latched.
-                usleep(static_cast<int32_t>(1e6 / displayConfig.refreshRate) * 3);
-
                 BufferItem item;
                 itemConsumer->acquireBuffer(&item, 0, true);
                 auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer);
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 13c7c8b..13b26fc 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -49,6 +49,7 @@
         "HWComposerTest.cpp",
         "OneShotTimerTest.cpp",
         "LayerHistoryTest.cpp",
+        "LayerInfoTest.cpp",
         "LayerMetadataTest.cpp",
         "MessageQueueTest.cpp",
         "SurfaceFlinger_CreateDisplayTest.cpp",
@@ -80,7 +81,6 @@
         "VSyncReactorTest.cpp",
         "VsyncConfigurationTest.cpp",
         "mock/DisplayHardware/MockComposer.cpp",
-        "mock/DisplayHardware/MockDisplay.cpp",
         "mock/DisplayHardware/MockPowerAdvisor.cpp",
         "mock/MockEventThread.cpp",
         "mock/MockFrameTimeline.cpp",
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index bc1e88a..5bab534 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -190,10 +190,10 @@
                 .WillRepeatedly(DoAll(SetArgPointee<3>(1), Return(V2_1::Error::NONE)));
     }
 
-    void testSetActiveConfigWithConstraintsCommon(bool isVsyncPeriodSwitchSupported);
+    void testSetActiveModeWithConstraintsCommon(bool isVsyncPeriodSwitchSupported);
 };
 
-void HWComposerConfigsTest::testSetActiveConfigWithConstraintsCommon(
+void HWComposerConfigsTest::testSetActiveModeWithConstraintsCommon(
         bool isVsyncPeriodSwitchSupported) {
     EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
     EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
@@ -229,9 +229,9 @@
     constraints.seamlessRequired = false;
 
     hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
-    constexpr size_t kConfigIndex = 0;
+    constexpr HwcConfigIndexType kConfigIndex(0);
     const auto status =
-            hwc.setActiveConfigWithConstraints(physicalId, kConfigIndex, constraints, &timeline);
+            hwc.setActiveModeWithConstraints(physicalId, kConfigIndex, constraints, &timeline);
     EXPECT_EQ(NO_ERROR, status);
 
     const std::vector<Config> kConfigs{7, 8, 9, 10, 11};
@@ -243,17 +243,18 @@
 
     for (size_t configIndex = 0; configIndex < kConfigs.size(); configIndex++) {
         const auto status =
-                hwc.setActiveConfigWithConstraints(physicalId, configIndex, constraints, &timeline);
+                hwc.setActiveModeWithConstraints(physicalId, HwcConfigIndexType(configIndex),
+                                                 constraints, &timeline);
         EXPECT_EQ(NO_ERROR, status) << "Error when switching to config " << configIndex;
     }
 }
 
-TEST_F(HWComposerConfigsTest, setActiveConfigWithConstraintsWithVsyncSwitchingSupported) {
-    testSetActiveConfigWithConstraintsCommon(/*supported=*/true);
+TEST_F(HWComposerConfigsTest, setActiveModeWithConstraintsWithVsyncSwitchingSupported) {
+    testSetActiveModeWithConstraintsCommon(/*supported=*/true);
 }
 
-TEST_F(HWComposerConfigsTest, setActiveConfigWithConstraintsWithVsyncSwitchingNotSupported) {
-    testSetActiveConfigWithConstraintsCommon(/*supported=*/false);
+TEST_F(HWComposerConfigsTest, setActiveModeWithConstraintsWithVsyncSwitchingNotSupported) {
+    testSetActiveModeWithConstraintsCommon(/*supported=*/false);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 2ee9c64..7024c1e 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -43,8 +43,8 @@
 class LayerHistoryTest : public testing::Test {
 protected:
     static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfo::HISTORY_SIZE;
-    static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfo::MAX_FREQUENT_LAYER_PERIOD_NS;
-    static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfo::FREQUENT_LAYER_WINDOW_SIZE;
+    static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfo::kMaxPeriodForFrequentLayerNs;
+    static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfo::kFrequentLayerWindowSize;
     static constexpr auto PRESENT_TIME_HISTORY_DURATION = LayerInfo::HISTORY_DURATION;
     static constexpr auto REFRESH_RATE_AVERAGE_HISTORY_DURATION =
             LayerInfo::RefreshRateHistory::HISTORY_DURATION;
@@ -110,12 +110,11 @@
                 << "Frame rate is " << frameRate;
     }
 
-    Hwc2::mock::Display mDisplay;
-    RefreshRateConfigs mConfigs{{HWC2::Display::Config::Builder(mDisplay, 0)
+    RefreshRateConfigs mConfigs{{DisplayMode::Builder(0)
                                          .setVsyncPeriod(int32_t(LO_FPS_PERIOD))
                                          .setConfigGroup(0)
                                          .build(),
-                                 HWC2::Display::Config::Builder(mDisplay, 1)
+                                 DisplayMode::Builder(1)
                                          .setVsyncPeriod(int32_t(HI_FPS_PERIOD))
                                          .setConfigGroup(0)
                                          .build()},
diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
new file mode 100644
index 0000000..d5c9b57
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
@@ -0,0 +1,181 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LayerInfoTest"
+
+#include <gtest/gtest.h>
+
+#include "Fps.h"
+#include "Scheduler/LayerHistory.h"
+#include "Scheduler/LayerInfo.h"
+
+namespace android::scheduler {
+
+class LayerInfoTest : public testing::Test {
+protected:
+    using FrameTimeData = LayerInfo::FrameTimeData;
+
+    void setFrameTimes(const std::deque<FrameTimeData>& frameTimes) {
+        layerInfo.mFrameTimes = frameTimes;
+    }
+
+    void setLastRefreshRate(Fps fps) {
+        layerInfo.mLastRefreshRate.reported = fps;
+        layerInfo.mLastRefreshRate.calculated = fps;
+    }
+
+    auto calculateAverageFrameTime() { return layerInfo.calculateAverageFrameTime(); }
+
+    LayerInfo layerInfo{"TestLayerInfo", LayerHistory::LayerVoteType::Heuristic};
+};
+
+namespace {
+
+TEST_F(LayerInfoTest, prefersPresentTime) {
+    std::deque<FrameTimeData> frameTimes;
+    constexpr auto kExpectedFps = Fps(50.0f);
+    constexpr auto kPeriod = kExpectedFps.getPeriodNsecs();
+    constexpr int kNumFrames = 10;
+    for (int i = 1; i <= kNumFrames; i++) {
+        frameTimes.push_back(FrameTimeData{.presentTime = kPeriod * i,
+                                           .queueTime = 0,
+                                           .pendingConfigChange = false});
+    }
+    setFrameTimes(frameTimes);
+    const auto averageFrameTime = calculateAverageFrameTime();
+    ASSERT_TRUE(averageFrameTime.has_value());
+    const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
+    ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
+            << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+}
+
+TEST_F(LayerInfoTest, fallbacksToQueueTimeIfNoPresentTime) {
+    std::deque<FrameTimeData> frameTimes;
+    constexpr auto kExpectedFps = Fps(50.0f);
+    constexpr auto kPeriod = kExpectedFps.getPeriodNsecs();
+    constexpr int kNumFrames = 10;
+    for (int i = 1; i <= kNumFrames; i++) {
+        frameTimes.push_back(FrameTimeData{.presentTime = 0,
+                                           .queueTime = kPeriod * i,
+                                           .pendingConfigChange = false});
+    }
+    setFrameTimes(frameTimes);
+    setLastRefreshRate(Fps(20.0f)); // Set to some valid value
+    const auto averageFrameTime = calculateAverageFrameTime();
+    ASSERT_TRUE(averageFrameTime.has_value());
+    const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
+    ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
+            << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+}
+
+TEST_F(LayerInfoTest, returnsNulloptIfThereWasConfigChange) {
+    std::deque<FrameTimeData> frameTimesWithoutConfigChange;
+    const auto period = Fps(50.0f).getPeriodNsecs();
+    constexpr int kNumFrames = 10;
+    for (int i = 1; i <= kNumFrames; i++) {
+        frameTimesWithoutConfigChange.push_back(FrameTimeData{.presentTime = period * i,
+                                                              .queueTime = period * i,
+                                                              .pendingConfigChange = false});
+    }
+
+    setFrameTimes(frameTimesWithoutConfigChange);
+    ASSERT_TRUE(calculateAverageFrameTime().has_value());
+
+    {
+        // Config change in the first record
+        auto frameTimes = frameTimesWithoutConfigChange;
+        frameTimes[0].pendingConfigChange = true;
+        setFrameTimes(frameTimes);
+        ASSERT_FALSE(calculateAverageFrameTime().has_value());
+    }
+
+    {
+        // Config change in the last record
+        auto frameTimes = frameTimesWithoutConfigChange;
+        frameTimes[frameTimes.size() - 1].pendingConfigChange = true;
+        setFrameTimes(frameTimes);
+        ASSERT_FALSE(calculateAverageFrameTime().has_value());
+    }
+
+    {
+        // Config change in the middle
+        auto frameTimes = frameTimesWithoutConfigChange;
+        frameTimes[frameTimes.size() / 2].pendingConfigChange = true;
+        setFrameTimes(frameTimes);
+        ASSERT_FALSE(calculateAverageFrameTime().has_value());
+    }
+}
+
+// A frame can be recorded twice with very close presentation or queue times.
+// Make sure that this doesn't influence the calculated average FPS.
+TEST_F(LayerInfoTest, ignoresSmallPeriods) {
+    std::deque<FrameTimeData> frameTimes;
+    constexpr auto kExpectedFps = Fps(50.0f);
+    constexpr auto kExpectedPeriod = kExpectedFps.getPeriodNsecs();
+    constexpr auto kSmallPeriod = Fps(150.0f).getPeriodNsecs();
+    constexpr int kNumIterations = 10;
+    for (int i = 1; i <= kNumIterations; i++) {
+        frameTimes.push_back(FrameTimeData{.presentTime = kExpectedPeriod * i,
+                                           .queueTime = 0,
+                                           .pendingConfigChange = false});
+
+        // A duplicate frame
+        frameTimes.push_back(FrameTimeData{.presentTime = kExpectedPeriod * i + kSmallPeriod,
+                                           .queueTime = 0,
+                                           .pendingConfigChange = false});
+    }
+    setFrameTimes(frameTimes);
+    const auto averageFrameTime = calculateAverageFrameTime();
+    ASSERT_TRUE(averageFrameTime.has_value());
+    const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
+    ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
+            << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+}
+
+// There may be a big period of time between two frames. Make sure that
+// this doesn't influence the calculated average FPS.
+TEST_F(LayerInfoTest, ignoresLargePeriods) {
+    std::deque<FrameTimeData> frameTimes;
+    constexpr auto kExpectedFps = Fps(50.0f);
+    constexpr auto kExpectedPeriod = kExpectedFps.getPeriodNsecs();
+    constexpr auto kLargePeriod = Fps(9.0f).getPeriodNsecs();
+
+    auto record = [&](nsecs_t time) {
+        frameTimes.push_back(
+                FrameTimeData{.presentTime = time, .queueTime = 0, .pendingConfigChange = false});
+    };
+
+    auto time = kExpectedPeriod; // Start with non-zero time.
+    record(time);
+    time += kLargePeriod;
+    record(time);
+    constexpr int kNumIterations = 10;
+    for (int i = 1; i <= kNumIterations; i++) {
+        time += kExpectedPeriod;
+        record(time);
+    }
+
+    setFrameTimes(frameTimes);
+    const auto averageFrameTime = calculateAverageFrameTime();
+    ASSERT_TRUE(averageFrameTime.has_value());
+    const auto averageFps = Fps::fromPeriodNsecs(*averageFrameTime);
+    ASSERT_TRUE(kExpectedFps.equalsWithMargin(averageFps))
+            << "Expected " << averageFps << " to be equal to " << kExpectedFps;
+}
+
+} // namespace
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 0813968..27c181d 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -25,13 +25,13 @@
 #include <log/log.h>
 #include <thread>
 
+#include <ui/Size.h>
+
 #include "../../Scheduler/RefreshRateConfigs.h"
 #include "DisplayHardware/HWC2.h"
 #include "Scheduler/RefreshRateConfigs.h"
-#include "mock/DisplayHardware/MockDisplay.h"
 
 using namespace std::chrono_literals;
-using testing::_;
 
 namespace android {
 
@@ -81,67 +81,48 @@
     static inline const HwcConfigIndexType HWC_CONFIG_ID_50 = HwcConfigIndexType(6);
 
     // Test configs
-    std::shared_ptr<const HWC2::Display::Config> mConfig60 =
-            createConfig(HWC_CONFIG_ID_60, 0, Fps(60.0f).getPeriodNsecs());
-    std::shared_ptr<const HWC2::Display::Config> mConfig90 =
-            createConfig(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs());
-    std::shared_ptr<const HWC2::Display::Config> mConfig90DifferentGroup =
+    DisplayModePtr mConfig60 = createConfig(HWC_CONFIG_ID_60, 0, Fps(60.0f).getPeriodNsecs());
+    DisplayModePtr mConfig90 = createConfig(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs());
+    DisplayModePtr mConfig90DifferentGroup =
             createConfig(HWC_CONFIG_ID_90, 1, Fps(90.0f).getPeriodNsecs());
-    std::shared_ptr<const HWC2::Display::Config> mConfig90DifferentResolution =
-            createConfig(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs(), 111, 222);
-    std::shared_ptr<const HWC2::Display::Config> mConfig72 =
-            createConfig(HWC_CONFIG_ID_72, 0, Fps(72.0f).getPeriodNsecs());
-    std::shared_ptr<const HWC2::Display::Config> mConfig72DifferentGroup =
+    DisplayModePtr mConfig90DifferentResolution =
+            createConfig(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs(), ui::Size(111, 222));
+    DisplayModePtr mConfig72 = createConfig(HWC_CONFIG_ID_72, 0, Fps(72.0f).getPeriodNsecs());
+    DisplayModePtr mConfig72DifferentGroup =
             createConfig(HWC_CONFIG_ID_72, 1, Fps(72.0f).getPeriodNsecs());
-    std::shared_ptr<const HWC2::Display::Config> mConfig120 =
-            createConfig(HWC_CONFIG_ID_120, 0, Fps(120.0f).getPeriodNsecs());
-    std::shared_ptr<const HWC2::Display::Config> mConfig120DifferentGroup =
+    DisplayModePtr mConfig120 = createConfig(HWC_CONFIG_ID_120, 0, Fps(120.0f).getPeriodNsecs());
+    DisplayModePtr mConfig120DifferentGroup =
             createConfig(HWC_CONFIG_ID_120, 1, Fps(120.0f).getPeriodNsecs());
-    std::shared_ptr<const HWC2::Display::Config> mConfig30 =
-            createConfig(HWC_CONFIG_ID_30, 0, Fps(30.0f).getPeriodNsecs());
-    std::shared_ptr<const HWC2::Display::Config> mConfig30DifferentGroup =
+    DisplayModePtr mConfig30 = createConfig(HWC_CONFIG_ID_30, 0, Fps(30.0f).getPeriodNsecs());
+    DisplayModePtr mConfig30DifferentGroup =
             createConfig(HWC_CONFIG_ID_30, 1, Fps(30.0f).getPeriodNsecs());
-    std::shared_ptr<const HWC2::Display::Config> mConfig25DifferentGroup =
+    DisplayModePtr mConfig25DifferentGroup =
             createConfig(HWC_CONFIG_ID_25, 1, Fps(25.0f).getPeriodNsecs());
-    std::shared_ptr<const HWC2::Display::Config> mConfig50 =
-            createConfig(HWC_CONFIG_ID_50, 0, Fps(50.0f).getPeriodNsecs());
+    DisplayModePtr mConfig50 = createConfig(HWC_CONFIG_ID_50, 0, Fps(50.0f).getPeriodNsecs());
 
     // Test device configurations
     // The positions of the configs in the arrays below MUST match their IDs. For example,
     // the first config should always be 60Hz, the second 90Hz etc.
-    std::vector<std::shared_ptr<const HWC2::Display::Config>> m60OnlyConfigDevice = {mConfig60};
-    std::vector<std::shared_ptr<const HWC2::Display::Config>> m60_90Device = {mConfig60, mConfig90};
-    std::vector<std::shared_ptr<const HWC2::Display::Config>> m60_90DeviceWithDifferentGroups =
-            {mConfig60, mConfig90DifferentGroup};
-    std::vector<std::shared_ptr<const HWC2::Display::Config>> m60_90DeviceWithDifferentResolutions =
-            {mConfig60, mConfig90DifferentResolution};
-    std::vector<std::shared_ptr<const HWC2::Display::Config>> m60_72_90Device = {mConfig60,
-                                                                                 mConfig90,
-                                                                                 mConfig72};
-    std::vector<std::shared_ptr<const HWC2::Display::Config>> m60_90_72_120Device = {mConfig60,
-                                                                                     mConfig90,
-                                                                                     mConfig72,
-                                                                                     mConfig120};
-    std::vector<std::shared_ptr<const HWC2::Display::Config>> m30_60_72_90_120Device = {mConfig60,
-                                                                                        mConfig90,
-                                                                                        mConfig72,
-                                                                                        mConfig120,
-                                                                                        mConfig30};
-    std::vector<std::shared_ptr<const HWC2::Display::Config>> m30_60Device =
-            {mConfig60, mConfig90DifferentGroup, mConfig72DifferentGroup, mConfig120DifferentGroup,
-             mConfig30};
-    std::vector<std::shared_ptr<const HWC2::Display::Config>> m30_60_72_90Device =
-            {mConfig60, mConfig90, mConfig72, mConfig120DifferentGroup, mConfig30};
-    std::vector<std::shared_ptr<const HWC2::Display::Config>> m30_60_90Device =
-            {mConfig60, mConfig90, mConfig72DifferentGroup, mConfig120DifferentGroup, mConfig30};
-    std::vector<std::shared_ptr<const HWC2::Display::Config>> m25_30_50_60Device =
-            {mConfig60,
-             mConfig90,
-             mConfig72DifferentGroup,
-             mConfig120DifferentGroup,
-             mConfig30DifferentGroup,
-             mConfig25DifferentGroup,
-             mConfig50};
+    DisplayModes m60OnlyConfigDevice = {mConfig60};
+    DisplayModes m60_90Device = {mConfig60, mConfig90};
+    DisplayModes m60_90DeviceWithDifferentGroups = {mConfig60, mConfig90DifferentGroup};
+    DisplayModes m60_90DeviceWithDifferentResolutions = {mConfig60, mConfig90DifferentResolution};
+    DisplayModes m60_72_90Device = {mConfig60, mConfig90, mConfig72};
+    DisplayModes m60_90_72_120Device = {mConfig60, mConfig90, mConfig72, mConfig120};
+    DisplayModes m30_60_72_90_120Device = {mConfig60, mConfig90, mConfig72, mConfig120, mConfig30};
+    DisplayModes m30_60Device = {mConfig60, mConfig90DifferentGroup, mConfig72DifferentGroup,
+                                 mConfig120DifferentGroup, mConfig30};
+    DisplayModes m30_60_72_90Device = {mConfig60, mConfig90, mConfig72, mConfig120DifferentGroup,
+                                       mConfig30};
+    DisplayModes m30_60_90Device = {mConfig60, mConfig90, mConfig72DifferentGroup,
+                                    mConfig120DifferentGroup, mConfig30};
+    DisplayModes m25_30_50_60Device = {mConfig60,
+                                       mConfig90,
+                                       mConfig72DifferentGroup,
+                                       mConfig120DifferentGroup,
+                                       mConfig30DifferentGroup,
+                                       mConfig25DifferentGroup,
+                                       mConfig50};
 
     // Expected RefreshRate objects
     RefreshRate mExpected60Config = {HWC_CONFIG_ID_60, mConfig60, Fps(60),
@@ -162,18 +143,12 @@
                                      RefreshRate::ConstructorTag(0)};
     RefreshRate mExpected120Config = {HWC_CONFIG_ID_120, mConfig120, Fps(120),
                                       RefreshRate::ConstructorTag(0)};
-
-    Hwc2::mock::Display mDisplay;
-
 private:
-    std::shared_ptr<const HWC2::Display::Config> createConfig(HwcConfigIndexType configId,
-                                                              int32_t configGroup,
-                                                              int64_t vsyncPeriod,
-                                                              int32_t hight = -1,
-                                                              int32_t width = -1);
+    DisplayModePtr createConfig(HwcConfigIndexType configId, int32_t configGroup,
+                                int64_t vsyncPeriod, ui::Size resolution = ui::Size());
 };
 
-using Builder = HWC2::Display::Config::Builder;
+using Builder = DisplayMode::Builder;
 
 RefreshRateConfigsTest::RefreshRateConfigsTest() {
     const ::testing::TestInfo* const test_info =
@@ -187,14 +162,14 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
-std::shared_ptr<const HWC2::Display::Config> RefreshRateConfigsTest::createConfig(
-        HwcConfigIndexType configId, int32_t configGroup, int64_t vsyncPeriod, int32_t hight,
-        int32_t width) {
-    return HWC2::Display::Config::Builder(mDisplay, hal::HWConfigId(configId.value()))
+DisplayModePtr RefreshRateConfigsTest::createConfig(HwcConfigIndexType configId,
+                                                    int32_t configGroup, int64_t vsyncPeriod,
+                                                    ui::Size resolution) {
+    return DisplayMode::Builder(hal::HWConfigId(configId.value()))
             .setVsyncPeriod(int32_t(vsyncPeriod))
             .setConfigGroup(configGroup)
-            .setHeight(hight)
-            .setWidth(width)
+            .setHeight(resolution.height)
+            .setWidth(resolution.width)
             .build();
 }
 
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 2188402..4a96fc5 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -28,7 +28,6 @@
 #include "Scheduler/HwcStrongTypes.h"
 #include "Scheduler/RefreshRateConfigs.h"
 #include "Scheduler/RefreshRateStats.h"
-#include "mock/DisplayHardware/MockDisplay.h"
 #include "mock/MockTimeStats.h"
 
 using namespace std::chrono_literals;
@@ -50,7 +49,7 @@
     RefreshRateStatsTest();
     ~RefreshRateStatsTest();
 
-    void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
+    void init(const DisplayModes& configs) {
         mRefreshRateConfigs =
                 std::make_unique<RefreshRateConfigs>(configs, /*currentConfig=*/CONFIG_ID_0);
 
@@ -59,14 +58,12 @@
                                                                /*currentPowerMode=*/PowerMode::OFF);
     }
 
-    Hwc2::mock::Display mDisplay;
     mock::TimeStats mTimeStats;
     std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
     std::unique_ptr<RefreshRateStats> mRefreshRateStats;
 
-    std::shared_ptr<const HWC2::Display::Config> createConfig(HwcConfigIndexType configId,
-                                                              int32_t configGroup,
-                                                              int64_t vsyncPeriod);
+    DisplayModePtr createConfig(HwcConfigIndexType configId, int32_t configGroup,
+                                int64_t vsyncPeriod);
 };
 
 RefreshRateStatsTest::RefreshRateStatsTest() {
@@ -81,9 +78,9 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
-std::shared_ptr<const HWC2::Display::Config> RefreshRateStatsTest::createConfig(
-        HwcConfigIndexType configId, int32_t configGroup, int64_t vsyncPeriod) {
-    return HWC2::Display::Config::Builder(mDisplay, static_cast<hal::HWConfigId>(configId.value()))
+DisplayModePtr RefreshRateStatsTest::createConfig(HwcConfigIndexType configId, int32_t configGroup,
+                                                  int64_t vsyncPeriod) {
+    return DisplayMode::Builder(static_cast<hal::HWConfigId>(configId.value()))
             .setVsyncPeriod(static_cast<int32_t>(vsyncPeriod))
             .setConfigGroup(configGroup)
             .build();
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index fb02a33..757c702 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -24,7 +24,6 @@
 #include "Scheduler/RefreshRateConfigs.h"
 #include "TestableScheduler.h"
 #include "TestableSurfaceFlinger.h"
-#include "mock/DisplayHardware/MockDisplay.h"
 #include "mock/MockEventThread.h"
 #include "mock/MockLayer.h"
 #include "mock/MockSchedulerCallback.h"
@@ -52,12 +51,9 @@
 
     SchedulerTest();
 
-    Hwc2::mock::Display mDisplay;
-    const scheduler::RefreshRateConfigs mConfigs{{HWC2::Display::Config::Builder(mDisplay, 0)
-                                                          .setVsyncPeriod(16'666'667)
-                                                          .setConfigGroup(0)
-                                                          .build()},
-                                                 HwcConfigIndexType(0)};
+    const scheduler::RefreshRateConfigs
+            mConfigs{{DisplayMode::Builder(0).setVsyncPeriod(16'666'667).setConfigGroup(0).build()},
+                     HwcConfigIndexType(0)};
 
     mock::SchedulerCallback mSchedulerCallback;
 
diff --git a/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp b/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp
index 5406879..45b7610 100644
--- a/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp
@@ -24,7 +24,6 @@
 
 TEST(StrongTypeTest, comparison) {
     using SpunkyType = StrongTyping<int, struct SpunkyTypeTag, Compare>;
-    SpunkyType f2(22);
     SpunkyType f1(10);
 
     EXPECT_TRUE(f1 == f1);
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 739a9b2..2b8a67d 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -41,7 +41,6 @@
 #include "SurfaceFlingerDefaultFactory.h"
 #include "SurfaceInterceptor.h"
 #include "TestableScheduler.h"
-#include "mock/DisplayHardware/MockDisplay.h"
 #include "mock/MockDisplayIdGenerator.h"
 #include "mock/MockFrameTimeline.h"
 #include "mock/MockFrameTracer.h"
@@ -211,17 +210,12 @@
                         std::unique_ptr<EventThread> appEventThread,
                         std::unique_ptr<EventThread> sfEventThread,
                         ISchedulerCallback* callback = nullptr, bool hasMultipleConfigs = false) {
-        std::vector<std::shared_ptr<const HWC2::Display::Config>> configs{
-                HWC2::Display::Config::Builder(mDisplay, 0)
-                        .setVsyncPeriod(16'666'667)
-                        .setConfigGroup(0)
-                        .build()};
+        DisplayModes configs{
+                DisplayMode::Builder(0).setVsyncPeriod(16'666'667).setConfigGroup(0).build()};
 
         if (hasMultipleConfigs) {
-            configs.emplace_back(HWC2::Display::Config::Builder(mDisplay, 1)
-                                         .setVsyncPeriod(11'111'111)
-                                         .setConfigGroup(0)
-                                         .build());
+            configs.emplace_back(
+                    DisplayMode::Builder(1).setVsyncPeriod(11'111'111).setConfigGroup(0).build());
         }
 
         const auto currConfig = HwcConfigIndexType(0);
@@ -366,7 +360,7 @@
         return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
     }
 
-    auto& getPendingTransactionQueue() { return mFlinger->mPendingTransactionQueues; }
+    auto& getTransactionQueue() { return mFlinger->mTransactionQueues; }
 
     auto setTransactionState(int64_t frameTimelineVsyncId, const Vector<ComposerState>& states,
                              const Vector<DisplayState>& displays, uint32_t flags,
@@ -382,7 +376,7 @@
                                              listenerCallbacks, transactionId);
     }
 
-    auto flushPendingTransactionQueues() { return mFlinger->flushPendingTransactionQueues(); };
+    auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); };
 
     auto onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
         return mFlinger->onTransact(code, data, reply, flags);
@@ -470,7 +464,6 @@
         }
 
         auto& mutableIsConnected() { return this->mIsConnected; }
-        auto& mutableConfigs() { return this->mConfigs; }
         auto& mutableLayers() { return this->mLayers; }
     };
 
@@ -545,19 +538,20 @@
             auto display = std::make_unique<HWC2Display>(*composer, *mCapabilities, mHwcDisplayId,
                                                          mHwcDisplayType);
 
-            auto config = HWC2::Display::Config::Builder(*display, mActiveConfig);
-            config.setWidth(mWidth);
-            config.setHeight(mHeight);
-            config.setVsyncPeriod(mRefreshRate);
-            config.setDpiX(mDpiX);
-            config.setDpiY(mDpiY);
-            config.setConfigGroup(mConfigGroup);
-            display->mutableConfigs().emplace(static_cast<int32_t>(mActiveConfig), config.build());
             display->mutableIsConnected() = true;
             display->setPowerMode(mPowerMode);
-
             flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = std::move(display);
 
+            auto config = DisplayMode::Builder(mActiveConfig)
+                                  .setWidth(mWidth)
+                                  .setHeight(mHeight)
+                                  .setVsyncPeriod(mRefreshRate)
+                                  .setDpiX(mDpiX)
+                                  .setDpiY(mDpiY)
+                                  .setConfigGroup(mConfigGroup)
+                                  .build();
+            flinger->mutableHwcDisplayData()[mDisplayId].modes.push_back(config);
+
             if (mHwcDisplayType == hal::DisplayType::PHYSICAL) {
                 const auto physicalId = PhysicalDisplayId::tryCast(mDisplayId);
                 LOG_ALWAYS_FATAL_IF(!physicalId);
@@ -704,7 +698,6 @@
     surfaceflinger::test::Factory mFactory;
     sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
     TestableScheduler* mScheduler = nullptr;
-    Hwc2::mock::Display mDisplay;
     mock::DisplayIdGenerator<GpuVirtualDisplayId> mGpuVirtualDisplayIdGenerator;
 };
 
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index a4a4408..06275c6 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -127,7 +127,7 @@
     }
 
     void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
-        ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
+        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
         // called in SurfaceFlinger::signalTransaction
         EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
         EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillOnce(Return(systemTime()));
@@ -154,12 +154,12 @@
         } else {
             EXPECT_LE(returnedTime, applicationTime + s2ns(5));
         }
-        auto transactionQueue = mFlinger.getPendingTransactionQueue();
+        auto transactionQueue = mFlinger.getTransactionQueue();
         EXPECT_EQ(0, transactionQueue.size());
     }
 
     void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
-        ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
+        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
         // called in SurfaceFlinger::signalTransaction
         EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
 
@@ -183,12 +183,12 @@
         nsecs_t returnedTime = systemTime();
         EXPECT_LE(returnedTime, applicationSentTime + s2ns(5));
         // This transaction should have been placed on the transaction queue
-        auto transactionQueue = mFlinger.getPendingTransactionQueue();
+        auto transactionQueue = mFlinger.getTransactionQueue();
         EXPECT_EQ(1, transactionQueue.size());
     }
 
     void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) {
-        ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
+        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
         // called in SurfaceFlinger::signalTransaction
         nsecs_t time = systemTime();
         EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
@@ -239,7 +239,7 @@
         }
 
         // check that there is one binder on the pending queue.
-        auto transactionQueue = mFlinger.getPendingTransactionQueue();
+        auto transactionQueue = mFlinger.getTransactionQueue();
         EXPECT_EQ(1, transactionQueue.size());
 
         auto& [applyToken, transactionStates] = *(transactionQueue.begin());
@@ -258,7 +258,7 @@
 };
 
 TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
-    ASSERT_EQ(0, mFlinger.getPendingTransactionQueue().size());
+    ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
     // called in SurfaceFlinger::signalTransaction
     EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
 
@@ -275,7 +275,7 @@
                                  transactionA.isAutoTimestamp, transactionA.uncacheBuffer,
                                  mHasListenerCallbacks, mCallbacks, transactionA.id);
 
-    auto& transactionQueue = mFlinger.getPendingTransactionQueue();
+    auto& transactionQueue = mFlinger.getTransactionQueue();
     ASSERT_EQ(1, transactionQueue.size());
 
     auto& [applyToken, transactionStates] = *(transactionQueue.begin());
@@ -294,9 +294,9 @@
                                  empty.desiredPresentTime, empty.isAutoTimestamp,
                                  empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks, empty.id);
 
-    // flush pending transaction queue should flush as desiredPresentTime has
+    // flush transaction queue should flush as desiredPresentTime has
     // passed
-    mFlinger.flushPendingTransactionQueues();
+    mFlinger.flushTransactionQueues();
 
     EXPECT_EQ(0, transactionQueue.size());
 }
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.cpp
deleted file mode 100644
index c9788af..0000000
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.cpp
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright 2019 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.
- */
-
-#include "mock/DisplayHardware/MockDisplay.h"
-
-namespace android::Hwc2::mock {
-
-// Explicit default instantiation is recommended.
-Display::Display() = default;
-Display::~Display() = default;
-
-} // namespace android::Hwc2::mock
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
deleted file mode 100644
index a96d9db..0000000
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2019 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 "DisplayHardware/HWC2.h"
-
-using android::HWC2::Layer;
-
-namespace android::Hwc2::mock {
-
-namespace hal = android::hardware::graphics::composer::hal;
-
-class Display : public HWC2::Display {
-public:
-    using Layer = ::Layer;
-
-    Display();
-    ~Display();
-
-    MOCK_CONST_METHOD0(getId, hal::HWDisplayId());
-    MOCK_CONST_METHOD0(isConnected, bool());
-    MOCK_METHOD1(setConnected, void(bool));
-    MOCK_CONST_METHOD0(getCapabilities, const std::unordered_set<hal::DisplayCapability>&());
-
-    MOCK_METHOD0(acceptChanges, hal::Error());
-    MOCK_METHOD1(createLayer, hal::Error(Layer**));
-    MOCK_METHOD1(destroyLayer, hal::Error(Layer*));
-    MOCK_CONST_METHOD1(getActiveConfig, hal::Error(std::shared_ptr<const Config>*));
-    MOCK_CONST_METHOD1(getActiveConfigIndex, hal::Error(int* outIndex));
-    MOCK_METHOD1(getChangedCompositionTypes,
-                 hal::Error(std::unordered_map<Layer*, hal::Composition>*));
-    MOCK_CONST_METHOD1(getColorModes, hal::Error(std::vector<hal::ColorMode>*));
-
-    MOCK_CONST_METHOD0(getSupportedPerFrameMetadata, int32_t());
-    MOCK_CONST_METHOD2(getRenderIntents,
-                       hal::Error(hal::ColorMode, std::vector<hal::RenderIntent>*));
-    MOCK_METHOD2(getDataspaceSaturationMatrix, hal::Error(hal::Dataspace, android::mat4*));
-    MOCK_CONST_METHOD0(getConfigs, std::vector<std::shared_ptr<const Config>>());
-
-    MOCK_CONST_METHOD1(getName, hal::Error(std::string*));
-    MOCK_METHOD2(getRequests,
-                 hal::Error(hal::DisplayRequest*, std::unordered_map<Layer*, hal::LayerRequest>*));
-    MOCK_CONST_METHOD1(getType, hal::Error(hal::DisplayType*));
-    MOCK_CONST_METHOD1(supportsDoze, hal::Error(bool*));
-    MOCK_CONST_METHOD1(getHdrCapabilities, hal::Error(android::HdrCapabilities*));
-    MOCK_CONST_METHOD3(getDisplayedContentSamplingAttributes,
-                       hal::Error(hal::PixelFormat*, hal::Dataspace*, uint8_t*));
-    MOCK_CONST_METHOD3(setDisplayContentSamplingEnabled, hal::Error(bool, uint8_t, uint64_t));
-    MOCK_CONST_METHOD3(getDisplayedContentSample,
-                       hal::Error(uint64_t, uint64_t, android::DisplayedFrameStats*));
-    MOCK_CONST_METHOD1(
-            getReleaseFences,
-            hal::Error(std::unordered_map<Layer*, android::sp<android::Fence>>* outFences));
-    MOCK_METHOD1(present, hal::Error(android::sp<android::Fence>*));
-    MOCK_METHOD1(setActiveConfig, hal::Error(const std::shared_ptr<const HWC2::Display::Config>&));
-    MOCK_METHOD4(setClientTarget,
-                 hal::Error(uint32_t, const android::sp<android::GraphicBuffer>&,
-                            const android::sp<android::Fence>&, hal::Dataspace));
-    MOCK_METHOD2(setColorMode, hal::Error(hal::ColorMode, hal::RenderIntent));
-    MOCK_METHOD2(setColorTransform, hal::Error(const android::mat4&, hal::ColorTransform));
-    MOCK_METHOD2(setOutputBuffer,
-                 hal::Error(const android::sp<android::GraphicBuffer>&,
-                            const android::sp<android::Fence>&));
-    MOCK_METHOD1(setPowerMode, hal::Error(hal::PowerMode));
-    MOCK_METHOD1(setVsyncEnabled, hal::Error(hal::Vsync));
-    MOCK_METHOD2(validate, hal::Error(uint32_t*, uint32_t*));
-    MOCK_METHOD4(presentOrValidate,
-                 hal::Error(uint32_t*, uint32_t*, android::sp<android::Fence>*, uint32_t*));
-    MOCK_METHOD1(setDisplayBrightness, std::future<hal::Error>(float));
-    MOCK_CONST_METHOD1(getDisplayVsyncPeriod, hal::Error(nsecs_t*));
-    MOCK_METHOD3(setActiveConfigWithConstraints,
-                 hal::Error(const std::shared_ptr<const HWC2::Display::Config>&,
-                            const hal::VsyncPeriodChangeConstraints&,
-                            hal::VsyncPeriodChangeTimeline*));
-    MOCK_METHOD1(setAutoLowLatencyMode, hal::Error(bool on));
-    MOCK_CONST_METHOD1(getSupportedContentTypes, hal::Error(std::vector<hal::ContentType>*));
-    MOCK_METHOD1(setContentType, hal::Error(hal::ContentType));
-    MOCK_METHOD1(getClientTargetProperty, hal::Error(hal::ClientTargetProperty*));
-    MOCK_CONST_METHOD1(getConnectionType, hal::Error(android::DisplayConnectionType*));
-    MOCK_CONST_METHOD0(isVsyncPeriodSwitchSupported, bool());
-};
-
-} // namespace android::Hwc2::mock