Merge Android R (rvc-dev-plus-aosp-without-vendor@6692709)

Bug: 166295507
Merged-In: I70ea776b8589ac3a7982c710c5c8b2941d86e55b
Change-Id: Ic1d535e9d2d6f80d95215240dbdb024995b045f8
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 53a3611..fe2af80 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -18,11 +18,25 @@
     test_suites: ["device-tests"],
     srcs: [
         "BufferGenerator.cpp",
+        "CommonTypes_test.cpp",
         "Credentials_test.cpp",
+        "DereferenceSurfaceControl_test.cpp",
+        "DisplayConfigs_test.cpp",
+        "EffectLayer_test.cpp",
         "InvalidHandles_test.cpp",
+        "LayerCallback_test.cpp",
+        "LayerRenderTypeTransaction_test.cpp",
+        "LayerTransaction_test.cpp",
+        "LayerTypeAndRenderTypeTransaction_test.cpp",
+        "LayerTypeTransaction_test.cpp",
+        "LayerUpdate_test.cpp",
+        "MirrorLayer_test.cpp",
+        "MultiDisplayLayerBounds_test.cpp",
+        "RelativeZ_test.cpp",
+        "SetFrameRate_test.cpp",
+        "SetGeometry_test.cpp",
         "Stress_test.cpp",
         "SurfaceInterceptor_test.cpp",
-        "Transaction_test.cpp",
         "VirtualDisplay_test.cpp",
     ],
     data: ["SurfaceFlinger_test.filter"],
@@ -30,6 +44,52 @@
         "libtrace_proto",
     ],
     shared_libs: [
+        "android.hardware.graphics.common-ndk_platform",
+        "android.hardware.graphics.common@1.2",
+        "android.hardware.graphics.composer@2.1",
+        "libandroid",
+        "libbinder",
+        "libcutils",
+        "libEGL",
+        "libGLESv2",
+        "libgui",
+        "liblayers_proto",
+        "liblog",
+        "libnativewindow",
+        "libprotobuf-cpp-full",
+        "libui",
+        "libutils",
+    ],
+    header_libs: [
+        "libnativewindow_headers",
+    ],
+}
+
+cc_defaults {
+    name: "ipc_defaults",
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+}
+
+cc_test {
+    name: "IPC_test",
+    defaults: ["ipc_defaults"],
+    test_suites: ["device-tests"],
+    srcs: [
+        "BufferGenerator.cpp",
+        "IPC_test.cpp",
+    ],
+    cppflags: [
+        "-Wall",
+        "-Werror",
+        "-Wformat",
+        "-Wthread-safety",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+    shared_libs: [
         "libandroid",
         "libbinder",
         "libcutils",
@@ -39,17 +99,18 @@
         "liblayers_proto",
         "liblog",
         "libprotobuf-cpp-full",
-        "libtimestats_proto",
         "libui",
         "libutils",
-    ]
-
+    ],
+    cpp_std: "experimental",
+    gnu_extensions: false,
 }
 
 subdirs = [
     "fakehwc",
     "hwc2",
     "unittests",
+    "utils",
     "vsync",
     "waitforvsync",
 ]
diff --git a/services/surfaceflinger/tests/BufferGenerator.cpp b/services/surfaceflinger/tests/BufferGenerator.cpp
index 8ddda60..4868c12 100644
--- a/services/surfaceflinger/tests/BufferGenerator.cpp
+++ b/services/surfaceflinger/tests/BufferGenerator.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <gui/BufferItemConsumer.h>
 #include <gui/Surface.h>
 
@@ -84,7 +88,7 @@
     sp<Surface> mSurface;
 };
 
-/* Used to generate valid fences. It is not possible to create a dummy sync
+/* Used to generate valid fences. It is not possible to create a placeholder sync
  * fence for testing. Egl can generate buffers along with a valid fence.
  * The buffer cannot be guaranteed to be the same format across all devices so
  * a CPU filled buffer is used instead. The Egl fence is used along with the
@@ -379,3 +383,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/CommonTypes_test.cpp b/services/surfaceflinger/tests/CommonTypes_test.cpp
new file mode 100644
index 0000000..25b4615
--- /dev/null
+++ b/services/surfaceflinger/tests/CommonTypes_test.cpp
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 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 <aidl/android/hardware/graphics/common/BlendMode.h>
+#include <aidl/android/hardware/graphics/common/Dataspace.h>
+
+#include <android/data_space.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <android/hardware/graphics/composer/2.1/IComposerClient.h>
+
+using AidlBlendMode = aidl::android::hardware::graphics::common::BlendMode;
+using AidlDataspace = aidl::android::hardware::graphics::common::Dataspace;
+
+using HidlBlendMode = android::hardware::graphics::composer::V2_1::IComposerClient::BlendMode;
+using HidlDataspace = android::hardware::graphics::common::V1_2::Dataspace;
+
+static_assert(static_cast<uint32_t>(AidlBlendMode::INVALID) ==
+              static_cast<uint32_t>(HidlBlendMode::INVALID));
+static_assert(static_cast<uint32_t>(AidlBlendMode::NONE) ==
+              static_cast<uint32_t>(HidlBlendMode::NONE));
+static_assert(static_cast<uint32_t>(AidlBlendMode::PREMULTIPLIED) ==
+              static_cast<uint32_t>(HidlBlendMode::PREMULTIPLIED));
+static_assert(static_cast<uint32_t>(AidlBlendMode::COVERAGE) ==
+              static_cast<uint32_t>(HidlBlendMode::COVERAGE));
+
+static_assert(static_cast<uint32_t>(ADATASPACE_UNKNOWN) ==
+              static_cast<uint32_t>(AidlDataspace::UNKNOWN));
+static_assert(static_cast<uint32_t>(ADATASPACE_SCRGB_LINEAR) ==
+              static_cast<uint32_t>(AidlDataspace::SCRGB_LINEAR));
+static_assert(static_cast<uint32_t>(ADATASPACE_SRGB) == static_cast<uint32_t>(AidlDataspace::SRGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_SCRGB) ==
+              static_cast<uint32_t>(AidlDataspace::SCRGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_DISPLAY_P3) ==
+              static_cast<uint32_t>(AidlDataspace::DISPLAY_P3));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT2020_PQ) ==
+              static_cast<uint32_t>(AidlDataspace::BT2020_PQ));
+static_assert(static_cast<uint32_t>(ADATASPACE_ADOBE_RGB) ==
+              static_cast<uint32_t>(AidlDataspace::ADOBE_RGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT2020) ==
+              static_cast<uint32_t>(AidlDataspace::BT2020));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT709) ==
+              static_cast<uint32_t>(AidlDataspace::BT709));
+static_assert(static_cast<uint32_t>(ADATASPACE_DCI_P3) ==
+              static_cast<uint32_t>(AidlDataspace::DCI_P3));
+static_assert(static_cast<uint32_t>(ADATASPACE_SRGB_LINEAR) ==
+              static_cast<uint32_t>(AidlDataspace::SRGB_LINEAR));
+
+static_assert(static_cast<uint32_t>(ADATASPACE_UNKNOWN) ==
+              static_cast<uint32_t>(HidlDataspace::UNKNOWN));
+static_assert(static_cast<uint32_t>(ADATASPACE_SCRGB_LINEAR) ==
+              static_cast<uint32_t>(HidlDataspace::V0_SCRGB_LINEAR));
+static_assert(static_cast<uint32_t>(ADATASPACE_SRGB) ==
+              static_cast<uint32_t>(HidlDataspace::V0_SRGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_SCRGB) ==
+              static_cast<uint32_t>(HidlDataspace::V0_SCRGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_DISPLAY_P3) ==
+              static_cast<uint32_t>(HidlDataspace::DISPLAY_P3));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT2020_PQ) ==
+              static_cast<uint32_t>(HidlDataspace::BT2020_PQ));
+static_assert(static_cast<uint32_t>(ADATASPACE_ADOBE_RGB) ==
+              static_cast<uint32_t>(HidlDataspace::ADOBE_RGB));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT2020) ==
+              static_cast<uint32_t>(HidlDataspace::BT2020));
+static_assert(static_cast<uint32_t>(ADATASPACE_BT709) ==
+              static_cast<uint32_t>(HidlDataspace::V0_BT709));
+static_assert(static_cast<uint32_t>(ADATASPACE_DCI_P3) ==
+              static_cast<uint32_t>(HidlDataspace::DCI_P3));
+static_assert(static_cast<uint32_t>(ADATASPACE_SRGB_LINEAR) ==
+              static_cast<uint32_t>(HidlDataspace::V0_SRGB_LINEAR));
+
+static_assert(static_cast<uint32_t>(AidlDataspace::UNKNOWN) ==
+              static_cast<uint32_t>(HidlDataspace::UNKNOWN));
+static_assert(static_cast<uint32_t>(AidlDataspace::ARBITRARY) ==
+              static_cast<uint32_t>(HidlDataspace::ARBITRARY));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_SHIFT) ==
+              static_cast<uint32_t>(HidlDataspace::STANDARD_SHIFT));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_MASK) ==
+              static_cast<uint32_t>(HidlDataspace::STANDARD_MASK));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_UNSPECIFIED) ==
+              static_cast<uint32_t>(HidlDataspace::STANDARD_UNSPECIFIED));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT709) ==
+              static_cast<uint32_t>(HidlDataspace::STANDARD_BT709));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT601_625) ==
+              static_cast<uint32_t>(HidlDataspace::STANDARD_BT601_625));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT601_625_UNADJUSTED) ==
+              static_cast<uint32_t>(HidlDataspace::STANDARD_BT601_625_UNADJUSTED));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT601_525) ==
+              static_cast<uint32_t>(HidlDataspace::STANDARD_BT601_525));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT601_525_UNADJUSTED) ==
+              static_cast<uint32_t>(HidlDataspace::STANDARD_BT601_525_UNADJUSTED));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT2020) ==
+              static_cast<uint32_t>(HidlDataspace::STANDARD_BT2020));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT2020_CONSTANT_LUMINANCE) ==
+              static_cast<uint32_t>(HidlDataspace::STANDARD_BT2020_CONSTANT_LUMINANCE));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_BT470M) ==
+              static_cast<uint32_t>(HidlDataspace::STANDARD_BT470M));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_FILM) ==
+              static_cast<uint32_t>(HidlDataspace::STANDARD_FILM));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_DCI_P3) ==
+              static_cast<uint32_t>(HidlDataspace::STANDARD_DCI_P3));
+static_assert(static_cast<uint32_t>(AidlDataspace::STANDARD_ADOBE_RGB) ==
+              static_cast<uint32_t>(HidlDataspace::STANDARD_ADOBE_RGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_SHIFT) ==
+              static_cast<uint32_t>(HidlDataspace::TRANSFER_SHIFT));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_MASK) ==
+              static_cast<uint32_t>(HidlDataspace::TRANSFER_MASK));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_UNSPECIFIED) ==
+              static_cast<uint32_t>(HidlDataspace::TRANSFER_UNSPECIFIED));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_LINEAR) ==
+              static_cast<uint32_t>(HidlDataspace::TRANSFER_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_SRGB) ==
+              static_cast<uint32_t>(HidlDataspace::TRANSFER_SRGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_SMPTE_170M) ==
+              static_cast<uint32_t>(HidlDataspace::TRANSFER_SMPTE_170M));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_GAMMA2_2) ==
+              static_cast<uint32_t>(HidlDataspace::TRANSFER_GAMMA2_2));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_GAMMA2_6) ==
+              static_cast<uint32_t>(HidlDataspace::TRANSFER_GAMMA2_6));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_GAMMA2_8) ==
+              static_cast<uint32_t>(HidlDataspace::TRANSFER_GAMMA2_8));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_ST2084) ==
+              static_cast<uint32_t>(HidlDataspace::TRANSFER_ST2084));
+static_assert(static_cast<uint32_t>(AidlDataspace::TRANSFER_HLG) ==
+              static_cast<uint32_t>(HidlDataspace::TRANSFER_HLG));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_SHIFT) ==
+              static_cast<uint32_t>(HidlDataspace::RANGE_SHIFT));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_MASK) ==
+              static_cast<uint32_t>(HidlDataspace::RANGE_MASK));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_UNSPECIFIED) ==
+              static_cast<uint32_t>(HidlDataspace::RANGE_UNSPECIFIED));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_FULL) ==
+              static_cast<uint32_t>(HidlDataspace::RANGE_FULL));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_LIMITED) ==
+              static_cast<uint32_t>(HidlDataspace::RANGE_LIMITED));
+static_assert(static_cast<uint32_t>(AidlDataspace::RANGE_EXTENDED) ==
+              static_cast<uint32_t>(HidlDataspace::RANGE_EXTENDED));
+static_assert(static_cast<uint32_t>(AidlDataspace::SRGB_LINEAR) ==
+              static_cast<uint32_t>(HidlDataspace::V0_SRGB_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::SCRGB_LINEAR) ==
+              static_cast<uint32_t>(HidlDataspace::V0_SCRGB_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::SRGB) ==
+              static_cast<uint32_t>(HidlDataspace::V0_SRGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::SCRGB) ==
+              static_cast<uint32_t>(HidlDataspace::V0_SCRGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::JFIF) ==
+              static_cast<uint32_t>(HidlDataspace::V0_JFIF));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT601_625) ==
+              static_cast<uint32_t>(HidlDataspace::V0_BT601_625));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT601_525) ==
+              static_cast<uint32_t>(HidlDataspace::V0_BT601_525));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT709) ==
+              static_cast<uint32_t>(HidlDataspace::V0_BT709));
+static_assert(static_cast<uint32_t>(AidlDataspace::DCI_P3_LINEAR) ==
+              static_cast<uint32_t>(HidlDataspace::DCI_P3_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::DCI_P3) ==
+              static_cast<uint32_t>(HidlDataspace::DCI_P3));
+static_assert(static_cast<uint32_t>(AidlDataspace::DISPLAY_P3_LINEAR) ==
+              static_cast<uint32_t>(HidlDataspace::DISPLAY_P3_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::DISPLAY_P3) ==
+              static_cast<uint32_t>(HidlDataspace::DISPLAY_P3));
+static_assert(static_cast<uint32_t>(AidlDataspace::ADOBE_RGB) ==
+              static_cast<uint32_t>(HidlDataspace::ADOBE_RGB));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_LINEAR) ==
+              static_cast<uint32_t>(HidlDataspace::BT2020_LINEAR));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020) ==
+              static_cast<uint32_t>(HidlDataspace::BT2020));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_PQ) ==
+              static_cast<uint32_t>(HidlDataspace::BT2020_PQ));
+static_assert(static_cast<uint32_t>(AidlDataspace::DEPTH) ==
+              static_cast<uint32_t>(HidlDataspace::DEPTH));
+static_assert(static_cast<uint32_t>(AidlDataspace::SENSOR) ==
+              static_cast<uint32_t>(HidlDataspace::SENSOR));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_ITU) ==
+              static_cast<uint32_t>(HidlDataspace::BT2020_ITU));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_ITU_PQ) ==
+              static_cast<uint32_t>(HidlDataspace::BT2020_ITU_PQ));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_ITU_HLG) ==
+              static_cast<uint32_t>(HidlDataspace::BT2020_ITU_HLG));
+static_assert(static_cast<uint32_t>(AidlDataspace::BT2020_HLG) ==
+              static_cast<uint32_t>(HidlDataspace::BT2020_HLG));
+static_assert(static_cast<uint32_t>(AidlDataspace::DISPLAY_BT2020) ==
+              static_cast<uint32_t>(HidlDataspace::DISPLAY_BT2020));
+static_assert(static_cast<uint32_t>(AidlDataspace::DYNAMIC_DEPTH) ==
+              static_cast<uint32_t>(HidlDataspace::DYNAMIC_DEPTH));
+static_assert(static_cast<uint32_t>(AidlDataspace::JPEG_APP_SEGMENTS) ==
+              static_cast<uint32_t>(HidlDataspace::JPEG_APP_SEGMENTS));
+static_assert(static_cast<uint32_t>(AidlDataspace::HEIF) ==
+              static_cast<uint32_t>(HidlDataspace::HEIF));
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index b667a74..c136708 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -1,20 +1,15 @@
-#include <algorithm>
-#include <functional>
-#include <limits>
-#include <ostream>
-
 #include <gtest/gtest.h>
-
 #include <gui/ISurfaceComposer.h>
 #include <gui/LayerDebugInfo.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
-
 #include <private/android_filesystem_config.h>
 #include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
 #include <utils/String8.h>
 
+#include <functional>
+
 namespace android {
 
 using Transaction = SurfaceComposerClient::Transaction;
@@ -23,7 +18,6 @@
 namespace {
 const String8 DISPLAY_NAME("Credentials Display Test");
 const String8 SURFACE_NAME("Test Surface Name");
-const uint32_t ROTATION = 0;
 const float FRAME_SCALE = 1.0f;
 } // namespace
 
@@ -32,6 +26,10 @@
  * Methods like EnableVsyncInjections and InjectVsync are not tested since they do not
  * return anything meaningful.
  */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
 class CredentialsTest : public ::testing::Test {
 protected:
     void SetUp() override {
@@ -64,14 +62,13 @@
         mDisplay = SurfaceComposerClient::getInternalDisplayToken();
         ASSERT_FALSE(mDisplay == nullptr);
 
-        DisplayInfo info;
-        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
-        const ssize_t displayWidth = info.w;
-        const ssize_t displayHeight = info.h;
+        DisplayConfig config;
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplay, &config));
 
         // Background surface
         mBGSurfaceControl =
-                mComposerClient->createSurface(SURFACE_NAME, displayWidth, displayHeight,
+                mComposerClient->createSurface(SURFACE_NAME, config.resolution.getWidth(),
+                                               config.resolution.getHeight(),
                                                PIXEL_FORMAT_RGBA_8888, 0);
         ASSERT_TRUE(mBGSurfaceControl != nullptr);
         ASSERT_TRUE(mBGSurfaceControl->isValid());
@@ -185,10 +182,10 @@
     const auto display = SurfaceComposerClient::getInternalDisplayToken();
     ASSERT_TRUE(display != nullptr);
 
-    DisplayInfo info;
-    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
+    DisplayConfig config;
+    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
 
-    Vector<DisplayInfo> configs;
+    Vector<DisplayConfig> configs;
     ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
 
     ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveConfig(display));
@@ -215,10 +212,24 @@
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, NO_ERROR));
 }
 
-TEST_F(CredentialsTest, SetActiveConfigTest) {
+TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
     const auto display = SurfaceComposerClient::getInternalDisplayToken();
+    int32_t defaultConfig;
+    float primaryFpsMin;
+    float primaryFpsMax;
+    float appRequestFpsMin;
+    float appRequestFpsMax;
+    status_t res =
+            SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
+                                                                &primaryFpsMin, &primaryFpsMax,
+                                                                &appRequestFpsMin,
+                                                                &appRequestFpsMax);
+    ASSERT_EQ(res, NO_ERROR);
     std::function<status_t()> condition = [=]() {
-        return SurfaceComposerClient::setActiveConfig(display, 0);
+        return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig,
+                                                                   primaryFpsMin, primaryFpsMax,
+                                                                   appRequestFpsMin,
+                                                                   appRequestFpsMax);
     };
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
 }
@@ -245,24 +256,13 @@
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges(condition, true, false));
 }
 
-TEST_F(CredentialsTest, DISABLED_DestroyDisplayTest) {
-    setupVirtualDisplay();
-
-    DisplayInfo info;
-    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info));
-    SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
-    // This test currently fails. TODO(b/112002626): Find a way to properly create
-    // a display in the test environment, so that destroy display can remove it.
-    ASSERT_EQ(NAME_NOT_FOUND, SurfaceComposerClient::getDisplayInfo(mVirtualDisplay, &info));
-}
-
 TEST_F(CredentialsTest, CaptureTest) {
     const auto display = SurfaceComposerClient::getInternalDisplayToken();
     std::function<status_t()> condition = [=]() {
         sp<GraphicBuffer> outBuffer;
         return ScreenshotClient::capture(display, ui::Dataspace::V0_SRGB,
                                          ui::PixelFormat::RGBA_8888, Rect(), 0 /*reqWidth*/,
-                                         0 /*reqHeight*/, false, ROTATION, &outBuffer);
+                                         0 /*reqHeight*/, false, ui::ROTATION_0, &outBuffer);
     };
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
 }
@@ -274,7 +274,7 @@
         sp<GraphicBuffer> outBuffer;
         return ScreenshotClient::captureLayers(mBGSurfaceControl->getHandle(),
                                                ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888,
-                                               Rect(), FRAME_SCALE, &outBuffer);
+                                               Rect(0, 0, 1, 1), FRAME_SCALE, &outBuffer);
     };
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
 }
@@ -363,3 +363,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp b/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp
new file mode 100644
index 0000000..46b98f9
--- /dev/null
+++ b/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+        ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class DereferenceSurfaceControlTest : public LayerTransactionTest {
+protected:
+    void SetUp() override {
+        LayerTransactionTest::SetUp();
+        bgLayer = createLayer("BG layer", 20, 20);
+        fillBufferQueueLayerColor(bgLayer, Color::RED, 20, 20);
+        fgLayer = createLayer("FG layer", 20, 20);
+        fillBufferQueueLayerColor(fgLayer, Color::BLUE, 20, 20);
+        Transaction().setLayer(fgLayer, mLayerZBase + 1).apply();
+        {
+            SCOPED_TRACE("before anything");
+            auto shot = screenshot();
+            shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
+        }
+    }
+    void TearDown() override {
+        LayerTransactionTest::TearDown();
+        bgLayer = 0;
+        fgLayer = 0;
+    }
+
+    sp<SurfaceControl> bgLayer;
+    sp<SurfaceControl> fgLayer;
+};
+
+TEST_F(DereferenceSurfaceControlTest, LayerNotInTransaction) {
+    fgLayer = nullptr;
+    {
+        SCOPED_TRACE("after setting null");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 20, 20), Color::RED);
+    }
+}
+
+TEST_F(DereferenceSurfaceControlTest, LayerInTransaction) {
+    auto transaction = Transaction().show(fgLayer);
+    fgLayer = nullptr;
+    {
+        SCOPED_TRACE("after setting null");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
+    }
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
new file mode 100644
index 0000000..debfe83
--- /dev/null
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <thread>
+#include "LayerTransactionTest.h"
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+        ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+/**
+ * Test class for setting display configs and passing around refresh rate ranges.
+ */
+class RefreshRateRangeTest : public ::testing::Test {
+protected:
+    void SetUp() override { mDisplayToken = SurfaceComposerClient::getInternalDisplayToken(); }
+
+    sp<IBinder> mDisplayToken;
+};
+
+TEST_F(RefreshRateRangeTest, setAllConfigs) {
+    int32_t initialDefaultConfig;
+    float initialPrimaryMin;
+    float initialPrimaryMax;
+    float initialAppRequestMin;
+    float initialAppRequestMax;
+    status_t res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
+                                                                       &initialDefaultConfig,
+                                                                       &initialPrimaryMin,
+                                                                       &initialPrimaryMax,
+                                                                       &initialAppRequestMin,
+                                                                       &initialAppRequestMax);
+    ASSERT_EQ(res, NO_ERROR);
+
+    Vector<DisplayConfig> configs;
+    res = SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &configs);
+    ASSERT_EQ(res, NO_ERROR);
+
+    for (size_t i = 0; i < configs.size(); i++) {
+        res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i,
+                                                                  configs[i].refreshRate,
+                                                                  configs[i].refreshRate,
+                                                                  configs[i].refreshRate,
+                                                                  configs[i].refreshRate);
+        ASSERT_EQ(res, NO_ERROR);
+
+        int defaultConfig;
+        float primaryRefreshRateMin;
+        float primaryRefreshRateMax;
+        float appRequestRefreshRateMin;
+        float appRequestRefreshRateMax;
+        res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
+                                                                  &primaryRefreshRateMin,
+                                                                  &primaryRefreshRateMax,
+                                                                  &appRequestRefreshRateMin,
+                                                                  &appRequestRefreshRateMax);
+        ASSERT_EQ(res, NO_ERROR);
+        ASSERT_EQ(defaultConfig, i);
+        ASSERT_EQ(primaryRefreshRateMin, configs[i].refreshRate);
+        ASSERT_EQ(primaryRefreshRateMax, configs[i].refreshRate);
+        ASSERT_EQ(appRequestRefreshRateMin, configs[i].refreshRate);
+        ASSERT_EQ(appRequestRefreshRateMax, configs[i].refreshRate);
+    }
+
+    res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, initialDefaultConfig,
+                                                              initialPrimaryMin, initialPrimaryMax,
+                                                              initialAppRequestMin,
+                                                              initialAppRequestMax);
+    ASSERT_EQ(res, NO_ERROR);
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/EffectLayer_test.cpp b/services/surfaceflinger/tests/EffectLayer_test.cpp
new file mode 100644
index 0000000..3dca391
--- /dev/null
+++ b/services/surfaceflinger/tests/EffectLayer_test.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class EffectLayerTest : public LayerTransactionTest {
+protected:
+    virtual void SetUp() {
+        LayerTransactionTest::SetUp();
+        ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+        const auto display = SurfaceComposerClient::getInternalDisplayToken();
+        ASSERT_FALSE(display == nullptr);
+
+        mParentLayer = createColorLayer("Parent layer", Color::RED);
+        asTransaction([&](Transaction& t) {
+            t.setDisplayLayerStack(display, 0);
+            t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer);
+            t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+        });
+    }
+
+    virtual void TearDown() {
+        LayerTransactionTest::TearDown();
+        mParentLayer = 0;
+    }
+
+    sp<SurfaceControl> mParentLayer;
+};
+
+TEST_F(EffectLayerTest, DefaultEffectLayerHasSolidBlackFill) {
+    sp<SurfaceControl> effectLayer =
+            mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */,
+                                   PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect,
+                                   mParentLayer.get());
+
+    EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
+    asTransaction([&](Transaction& t) {
+        t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400));
+        t.show(effectLayer);
+    });
+
+    {
+        SCOPED_TRACE("Default effect Layer has solid black fill");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 400, 400), Color::BLACK);
+    }
+}
+
+TEST_F(EffectLayerTest, EffectLayerWithNoFill) {
+    sp<SurfaceControl> effectLayer =
+            mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */,
+                                   PIXEL_FORMAT_RGBA_8888,
+                                   ISurfaceComposerClient::eFXSurfaceEffect |
+                                           ISurfaceComposerClient::eNoColorFill,
+                                   mParentLayer.get());
+
+    EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
+    asTransaction([&](Transaction& t) {
+        t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400));
+        t.show(effectLayer);
+    });
+
+    {
+        SCOPED_TRACE("Effect layer with nofill option is transparent");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 400, 400), Color::RED);
+    }
+}
+
+TEST_F(EffectLayerTest, EffectLayerCanSetColor) {
+    sp<SurfaceControl> effectLayer =
+            mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */,
+                                   PIXEL_FORMAT_RGBA_8888,
+                                   ISurfaceComposerClient::eFXSurfaceEffect |
+                                           ISurfaceComposerClient::eNoColorFill,
+                                   mParentLayer.get());
+
+    EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
+    asTransaction([&](Transaction& t) {
+        t.setCrop_legacy(effectLayer, Rect(0, 0, 400, 400));
+        t.setColor(effectLayer,
+                   half3{Color::GREEN.r / 255.0f, Color::GREEN.g / 255.0f,
+                         Color::GREEN.b / 255.0f});
+        t.show(effectLayer);
+    });
+
+    {
+        SCOPED_TRACE("Effect Layer can set color");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 400, 400), Color::GREEN);
+    }
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
new file mode 100644
index 0000000..4023c66
--- /dev/null
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 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 <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <ui/DisplayConfig.h>
+#include <utils/String8.h>
+
+#include <limits>
+
+#include "BufferGenerator.h"
+#include "utils/CallbackUtils.h"
+#include "utils/ColorUtils.h"
+#include "utils/TransactionUtils.h"
+
+namespace android {
+
+namespace test {
+
+using Transaction = SurfaceComposerClient::Transaction;
+using CallbackInfo = SurfaceComposerClient::CallbackInfo;
+using TCLHash = SurfaceComposerClient::TCLHash;
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class TransactionHelper : public Transaction {
+public:
+    size_t getNumListeners() { return mListenerCallbacks.size(); }
+
+    std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
+    getListenerCallbacks() {
+        return mListenerCallbacks;
+    }
+};
+
+class IPCTestUtils {
+public:
+    static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
+                                bool finalState = false);
+    static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence);
+};
+
+class IIPCTest : public IInterface {
+public:
+    DECLARE_META_INTERFACE(IPCTest)
+    enum class Tag : uint32_t {
+        SetDeathToken = IBinder::FIRST_CALL_TRANSACTION,
+        InitClient,
+        CreateTransaction,
+        MergeAndApply,
+        VerifyCallbacks,
+        CleanUp,
+        Last,
+    };
+
+    virtual status_t setDeathToken(sp<IBinder>& token) = 0;
+
+    virtual status_t initClient() = 0;
+
+    virtual status_t createTransaction(TransactionHelper* outTransaction, uint32_t width,
+                                       uint32_t height) = 0;
+
+    virtual status_t mergeAndApply(TransactionHelper transaction) = 0;
+
+    virtual status_t verifyCallbacks() = 0;
+
+    virtual status_t cleanUp() = 0;
+};
+
+class BpIPCTest : public SafeBpInterface<IIPCTest> {
+public:
+    explicit BpIPCTest(const sp<IBinder>& impl) : SafeBpInterface<IIPCTest>(impl, "BpIPCTest") {}
+
+    status_t setDeathToken(sp<IBinder>& token) {
+        return callRemote<decltype(&IIPCTest::setDeathToken)>(Tag::SetDeathToken, token);
+    }
+
+    status_t initClient() { return callRemote<decltype(&IIPCTest::initClient)>(Tag::InitClient); }
+
+    status_t createTransaction(TransactionHelper* transaction, uint32_t width, uint32_t height) {
+        return callRemote<decltype(&IIPCTest::createTransaction)>(Tag::CreateTransaction,
+                                                                  transaction, width, height);
+    }
+
+    status_t mergeAndApply(TransactionHelper transaction) {
+        return callRemote<decltype(&IIPCTest::mergeAndApply)>(Tag::MergeAndApply, transaction);
+    }
+
+    status_t verifyCallbacks() {
+        return callRemote<decltype(&IIPCTest::verifyCallbacks)>(Tag::VerifyCallbacks);
+    }
+
+    status_t cleanUp() { return callRemote<decltype(&IIPCTest::cleanUp)>(Tag::CleanUp); }
+};
+
+IMPLEMENT_META_INTERFACE(IPCTest, "android.gfx.tests.IIPCTest")
+
+class onTestDeath : public IBinder::DeathRecipient {
+public:
+    void binderDied(const wp<IBinder>& /*who*/) override {
+        ALOGE("onTestDeath::binderDied, exiting");
+        exit(0);
+    }
+};
+
+sp<onTestDeath> getDeathToken() {
+    static sp<onTestDeath> token = new onTestDeath;
+    return token;
+}
+
+class BnIPCTest : public SafeBnInterface<IIPCTest> {
+public:
+    BnIPCTest() : SafeBnInterface("BnIPCTest") {}
+
+    status_t setDeathToken(sp<IBinder>& token) override {
+        return token->linkToDeath(getDeathToken());
+    }
+
+    status_t initClient() override {
+        mClient = new SurfaceComposerClient;
+        auto err = mClient->initCheck();
+        return err;
+    }
+
+    status_t createTransaction(TransactionHelper* transaction, uint32_t width, uint32_t height) {
+        if (transaction == nullptr) {
+            ALOGE("Error in createTransaction: transaction is nullptr");
+            return BAD_VALUE;
+        }
+        mSurfaceControl = mClient->createSurface(String8("parentProcessSurface"), 0, 0,
+                                                 PIXEL_FORMAT_RGBA_8888,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState,
+                                                 /*parent*/ nullptr);
+        sp<GraphicBuffer> gb;
+        sp<Fence> fence;
+        int err = IPCTestUtils::getBuffer(&gb, &fence);
+        if (err != NO_ERROR) return err;
+
+        TransactionUtils::fillGraphicBufferColor(gb,
+                                                 {0, 0, static_cast<int32_t>(width),
+                                                  static_cast<int32_t>(height)},
+                                                 Color::RED);
+        transaction->setLayerStack(mSurfaceControl, 0)
+                .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
+                .setFrame(mSurfaceControl, Rect(0, 0, width, height))
+                .setBuffer(mSurfaceControl, gb)
+                .setAcquireFence(mSurfaceControl, fence)
+                .show(mSurfaceControl)
+                .addTransactionCompletedCallback(mCallbackHelper.function,
+                                                 mCallbackHelper.getContext());
+        return NO_ERROR;
+    }
+
+    status_t mergeAndApply(TransactionHelper /*transaction*/) {
+        // transaction.apply();
+        return NO_ERROR;
+    }
+
+    status_t verifyCallbacks() {
+        ExpectedResult expected;
+        expected.addSurface(ExpectedResult::Transaction::PRESENTED, mSurfaceControl);
+        EXPECT_NO_FATAL_FAILURE(IPCTestUtils::waitForCallback(mCallbackHelper, expected, true));
+        return NO_ERROR;
+    }
+
+    status_t cleanUp() {
+        if (mClient) mClient->dispose();
+        mSurfaceControl = nullptr;
+        IPCThreadState::self()->stopProcess();
+        return NO_ERROR;
+    }
+
+    status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                        uint32_t /*flags*/) override {
+        EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION);
+        EXPECT_LT(code, static_cast<uint32_t>(IIPCTest::Tag::Last));
+        switch (static_cast<IIPCTest::Tag>(code)) {
+            case IIPCTest::Tag::SetDeathToken:
+                return callLocal(data, reply, &IIPCTest::setDeathToken);
+            case IIPCTest::Tag::InitClient:
+                return callLocal(data, reply, &IIPCTest::initClient);
+            case IIPCTest::Tag::CreateTransaction:
+                return callLocal(data, reply, &IIPCTest::createTransaction);
+            case IIPCTest::Tag::MergeAndApply:
+                return callLocal(data, reply, &IIPCTest::mergeAndApply);
+            case IIPCTest::Tag::VerifyCallbacks:
+                return callLocal(data, reply, &IIPCTest::verifyCallbacks);
+            case IIPCTest::Tag::CleanUp:
+                return callLocal(data, reply, &IIPCTest::cleanUp);
+            default:
+                return UNKNOWN_ERROR;
+        }
+    }
+
+private:
+    sp<SurfaceComposerClient> mClient;
+    sp<SurfaceControl> mSurfaceControl;
+    CallbackHelper mCallbackHelper;
+};
+
+class IPCTest : public ::testing::Test {
+public:
+    IPCTest() : mDeathRecipient(new BBinder), mRemote(initRemoteService()) {
+        ProcessState::self()->startThreadPool();
+    }
+    void SetUp() {
+        mClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+        mPrimaryDisplay = mClient->getInternalDisplayToken();
+        DisplayConfig config;
+        mClient->getActiveDisplayConfig(mPrimaryDisplay, &config);
+        mDisplayWidth = config.resolution.getWidth();
+        mDisplayHeight = config.resolution.getHeight();
+
+        Transaction setupTransaction;
+        setupTransaction.setDisplayLayerStack(mPrimaryDisplay, 0);
+        setupTransaction.apply();
+    }
+
+protected:
+    sp<IIPCTest> initRemoteService();
+
+    sp<IBinder> mDeathRecipient;
+    sp<IIPCTest> mRemote;
+    sp<SurfaceComposerClient> mClient;
+    sp<IBinder> mPrimaryDisplay;
+    uint32_t mDisplayWidth;
+    uint32_t mDisplayHeight;
+    sp<SurfaceControl> sc;
+};
+
+status_t IPCTestUtils::getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
+    static BufferGenerator bufferGenerator;
+    return bufferGenerator.get(outBuffer, outFence);
+}
+
+void IPCTestUtils::waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
+                                   bool finalState) {
+    CallbackData callbackData;
+    ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData));
+    EXPECT_NO_FATAL_FAILURE(expectedResult.verifyCallbackData(callbackData));
+
+    if (finalState) {
+        ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+    }
+}
+
+sp<IIPCTest> IPCTest::initRemoteService() {
+    static std::mutex mMutex;
+    static sp<IIPCTest> remote;
+    const String16 serviceName("IPCTest");
+
+    std::unique_lock<decltype(mMutex)> lock;
+    if (remote == nullptr) {
+        pid_t forkPid = fork();
+        EXPECT_NE(forkPid, -1);
+
+        if (forkPid == 0) {
+            sp<IIPCTest> nativeService = new BnIPCTest;
+            if (!nativeService) {
+                ALOGE("null service...");
+            }
+            status_t err = defaultServiceManager()->addService(serviceName,
+                                                               IInterface::asBinder(nativeService));
+            if (err != NO_ERROR) {
+                ALOGE("failed to add service: %d", err);
+            }
+            ProcessState::self()->startThreadPool();
+            IPCThreadState::self()->joinThreadPool();
+            [&]() { exit(0); }();
+        }
+        sp<IBinder> binder = defaultServiceManager()->getService(serviceName);
+        remote = interface_cast<IIPCTest>(binder);
+        remote->setDeathToken(mDeathRecipient);
+    }
+    return remote;
+}
+
+TEST_F(IPCTest, MergeBasic) {
+    CallbackHelper helper1;
+    sc = mClient->createSurface(String8("parentProcessSurface"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+                                ISurfaceComposerClient::eFXSurfaceBufferState,
+                                /*parent*/ nullptr);
+    sp<GraphicBuffer> gb;
+    sp<Fence> fence;
+    int err = IPCTestUtils::getBuffer(&gb, &fence);
+    ASSERT_EQ(NO_ERROR, err);
+    TransactionUtils::fillGraphicBufferColor(gb,
+                                             {0, 0, static_cast<int32_t>(mDisplayWidth),
+                                              static_cast<int32_t>(mDisplayHeight)},
+                                             Color::RED);
+
+    Transaction transaction;
+    transaction.setLayerStack(sc, 0)
+            .setLayer(sc, std::numeric_limits<int32_t>::max() - 1)
+            .setBuffer(sc, gb)
+            .setAcquireFence(sc, fence)
+            .show(sc)
+            .addTransactionCompletedCallback(helper1.function, helper1.getContext());
+
+    TransactionHelper remote;
+    mRemote->initClient();
+    mRemote->createTransaction(&remote, mDisplayWidth / 2, mDisplayHeight / 2);
+    ASSERT_EQ(1, remote.getNumListeners());
+    auto remoteListenerCallbacks = remote.getListenerCallbacks();
+    auto remoteCallback = remoteListenerCallbacks.begin();
+    auto remoteCallbackInfo = remoteCallback->second;
+    auto remoteListenerScs = remoteCallbackInfo.surfaceControls;
+    ASSERT_EQ(1, remoteCallbackInfo.callbackIds.size());
+    ASSERT_EQ(1, remoteListenerScs.size());
+
+    sp<SurfaceControl> remoteSc = *(remoteListenerScs.begin());
+    transaction.merge(std::move(remote));
+    transaction.apply();
+
+    sleep(1);
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, sc);
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, remoteSc);
+    EXPECT_NO_FATAL_FAILURE(IPCTestUtils::waitForCallback(helper1, expected, true));
+
+    mRemote->verifyCallbacks();
+    mRemote->cleanUp();
+}
+
+} // namespace test
+} // namespace android
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
new file mode 100644
index 0000000..6d28e62
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -0,0 +1,879 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+#include "utils/CallbackUtils.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+        ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class LayerCallbackTest : public LayerTransactionTest {
+public:
+    virtual sp<SurfaceControl> createBufferStateLayer() {
+        return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState);
+    }
+
+    static int fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
+                               const sp<SurfaceControl>& layer = nullptr, bool setBuffer = true,
+                               bool setBackgroundColor = false) {
+        if (layer) {
+            sp<GraphicBuffer> buffer;
+            sp<Fence> fence;
+            if (setBuffer) {
+                int err = getBuffer(&buffer, &fence);
+                if (err != NO_ERROR) {
+                    return err;
+                }
+
+                transaction.setBuffer(layer, buffer);
+                transaction.setAcquireFence(layer, fence);
+            }
+
+            if (setBackgroundColor) {
+                transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f,
+                                               ui::Dataspace::UNKNOWN);
+            }
+        }
+
+        transaction.addTransactionCompletedCallback(callbackHelper->function,
+                                                    callbackHelper->getContext());
+        return NO_ERROR;
+    }
+
+    static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
+                                bool finalState = false) {
+        CallbackData callbackData;
+        ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData));
+        EXPECT_NO_FATAL_FAILURE(expectedResult.verifyCallbackData(callbackData));
+
+        if (finalState) {
+            ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+        }
+    }
+
+    static void waitForCallbacks(CallbackHelper& helper,
+                                 const std::vector<ExpectedResult>& expectedResults,
+                                 bool finalState = false) {
+        for (const auto& expectedResult : expectedResults) {
+            waitForCallback(helper, expectedResult);
+        }
+        if (finalState) {
+            ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+        }
+    }
+};
+
+TEST_F(LayerCallbackTest, BufferColor) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer, true, true);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction.apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoBufferNoColor) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer, false, false);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
+                        ExpectedResult::Buffer::NOT_ACQUIRED);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, BufferNoColor) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer, true, false);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoBufferColor) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer, false, true);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+                        ExpectedResult::Buffer::NOT_ACQUIRED);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoStateChange) {
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction.apply();
+
+    ExpectedResult expected;
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, OffScreen) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction.setFrame(layer, Rect(-100, -100, 100, 100)).apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MergeBufferNoColor) {
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    int err = fillTransaction(transaction1, &callback1, layer1);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    err = fillTransaction(transaction2, &callback2, layer2);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MergeNoBufferColor) {
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    int err = fillTransaction(transaction1, &callback1, layer1, false, true);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    err = fillTransaction(transaction2, &callback2, layer2, false, true);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+                         ExpectedResult::Buffer::NOT_ACQUIRED);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MergeOneBufferOneColor) {
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    int err = fillTransaction(transaction1, &callback1, layer1);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    err = fillTransaction(transaction2, &callback2, layer2, false, true);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer1);
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer2,
+                        ExpectedResult::Buffer::NOT_ACQUIRED);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+TEST_F(LayerCallbackTest, Merge_SameCallback) {
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction1, &callback, layer1);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    err = fillTransaction(transaction2, &callback, layer2);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction2.merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SameLayer) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    int err = fillTransaction(transaction1, &callback1, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    err = fillTransaction(transaction2, &callback2, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction2.merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_DifferentClients) {
+    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+            client2(new SurfaceComposerClient);
+
+    ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+    ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    int err = fillTransaction(transaction1, &callback1, layer1);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    err = fillTransaction(transaction2, &callback2, layer2);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    for (size_t i = 0; i < 10; i++) {
+        int err = fillTransaction(transaction, &callback, layer);
+        if (err) {
+            GTEST_SUCCEED() << "test not supported";
+            return;
+        }
+
+        transaction.apply();
+
+        ExpectedResult expected;
+        expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+                            ExpectedResult::Buffer::ACQUIRED,
+                            (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+                                     : ExpectedResult::PreviousBuffer::RELEASED);
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+    }
+    ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_NoStateChange) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    for (size_t i = 0; i < 10; i++) {
+        ExpectedResult expected;
+
+        if (i == 0) {
+            int err = fillTransaction(transaction, &callback, layer);
+            if (err) {
+                GTEST_SUCCEED() << "test not supported";
+                return;
+            }
+            expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+        } else {
+            int err = fillTransaction(transaction, &callback);
+            if (err) {
+                GTEST_SUCCEED() << "test not supported";
+                return;
+            }
+        }
+
+        transaction.apply();
+
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+    }
+    ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    for (size_t i = 0; i < 10; i++) {
+        if (i == 0) {
+            int err = fillTransaction(transaction, &callback, layer);
+            if (err) {
+                GTEST_SUCCEED() << "test not supported";
+                return;
+            }
+        } else {
+            int err = fillTransaction(transaction, &callback);
+            if (err) {
+                GTEST_SUCCEED() << "test not supported";
+                return;
+            }
+        }
+
+        transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+        ExpectedResult expected;
+        expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED
+                                     : ExpectedResult::Transaction::NOT_PRESENTED,
+                            layer,
+                            (i == 0) ? ExpectedResult::Buffer::ACQUIRED
+                                     : ExpectedResult::Buffer::NOT_ACQUIRED);
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, i == 0));
+    }
+    ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge) {
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    for (size_t i = 0; i < 10; i++) {
+        int err = fillTransaction(transaction1, &callback1, layer1);
+        if (err) {
+            GTEST_SUCCEED() << "test not supported";
+            return;
+        }
+        err = fillTransaction(transaction2, &callback2, layer2);
+        if (err) {
+            GTEST_SUCCEED() << "test not supported";
+            return;
+        }
+
+        transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+        transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+        ExpectedResult expected;
+        expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+                             ExpectedResult::Buffer::ACQUIRED,
+                             (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+                                      : ExpectedResult::PreviousBuffer::RELEASED);
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
+    }
+    ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
+    ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) {
+    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+            client2(new SurfaceComposerClient);
+    ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+    ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+    for (size_t i = 0; i < 10; i++) {
+        int err = fillTransaction(transaction1, &callback1, layer1);
+        if (err) {
+            GTEST_SUCCEED() << "test not supported";
+            return;
+        }
+        err = fillTransaction(transaction2, &callback2, layer2);
+        if (err) {
+            GTEST_SUCCEED() << "test not supported";
+            return;
+        }
+
+        transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+        transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+        ExpectedResult expected;
+        expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+                             ExpectedResult::Buffer::ACQUIRED,
+                             (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+                                      : ExpectedResult::PreviousBuffer::RELEASED);
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
+    }
+    ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
+    ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateChange) {
+    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+            client2(new SurfaceComposerClient);
+    ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+    ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+
+    // Normal call to set up test
+    int err = fillTransaction(transaction1, &callback1, layer1);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    err = fillTransaction(transaction2, &callback2, layer2);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+    expected.reset();
+
+    // Test
+    err = fillTransaction(transaction1, &callback1);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    err = fillTransaction(transaction2, &callback2);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction2.merge(std::move(transaction1)).apply();
+
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateChange) {
+    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+            client2(new SurfaceComposerClient);
+
+    ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+    ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+    sp<SurfaceControl> layer1, layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
+                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    Transaction transaction1, transaction2;
+    CallbackHelper callback1, callback2;
+
+    // Normal call to set up test
+    int err = fillTransaction(transaction1, &callback1, layer1);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    err = fillTransaction(transaction2, &callback2, layer2);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+    ExpectedResult expected;
+    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+    expected.reset();
+
+    // Test
+    err = fillTransaction(transaction1, &callback1);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+    err = fillTransaction(transaction2, &callback2);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+    expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2,
+                        ExpectedResult::Buffer::NOT_ACQUIRED);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    std::vector<ExpectedResult> expectedResults(50);
+    for (auto& expected : expectedResults) {
+        expected.reset();
+        expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+                            ExpectedResult::Buffer::ACQUIRED,
+                            ExpectedResult::PreviousBuffer::UNKNOWN);
+
+        int err = fillTransaction(transaction, &callback, layer);
+        if (err) {
+            GTEST_SUCCEED() << "test not supported";
+            return;
+        }
+
+        transaction.apply();
+    }
+    EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_NoStateChange) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    // Normal call to set up test
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction.apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+
+    // Test
+    std::vector<ExpectedResult> expectedResults(50);
+    for (auto& expected : expectedResults) {
+        expected.reset();
+
+        err = fillTransaction(transaction, &callback);
+        if (err) {
+            GTEST_SUCCEED() << "test not supported";
+            return;
+        }
+
+        transaction.apply();
+    }
+    EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    // Normal call to set up test
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+    ExpectedResult expectedResult;
+    expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expectedResult, true));
+
+    // Test
+    std::vector<ExpectedResult> expectedResults(50);
+    for (auto& expected : expectedResults) {
+        expected.reset();
+        expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
+                            ExpectedResult::Buffer::NOT_ACQUIRED);
+
+        err = fillTransaction(transaction, &callback);
+        if (err) {
+            GTEST_SUCCEED() << "test not supported";
+            return;
+        }
+
+        transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+    }
+    EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    // Try to present 100ms in the future
+    nsecs_t time = systemTime() + (100 * 1e6);
+
+    transaction.setDesiredPresentTime(time);
+    transaction.apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    expected.addExpectedPresentTime(time);
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback1;
+    int err = fillTransaction(transaction, &callback1, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    // Try to present 100ms in the future
+    nsecs_t time = systemTime() + (100 * 1e6);
+
+    transaction.setDesiredPresentTime(time);
+    transaction.apply();
+
+    ExpectedResult expected1;
+    expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    expected1.addExpectedPresentTime(time);
+
+    CallbackHelper callback2;
+    err = fillTransaction(transaction, &callback2, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    // Try to present 33ms after the first frame
+    time += (33.3 * 1e6);
+
+    transaction.setDesiredPresentTime(time);
+    transaction.apply();
+
+    ExpectedResult expected2;
+    expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+                         ExpectedResult::Buffer::ACQUIRED,
+                         ExpectedResult::PreviousBuffer::RELEASED);
+    expected2.addExpectedPresentTime(time);
+
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback1;
+    int err = fillTransaction(transaction, &callback1, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    // Try to present 100ms in the future
+    nsecs_t time = systemTime() + (100 * 1e6);
+
+    transaction.setDesiredPresentTime(time);
+    transaction.apply();
+
+    ExpectedResult expected1;
+    expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    expected1.addExpectedPresentTime(time);
+
+    CallbackHelper callback2;
+    err = fillTransaction(transaction, &callback2, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    // Try to present 33ms before the previous frame
+    time -= (33.3 * 1e6);
+
+    transaction.setDesiredPresentTime(time);
+    transaction.apply();
+
+    ExpectedResult expected2;
+    expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+                         ExpectedResult::Buffer::ACQUIRED,
+                         ExpectedResult::PreviousBuffer::RELEASED);
+
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_Past) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+    Transaction transaction;
+    CallbackHelper callback;
+    int err = fillTransaction(transaction, &callback, layer);
+    if (err) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    // Try to present 100ms in the past
+    nsecs_t time = systemTime() - (100 * 1e6);
+
+    transaction.setDesiredPresentTime(time);
+    transaction.apply();
+
+    ExpectedResult expected;
+    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+    expected.addExpectedPresentTime(systemTime());
+    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
new file mode 100644
index 0000000..83e5060
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -0,0 +1,1864 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <gui/BufferItemConsumer.h>
+#include <ui/Transform.h>
+#include <thread>
+#include "TransactionTestHarnesses.h"
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+        ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class LayerRenderTypeTransactionTest : public LayerTransactionTest,
+                                       public ::testing::WithParamInterface<RenderPath> {
+public:
+    LayerRenderTypeTransactionTest() : mHarness(LayerRenderPathTestHarness(this, GetParam())) {}
+
+    std::unique_ptr<ScreenCapture> getScreenCapture() { return mHarness.getScreenCapture(); }
+    void setRelativeZBasicHelper(uint32_t layerType);
+    void setRelativeZGroupHelper(uint32_t layerType);
+    void setAlphaBasicHelper(uint32_t layerType);
+    void setBackgroundColorHelper(uint32_t layerType, bool priorColor, bool bufferFill, float alpha,
+                                  Color finalColor);
+
+protected:
+    LayerRenderPathTestHarness mHarness;
+};
+
+INSTANTIATE_TEST_CASE_P(LayerRenderTypeTransactionTests, LayerRenderTypeTransactionTest,
+                        ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT));
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionBasic_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    {
+        SCOPED_TRACE("default position");
+        const Rect rect(0, 0, 32, 32);
+        auto shot = getScreenCapture();
+        shot->expectColor(rect, Color::RED);
+        shot->expectBorder(rect, Color::BLACK);
+    }
+
+    Transaction().setPosition(layer, 5, 10).apply();
+    {
+        SCOPED_TRACE("new position");
+        const Rect rect(5, 10, 37, 42);
+        auto shot = getScreenCapture();
+        shot->expectColor(rect, Color::RED);
+        shot->expectBorder(rect, Color::BLACK);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionRounding_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    // GPU composition requires only 4 bits of subpixel precision during rasterization
+    // XXX GPU composition does not match HWC composition due to precision
+    // loss (b/69315223)
+    const float epsilon = 1.0f / 16.0f;
+    Transaction().setPosition(layer, 0.5f - epsilon, 0.5f - epsilon).apply();
+    {
+        SCOPED_TRACE("rounding down");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    Transaction().setPosition(layer, 0.5f + epsilon, 0.5f + epsilon).apply();
+    {
+        SCOPED_TRACE("rounding up");
+        getScreenCapture()->expectColor(Rect(1, 1, 33, 33), Color::RED);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionOutOfBounds_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    Transaction().setPosition(layer, -32, -32).apply();
+    {
+        SCOPED_TRACE("negative coordinates");
+        getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
+    }
+
+    Transaction().setPosition(layer, mDisplayWidth, mDisplayHeight).apply();
+    {
+        SCOPED_TRACE("positive coordinates");
+        getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionPartiallyOutOfBounds_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    // partially out of bounds
+    Transaction().setPosition(layer, -30, -30).apply();
+    {
+        SCOPED_TRACE("negative coordinates");
+        getScreenCapture()->expectColor(Rect(0, 0, 2, 2), Color::RED);
+    }
+
+    Transaction().setPosition(layer, mDisplayWidth - 2, mDisplayHeight - 2).apply();
+    {
+        SCOPED_TRACE("positive coordinates");
+        getScreenCapture()->expectColor(Rect(mDisplayWidth - 2, mDisplayHeight - 2, mDisplayWidth,
+                                             mDisplayHeight),
+                                        Color::RED);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionWithResize_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    // setPosition is applied immediately by default, with or without resize
+    // pending
+    Transaction().setPosition(layer, 5, 10).setSize(layer, 64, 64).apply();
+    {
+        SCOPED_TRACE("resize pending");
+        auto shot = getScreenCapture();
+        const Rect rect(5, 10, 37, 42);
+        shot->expectColor(rect, Color::RED);
+        shot->expectBorder(rect, Color::BLACK);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
+    {
+        SCOPED_TRACE("resize applied");
+        getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    Transaction().setSize(layer, 64, 64).apply();
+    {
+        SCOPED_TRACE("resize pending");
+        auto shot = getScreenCapture();
+        const Rect rect(0, 0, 32, 32);
+        shot->expectColor(rect, Color::RED);
+        shot->expectBorder(rect, Color::BLACK);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
+    {
+        SCOPED_TRACE("resize applied");
+        auto shot = getScreenCapture();
+        const Rect rect(0, 0, 64, 64);
+        shot->expectColor(rect, Color::RED);
+        shot->expectBorder(rect, Color::BLACK);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetSizeWithScaleToWindow_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    // setSize is immediate with SCALE_TO_WINDOW, unlike setPosition
+    Transaction()
+            .setSize(layer, 64, 64)
+            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+            .apply();
+    getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, CreateLayer_BufferState) {
+    uint32_t transformHint = ui::Transform::ROT_INVALID;
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32,
+                                                ISurfaceComposerClient::eFXSurfaceBufferState,
+                                                /*parent*/ nullptr, &transformHint));
+    ASSERT_NE(ui::Transform::ROT_INVALID, transformHint);
+}
+
+void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) {
+    sp<SurfaceControl> layerR;
+    sp<SurfaceControl> layerG;
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32));
+
+    switch (layerType) {
+        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+            Transaction()
+                    .setPosition(layerG, 16, 16)
+                    .setRelativeLayer(layerG, layerR->getHandle(), 1)
+                    .apply();
+            break;
+        case ISurfaceComposerClient::eFXSurfaceBufferState:
+            Transaction()
+                    .setFrame(layerR, Rect(0, 0, 32, 32))
+                    .setFrame(layerG, Rect(16, 16, 48, 48))
+                    .setRelativeLayer(layerG, layerR->getHandle(), 1)
+                    .apply();
+            break;
+        default:
+            ASSERT_FALSE(true) << "Unsupported layer type";
+    }
+    {
+        SCOPED_TRACE("layerG above");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
+        shot->expectColor(Rect(16, 16, 48, 48), Color::GREEN);
+    }
+
+    Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).apply();
+    {
+        SCOPED_TRACE("layerG below");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+        shot->expectColor(Rect(32, 32, 48, 48), Color::GREEN);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferQueue) {
+    ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferState) {
+    ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
+void LayerRenderTypeTransactionTest::setRelativeZGroupHelper(uint32_t layerType) {
+    sp<SurfaceControl> layerR;
+    sp<SurfaceControl> layerG;
+    sp<SurfaceControl> layerB;
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerB, Color::BLUE, 32, 32));
+
+    // layerR = 0, layerG = layerR + 3, layerB = 2
+    switch (layerType) {
+        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+            Transaction()
+                    .setPosition(layerG, 8, 8)
+                    .setRelativeLayer(layerG, layerR->getHandle(), 3)
+                    .setPosition(layerB, 16, 16)
+                    .setLayer(layerB, mLayerZBase + 2)
+                    .apply();
+            break;
+        case ISurfaceComposerClient::eFXSurfaceBufferState:
+            Transaction()
+                    .setFrame(layerR, Rect(0, 0, 32, 32))
+                    .setFrame(layerG, Rect(8, 8, 40, 40))
+                    .setRelativeLayer(layerG, layerR->getHandle(), 3)
+                    .setFrame(layerB, Rect(16, 16, 48, 48))
+                    .setLayer(layerB, mLayerZBase + 2)
+                    .apply();
+            break;
+        default:
+            ASSERT_FALSE(true) << "Unsupported layer type";
+    }
+
+    {
+        SCOPED_TRACE("(layerR < layerG) < layerB");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
+        shot->expectColor(Rect(8, 8, 16, 16), Color::GREEN);
+        shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
+    }
+
+    // layerR = 4, layerG = layerR + 3, layerB = 2
+    Transaction().setLayer(layerR, mLayerZBase + 4).apply();
+    {
+        SCOPED_TRACE("layerB < (layerR < layerG)");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
+        shot->expectColor(Rect(8, 8, 40, 40), Color::GREEN);
+        shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
+    }
+
+    // layerR = 4, layerG = layerR - 3, layerB = 2
+    Transaction().setRelativeLayer(layerG, layerR->getHandle(), -3).apply();
+    {
+        SCOPED_TRACE("layerB < (layerG < layerR)");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+        shot->expectColor(Rect(32, 32, 40, 40), Color::GREEN);
+        shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
+    }
+
+    // restore to absolute z
+    // layerR = 4, layerG = 0, layerB = 2
+    Transaction().setLayer(layerG, mLayerZBase).apply();
+    {
+        SCOPED_TRACE("layerG < layerB < layerR");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+        shot->expectColor(Rect(32, 32, 48, 48), Color::BLUE);
+    }
+
+    // layerR should not affect layerG anymore
+    // layerR = 1, layerG = 0, layerB = 2
+    Transaction().setLayer(layerR, mLayerZBase + 1).apply();
+    {
+        SCOPED_TRACE("layerG < layerR < layerB");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
+        shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferQueue) {
+    ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferState) {
+    ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferQueue) {
+    const Rect top(0, 0, 32, 16);
+    const Rect bottom(0, 16, 32, 32);
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+
+    ANativeWindow_Buffer buffer;
+    ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+    ASSERT_NO_FATAL_FAILURE(
+            TransactionUtils::fillANativeWindowBufferColor(buffer, top, Color::TRANSPARENT));
+    ASSERT_NO_FATAL_FAILURE(
+            TransactionUtils::fillANativeWindowBufferColor(buffer, bottom, Color::RED));
+    // setTransparentRegionHint always applies to the following buffer
+    Transaction().setTransparentRegionHint(layer, Region(top)).apply();
+    ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
+    {
+        SCOPED_TRACE("top transparent");
+        auto shot = getScreenCapture();
+        shot->expectColor(top, Color::BLACK);
+        shot->expectColor(bottom, Color::RED);
+    }
+
+    Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
+    {
+        SCOPED_TRACE("transparent region hint pending");
+        auto shot = getScreenCapture();
+        shot->expectColor(top, Color::BLACK);
+        shot->expectColor(bottom, Color::RED);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+    ASSERT_NO_FATAL_FAILURE(
+            TransactionUtils::fillANativeWindowBufferColor(buffer, top, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(
+            TransactionUtils::fillANativeWindowBufferColor(buffer, bottom, Color::TRANSPARENT));
+    ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
+    {
+        SCOPED_TRACE("bottom transparent");
+        auto shot = getScreenCapture();
+        shot->expectColor(top, Color::RED);
+        shot->expectColor(bottom, Color::BLACK);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState) {
+    const Rect top(0, 0, 32, 16);
+    const Rect bottom(0, 16, 32, 32);
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+
+    ASSERT_NO_FATAL_FAILURE(
+            TransactionUtils::fillGraphicBufferColor(buffer, top, Color::TRANSPARENT));
+    ASSERT_NO_FATAL_FAILURE(TransactionUtils::fillGraphicBufferColor(buffer, bottom, Color::RED));
+    Transaction()
+            .setTransparentRegionHint(layer, Region(top))
+            .setBuffer(layer, buffer)
+            .setFrame(layer, Rect(0, 0, 32, 32))
+            .apply();
+    {
+        SCOPED_TRACE("top transparent");
+        auto shot = getScreenCapture();
+        shot->expectColor(top, Color::BLACK);
+        shot->expectColor(bottom, Color::RED);
+    }
+
+    Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
+    {
+        SCOPED_TRACE("transparent region hint intermediate");
+        auto shot = getScreenCapture();
+        shot->expectColor(top, Color::BLACK);
+        shot->expectColor(bottom, Color::BLACK);
+    }
+
+    buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                               BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                       BufferUsage::COMPOSER_OVERLAY,
+                               "test");
+
+    ASSERT_NO_FATAL_FAILURE(TransactionUtils::fillGraphicBufferColor(buffer, top, Color::RED));
+    ASSERT_NO_FATAL_FAILURE(
+            TransactionUtils::fillGraphicBufferColor(buffer, bottom, Color::TRANSPARENT));
+    Transaction().setBuffer(layer, buffer).apply();
+    {
+        SCOPED_TRACE("bottom transparent");
+        auto shot = getScreenCapture();
+        shot->expectColor(top, Color::RED);
+        shot->expectColor(bottom, Color::BLACK);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferQueue) {
+    sp<SurfaceControl> layerTransparent;
+    sp<SurfaceControl> layerR;
+    ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+
+    // check that transparent region hint is bound by the layer size
+    Transaction()
+            .setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
+            .setPosition(layerR, 16, 16)
+            .setLayer(layerR, mLayerZBase + 1)
+            .apply();
+    ASSERT_NO_FATAL_FAILURE(
+            fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layerR, Color::RED, 32, 32));
+    getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferState) {
+    sp<SurfaceControl> layerTransparent;
+    sp<SurfaceControl> layerR;
+    ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(
+            layerR = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    // check that transparent region hint is bound by the layer size
+    Transaction()
+            .setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
+            .setFrame(layerR, Rect(16, 16, 48, 48))
+            .setLayer(layerR, mLayerZBase + 1)
+            .apply();
+    ASSERT_NO_FATAL_FAILURE(
+            fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layerR, Color::RED, 32, 32));
+    getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
+}
+
+void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) {
+    sp<SurfaceControl> layer1;
+    sp<SurfaceControl> layer2;
+    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer("test 2", 32, 32, layerType));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer1, {64, 0, 0, 255}, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer2, {0, 64, 0, 255}, 32, 32));
+
+    switch (layerType) {
+        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+            Transaction()
+                    .setAlpha(layer1, 0.25f)
+                    .setAlpha(layer2, 0.75f)
+                    .setPosition(layer2, 16, 0)
+                    .setLayer(layer2, mLayerZBase + 1)
+                    .apply();
+            break;
+        case ISurfaceComposerClient::eFXSurfaceBufferState:
+            Transaction()
+                    .setAlpha(layer1, 0.25f)
+                    .setAlpha(layer2, 0.75f)
+                    .setFrame(layer1, Rect(0, 0, 32, 32))
+                    .setFrame(layer2, Rect(16, 0, 48, 32))
+                    .setLayer(layer2, mLayerZBase + 1)
+                    .apply();
+            break;
+        default:
+            ASSERT_FALSE(true) << "Unsupported layer type";
+    }
+    {
+        auto shot = getScreenCapture();
+        uint8_t r = 16; // 64 * 0.25f
+        uint8_t g = 48; // 64 * 0.75f
+        shot->expectColor(Rect(0, 0, 16, 32), {r, 0, 0, 255});
+        shot->expectColor(Rect(32, 0, 48, 32), {0, g, 0, 255});
+
+        r /= 4; // r * (1.0f - 0.75f)
+        shot->expectColor(Rect(16, 0, 32, 32), {r, g, 0, 255});
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferQueue) {
+    ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferState) {
+    ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorBasic) {
+    sp<SurfaceControl> bufferLayer;
+    sp<SurfaceControl> colorLayer;
+    ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(colorLayer =
+                                    createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+                                                ISurfaceComposerClient::eFXSurfaceEffect));
+
+    Transaction()
+            .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+            .setLayer(colorLayer, mLayerZBase + 1)
+            .apply();
+
+    {
+        SCOPED_TRACE("default color");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
+    const Color expected = {15, 51, 85, 255};
+    // this is handwavy, but the precison loss scaled by 255 (8-bit per
+    // channel) should be less than one
+    const uint8_t tolerance = 1;
+    Transaction().setColor(colorLayer, color).apply();
+    {
+        SCOPED_TRACE("new color");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
+    }
+}
+
+// RED: Color layer base color and BufferQueueLayer/BufferStateLayer fill
+// BLUE: prior background color
+// GREEN: final background color
+// BLACK: no color or fill
+void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType, bool priorColor,
+                                                              bool bufferFill, float alpha,
+                                                              Color finalColor) {
+    sp<SurfaceControl> layer;
+    int32_t width = 500;
+    int32_t height = 500;
+
+    Color fillColor = Color::RED;
+    Color priorBgColor = Color::BLUE;
+    Color expectedColor = Color::BLACK;
+    switch (layerType) {
+        case ISurfaceComposerClient::eFXSurfaceEffect:
+            ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType));
+            Transaction()
+                    .setCrop_legacy(layer, Rect(0, 0, width, height))
+                    .setColor(layer, half3(1.0f, 0, 0))
+                    .apply();
+            expectedColor = fillColor;
+            break;
+        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+            ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
+            if (bufferFill) {
+                ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, fillColor, width, height));
+                expectedColor = fillColor;
+            }
+            Transaction().setCrop_legacy(layer, Rect(0, 0, width, height)).apply();
+            break;
+        case ISurfaceComposerClient::eFXSurfaceBufferState:
+            ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height, layerType));
+            if (bufferFill) {
+                ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height));
+                expectedColor = fillColor;
+            }
+            Transaction().setFrame(layer, Rect(0, 0, width, height)).apply();
+            break;
+        default:
+            GTEST_FAIL() << "Unknown layer type in setBackgroundColorHelper";
+            return;
+    }
+
+    if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceEffect) {
+        Transaction()
+                .setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN)
+                .apply();
+        if (!bufferFill) {
+            expectedColor = priorBgColor;
+        }
+    }
+
+    {
+        SCOPED_TRACE("default before setting background color layer");
+        screenshot()->expectColor(Rect(0, 0, width, height), expectedColor);
+    }
+    Transaction()
+            .setBackgroundColor(layer, half3(0, 1.0f, 0), alpha, ui::Dataspace::UNKNOWN)
+            .apply();
+
+    {
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, width, height), finalColor);
+        shot->expectBorder(Rect(0, 0, width, height), Color::BLACK);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) {
+    bool priorColor = false;
+    bool bufferFill = false;
+    float alpha = 1.0f;
+    Color finalColor = Color::RED;
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceEffect,
+                                                     priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+       SetBackgroundColor_BufferQueue_BufferFill_NoPriorColor_Basic) {
+    bool priorColor = false;
+    bool bufferFill = true;
+    float alpha = 1.0f;
+    Color finalColor = Color::RED;
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+                                                     priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+       SetBackgroundColor_BufferQueue_NoBufferFill_NoPriorColor_Basic) {
+    bool priorColor = false;
+    bool bufferFill = false;
+    float alpha = 1.0f;
+    Color finalColor = Color::GREEN;
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+                                                     priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferQueue_BufferFill_PriorColor_Basic) {
+    bool priorColor = true;
+    bool bufferFill = true;
+    float alpha = 1.0f;
+    Color finalColor = Color::RED;
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+                                                     priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+       SetBackgroundColor_BufferQueue_NoBufferFill_PriorColor_Basic) {
+    bool priorColor = true;
+    bool bufferFill = false;
+    float alpha = 1.0f;
+    Color finalColor = Color::GREEN;
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+                                                     priorColor, bufferFill, alpha, finalColor));
+}
+TEST_P(LayerRenderTypeTransactionTest,
+       SetBackgroundColor_BufferQueue_NoPriorColor_ZeroAlpha_NoEffect) {
+    bool priorColor = false;
+    bool bufferFill = false;
+    float alpha = 0;
+    Color finalColor = Color::BLACK;
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+                                                     priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+       SetBackgroundColor_BufferQueue_PriorColor_ZeroAlpha_DeleteBackground) {
+    bool priorColor = true;
+    bool bufferFill = false;
+    float alpha = 0;
+    Color finalColor = Color::BLACK;
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+                                                     priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+       SetBackgroundColor_BufferState_BufferFill_NoPriorColor_Basic) {
+    bool priorColor = false;
+    bool bufferFill = true;
+    float alpha = 1.0f;
+    Color finalColor = Color::RED;
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+                                                     priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+       SetBackgroundColor_BufferState_NoBufferFill_NoPriorColor_Basic) {
+    bool priorColor = false;
+    bool bufferFill = false;
+    float alpha = 1.0f;
+    Color finalColor = Color::GREEN;
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+                                                     priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+       SetBackgroundColor_BufferState_NoBufferFill_PriorColor_Basic) {
+    bool priorColor = true;
+    bool bufferFill = false;
+    float alpha = 1.0f;
+    Color finalColor = Color::GREEN;
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+                                                     priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+       SetBackgroundColor_BufferState_NoPriorColor_ZeroAlpha_NoEffect) {
+    bool priorColor = false;
+    bool bufferFill = false;
+    float alpha = 0;
+    Color finalColor = Color::BLACK;
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+                                                     priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+       SetBackgroundColor_BufferState_PriorColor_ZeroAlpha_DeleteBackground) {
+    bool priorColor = true;
+    bool bufferFill = false;
+    float alpha = 0;
+    Color finalColor = Color::BLACK;
+    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+                                                     priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) {
+    sp<SurfaceControl> colorLayer;
+    ASSERT_NO_FATAL_FAILURE(colorLayer =
+                                    createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+                                                ISurfaceComposerClient::eFXSurfaceEffect));
+    Transaction()
+            .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+            .setColor(colorLayer, half3(2.0f, 0.0f, 0.0f))
+            .apply();
+
+    getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+// An invalid color will not render a color and the layer will not be visible.
+TEST_P(LayerRenderTypeTransactionTest, SetInvalidColor) {
+    sp<SurfaceControl> colorLayer;
+    ASSERT_NO_FATAL_FAILURE(colorLayer =
+                                    createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+                                                ISurfaceComposerClient::eFXSurfaceEffect));
+    Transaction()
+            .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+            .setColor(colorLayer, half3(1.0f, -1.0f, 0.5f))
+            .apply();
+
+    getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) {
+    sp<SurfaceControl> bufferLayer;
+    sp<SurfaceControl> colorLayer;
+    ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(colorLayer =
+                                    createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+                                                ISurfaceComposerClient::eFXSurfaceEffect));
+    Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
+
+    const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
+    const float alpha = 0.25f;
+    const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
+    // this is handwavy, but the precison loss scaled by 255 (8-bit per
+    // channel) should be less than one
+    const uint8_t tolerance = 1;
+    Transaction()
+            .setColor(colorLayer, color)
+            .setAlpha(colorLayer, alpha)
+            .setLayer(colorLayer, mLayerZBase + 1)
+            .apply();
+    getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
+                                    tolerance);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorWithParentAlpha_Bug74220420) {
+    sp<SurfaceControl> bufferLayer;
+    sp<SurfaceControl> parentLayer;
+    sp<SurfaceControl> colorLayer;
+    ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parentWithAlpha", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */,
+                                                     0 /* buffer height */,
+                                                     ISurfaceComposerClient::eFXSurfaceEffect));
+    Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
+    const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
+    const float alpha = 0.25f;
+    const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
+    // this is handwavy, but the precision loss scaled by 255 (8-bit per
+    // channel) should be less than one
+    const uint8_t tolerance = 1;
+    Transaction()
+            .reparent(colorLayer, parentLayer->getHandle())
+            .setColor(colorLayer, color)
+            .setAlpha(parentLayer, alpha)
+            .setLayer(parentLayer, mLayerZBase + 1)
+            .apply();
+    getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
+                                    tolerance);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+                                                         Color::BLUE, Color::WHITE));
+
+    Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 0, 0).apply();
+    {
+        SCOPED_TRACE("IDENTITY");
+        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+                                           Color::BLUE, Color::WHITE);
+    }
+
+    Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 32, 0).apply();
+    {
+        SCOPED_TRACE("FLIP_H");
+        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED,
+                                           Color::WHITE, Color::BLUE);
+    }
+
+    Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).setPosition(layer, 0, 32).apply();
+    {
+        SCOPED_TRACE("FLIP_V");
+        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE,
+                                           Color::RED, Color::GREEN);
+    }
+
+    Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).setPosition(layer, 32, 0).apply();
+    {
+        SCOPED_TRACE("ROT_90");
+        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED,
+                                           Color::WHITE, Color::GREEN);
+    }
+
+    Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setPosition(layer, 0, 0).apply();
+    {
+        SCOPED_TRACE("SCALE");
+        getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 64), Color::RED, Color::GREEN,
+                                           Color::BLUE, Color::WHITE, true /* filtered */);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+                                                         Color::BLUE, Color::WHITE));
+
+    Transaction()
+            .setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f)
+            .setFrame(layer, Rect(0, 0, 32, 32))
+            .apply();
+    {
+        SCOPED_TRACE("IDENTITY");
+        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+                                           Color::BLUE, Color::WHITE);
+    }
+
+    Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply();
+    {
+        SCOPED_TRACE("FLIP_H");
+        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+                                           Color::BLUE, Color::WHITE);
+    }
+
+    Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply();
+    {
+        SCOPED_TRACE("FLIP_V");
+        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+                                           Color::BLUE, Color::WHITE);
+    }
+
+    Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply();
+    {
+        SCOPED_TRACE("ROT_90");
+        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+                                           Color::BLUE, Color::WHITE);
+    }
+
+    Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply();
+    {
+        SCOPED_TRACE("SCALE");
+        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+                                           Color::BLUE, Color::WHITE);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixRot45_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+                                                         Color::BLUE, Color::WHITE));
+
+    const float rot = M_SQRT1_2; // 45 degrees
+    const float trans = M_SQRT2 * 16.0f;
+    Transaction().setMatrix(layer, rot, rot, -rot, rot).setPosition(layer, trans, 0).apply();
+
+    auto shot = getScreenCapture();
+    // check a 8x8 region inside each color
+    auto get8x8Rect = [](int32_t centerX, int32_t centerY) {
+        const int32_t halfL = 4;
+        return Rect(centerX - halfL, centerY - halfL, centerX + halfL, centerY + halfL);
+    };
+    const int32_t unit = int32_t(trans / 2);
+    shot->expectColor(get8x8Rect(2 * unit, 1 * unit), Color::RED);
+    shot->expectColor(get8x8Rect(3 * unit, 2 * unit), Color::GREEN);
+    shot->expectColor(get8x8Rect(1 * unit, 2 * unit), Color::BLUE);
+    shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithResize_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    // setMatrix is applied after any pending resize, unlike setPosition
+    Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply();
+    {
+        SCOPED_TRACE("resize pending");
+        auto shot = getScreenCapture();
+        const Rect rect(0, 0, 32, 32);
+        shot->expectColor(rect, Color::RED);
+        shot->expectBorder(rect, Color::BLACK);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
+    {
+        SCOPED_TRACE("resize applied");
+        const Rect rect(0, 0, 128, 128);
+        getScreenCapture()->expectColor(rect, Color::RED);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithScaleToWindow_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    // setMatrix is immediate with SCALE_TO_WINDOW, unlike setPosition
+    Transaction()
+            .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
+            .setSize(layer, 64, 64)
+            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+            .apply();
+    getScreenCapture()->expectColor(Rect(0, 0, 128, 128), Color::RED);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetOverrideScalingModeBasic_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+                                                         Color::BLUE, Color::WHITE));
+
+    // XXX SCALE_CROP is not respected; calling setSize and
+    // setOverrideScalingMode in separate transactions does not work
+    // (b/69315456)
+    Transaction()
+            .setSize(layer, 64, 16)
+            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+            .apply();
+    {
+        SCOPED_TRACE("SCALE_TO_WINDOW");
+        getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN,
+                                           Color::BLUE, Color::WHITE, true /* filtered */);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+    const Rect crop(8, 8, 24, 24);
+
+    Transaction().setCrop_legacy(layer, crop).apply();
+    auto shot = getScreenCapture();
+    shot->expectColor(crop, Color::RED);
+    shot->expectBorder(crop, Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+    const Rect crop(8, 8, 24, 24);
+
+    Transaction().setCrop(layer, crop).apply();
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    {
+        SCOPED_TRACE("empty rect");
+        Transaction().setCrop_legacy(layer, Rect(8, 8, 8, 8)).apply();
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    {
+        SCOPED_TRACE("negative rect");
+        Transaction().setCrop_legacy(layer, Rect(8, 8, 0, 0)).apply();
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+    {
+        SCOPED_TRACE("empty rect");
+        Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply();
+        getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+    }
+
+    {
+        SCOPED_TRACE("negative rect");
+        Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply();
+        getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    Transaction().setCrop_legacy(layer, Rect(-128, -64, 128, 64)).apply();
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(32, 64, PIXEL_FORMAT_RGBA_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+    TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE);
+    TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED);
+
+    Transaction().setFrame(layer, Rect(0, 0, 64, 64)).apply();
+
+    Transaction().setBuffer(layer, buffer).apply();
+
+    // Partially out of bounds in the negative (upper left) direction
+    Transaction().setCrop(layer, Rect(-128, -128, 32, 16)).apply();
+    {
+        SCOPED_TRACE("out of bounds, negative (upper left) direction");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 64, 64), Color::BLUE);
+        shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
+    }
+
+    // Partially out of bounds in the positive (lower right) direction
+    Transaction().setCrop(layer, Rect(0, 16, 128, 128)).apply();
+    {
+        SCOPED_TRACE("out of bounds, positive (lower right) direction");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
+        shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
+    }
+
+    // Fully out of buffer space bounds
+    Transaction().setCrop(layer, Rect(-128, -128, -1, -1)).apply();
+    {
+        SCOPED_TRACE("Fully out of bounds");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 64, 16), Color::BLUE);
+        shot->expectColor(Rect(0, 16, 64, 64), Color::RED);
+        shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    const Point position(32, 32);
+    const Rect crop(8, 8, 24, 24);
+    Transaction().setPosition(layer, position.x, position.y).setCrop_legacy(layer, crop).apply();
+    auto shot = getScreenCapture();
+    shot->expectColor(crop + position, Color::RED);
+    shot->expectBorder(crop + position, Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+    const Rect frame(32, 32, 64, 64);
+    const Rect crop(8, 8, 24, 24);
+    Transaction().setFrame(layer, frame).setCrop(layer, crop).apply();
+    auto shot = getScreenCapture();
+    shot->expectColor(frame, Color::RED);
+    shot->expectBorder(frame, Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    // crop_legacy is affected by matrix
+    Transaction()
+            .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
+            .setCrop_legacy(layer, Rect(8, 8, 24, 24))
+            .apply();
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
+    shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithResize_BufferQueue) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    // setCrop_legacy is applied immediately by default, with or without resize pending
+    Transaction().setCrop_legacy(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
+    {
+        SCOPED_TRACE("resize pending");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
+        shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
+    {
+        SCOPED_TRACE("resize applied");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
+        shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+    const Rect frame(8, 8, 24, 24);
+
+    Transaction().setFrame(layer, frame).apply();
+    auto shot = getScreenCapture();
+    shot->expectColor(frame, Color::RED);
+    shot->expectBorder(frame, Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+    {
+        SCOPED_TRACE("empty rect");
+        Transaction().setFrame(layer, Rect(8, 8, 8, 8)).apply();
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    {
+        SCOPED_TRACE("negative rect");
+        Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply();
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10));
+
+    // A parentless layer will default to a frame with the same size as the buffer
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) {
+    sp<SurfaceControl> parent, child;
+    ASSERT_NO_FATAL_FAILURE(
+            parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
+    Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
+
+    ASSERT_NO_FATAL_FAILURE(
+            child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
+
+    Transaction().reparent(child, parent->getHandle()).apply();
+
+    // A layer will default to the frame of its parent
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) {
+    sp<SurfaceControl> parent, child;
+    ASSERT_NO_FATAL_FAILURE(parent = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, Color::RED, 32, 32));
+
+    ASSERT_NO_FATAL_FAILURE(
+            child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
+
+    Transaction().reparent(child, parent->getHandle()).apply();
+
+    // A layer will default to the frame of its parent
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameUpdate_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+    Transaction().setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+    std::this_thread::sleep_for(500ms);
+
+    Transaction().setFrame(layer, Rect(16, 16, 48, 48)).apply();
+
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
+    shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameOutsideBounds_BufferState) {
+    sp<SurfaceControl> parent, child;
+    ASSERT_NO_FATAL_FAILURE(
+            parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    ASSERT_NO_FATAL_FAILURE(
+            child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+    Transaction().reparent(child, parent->getHandle()).apply();
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
+    Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
+    Transaction().setFrame(child, Rect(0, 16, 32, 32)).apply();
+
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(0, 0, 32, 16), Color::RED);
+    shot->expectColor(Rect(0, 16, 32, 32), Color::BLUE);
+    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+    {
+        SCOPED_TRACE("set buffer 1");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+        shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32));
+
+    {
+        SCOPED_TRACE("set buffer 2");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLUE);
+        shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+    {
+        SCOPED_TRACE("set buffer 3");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+        shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) {
+    sp<SurfaceControl> layer1;
+    ASSERT_NO_FATAL_FAILURE(
+            layer1 = createLayer("test", 64, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<SurfaceControl> layer2;
+    ASSERT_NO_FATAL_FAILURE(
+            layer2 = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::RED, 64, 64));
+
+    Transaction().setFrame(layer1, Rect(0, 0, 64, 64)).apply();
+    {
+        SCOPED_TRACE("set layer 1 buffer red");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32));
+
+    Transaction().setFrame(layer2, Rect(0, 0, 32, 32)).apply();
+    {
+        SCOPED_TRACE("set layer 2 buffer blue");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+        shot->expectColor(Rect(0, 32, 64, 64), Color::RED);
+        shot->expectColor(Rect(0, 32, 32, 64), Color::RED);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::GREEN, 64, 64));
+    {
+        SCOPED_TRACE("set layer 1 buffer green");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+        shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
+        shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
+    }
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::WHITE, 32, 32));
+
+    {
+        SCOPED_TRACE("set layer 2 buffer white");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::WHITE);
+        shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
+        shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+    std::array<sp<GraphicBuffer>, 10> buffers;
+
+    size_t idx = 0;
+    for (auto& buffer : buffers) {
+        buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                                   BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                           BufferUsage::COMPOSER_OVERLAY,
+                                   "test");
+        Color color = colors[idx % colors.size()];
+        TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+        idx++;
+    }
+
+    // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+    // cache is working.
+    idx = 0;
+    for (auto& buffer : buffers) {
+        for (int i = 0; i < 2; i++) {
+            Transaction().setBuffer(layer, buffer).apply();
+
+            Color color = colors[idx % colors.size()];
+            auto shot = screenshot();
+            shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
+            shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+        }
+        idx++;
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+    std::array<sp<GraphicBuffer>, 70> buffers;
+
+    size_t idx = 0;
+    for (auto& buffer : buffers) {
+        buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                                   BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                           BufferUsage::COMPOSER_OVERLAY,
+                                   "test");
+        Color color = colors[idx % colors.size()];
+        TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+        idx++;
+    }
+
+    // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+    // cache is working.
+    idx = 0;
+    for (auto& buffer : buffers) {
+        for (int i = 0; i < 2; i++) {
+            Transaction().setBuffer(layer, buffer).apply();
+
+            Color color = colors[idx % colors.size()];
+            auto shot = screenshot();
+            shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
+            shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+        }
+        idx++;
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+    std::array<sp<GraphicBuffer>, 65> buffers;
+
+    size_t idx = 0;
+    for (auto& buffer : buffers) {
+        buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                                   BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                           BufferUsage::COMPOSER_OVERLAY,
+                                   "test");
+        Color color = colors[idx % colors.size()];
+        TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+        idx++;
+    }
+
+    // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+    // cache is working.
+    idx = 0;
+    for (auto& buffer : buffers) {
+        for (int i = 0; i < 2; i++) {
+            Transaction().setBuffer(layer, buffer).apply();
+
+            Color color = colors[idx % colors.size()];
+            auto shot = screenshot();
+            shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
+            shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+        }
+        if (idx == 0) {
+            buffers[0].clear();
+        }
+        idx++;
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+                                                         Color::BLUE, Color::WHITE));
+
+    Transaction()
+            .setFrame(layer, Rect(0, 0, 32, 32))
+            .setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90)
+            .apply();
+
+    getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
+                                       Color::GREEN, true /* filtered */);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipH_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+                                                         Color::BLUE, Color::WHITE));
+
+    Transaction()
+            .setFrame(layer, Rect(0, 0, 32, 32))
+            .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H)
+            .apply();
+
+    getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
+                                       Color::BLUE, true /* filtered */);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipV_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+                                                         Color::BLUE, Color::WHITE));
+
+    Transaction()
+            .setFrame(layer, Rect(0, 0, 32, 32))
+            .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V)
+            .apply();
+
+    getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
+                                       Color::GREEN, true /* filtered */);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFenceBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    Transaction transaction;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+    TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+    sp<Fence> fence;
+    if (getBuffer(nullptr, &fence) != NO_ERROR) {
+        GTEST_SUCCEED() << "test not supported";
+        return;
+    }
+
+    Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply();
+
+    status_t status = fence->wait(1000);
+    ASSERT_NE(static_cast<status_t>(Fence::Status::Unsignaled), status);
+    std::this_thread::sleep_for(200ms);
+
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+    TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+    sp<Fence> fence = Fence::NO_FENCE;
+
+    Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply();
+
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+    TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+    Transaction().setBuffer(layer, buffer).setDataspace(layer, ui::Dataspace::UNKNOWN).apply();
+
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+    TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+    HdrMetadata hdrMetadata;
+    hdrMetadata.validTypes = 0;
+    Transaction().setBuffer(layer, buffer).setHdrMetadata(layer, hdrMetadata).apply();
+
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+    TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+    Region region;
+    region.set(32, 32);
+    Transaction().setBuffer(layer, buffer).setSurfaceDamageRegion(layer, region).apply();
+
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+    TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+    Transaction().setBuffer(layer, buffer).setApi(layer, NATIVE_WINDOW_API_CPU).apply();
+
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) {
+    sp<SurfaceControl> colorLayer;
+    ASSERT_NO_FATAL_FAILURE(colorLayer =
+                                    createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+                                                ISurfaceComposerClient::eFXSurfaceEffect));
+    Transaction()
+            .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+            .setLayer(colorLayer, mLayerZBase + 1)
+            .apply();
+    {
+        SCOPED_TRACE("default color");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
+    half3 expected = color;
+    mat3 matrix;
+    matrix[0][0] = 0.3;
+    matrix[1][0] = 0.59;
+    matrix[2][0] = 0.11;
+    matrix[0][1] = 0.3;
+    matrix[1][1] = 0.59;
+    matrix[2][1] = 0.11;
+    matrix[0][2] = 0.3;
+    matrix[1][2] = 0.59;
+    matrix[2][2] = 0.11;
+
+    // degamma before applying the matrix
+    if (mColorManagementUsed) {
+        ColorTransformHelper::DegammaColor(expected);
+    }
+
+    ColorTransformHelper::applyMatrix(expected, matrix);
+
+    if (mColorManagementUsed) {
+        ColorTransformHelper::GammaColor(expected);
+    }
+
+    const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
+                                 uint8_t(expected.b * 255), 255};
+
+    // this is handwavy, but the precison loss scaled by 255 (8-bit per
+    // channel) should be less than one
+    const uint8_t tolerance = 1;
+
+    Transaction().setColor(colorLayer, color).setColorTransform(colorLayer, matrix, vec3()).apply();
+    {
+        SCOPED_TRACE("new color");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnParent) {
+    sp<SurfaceControl> parentLayer;
+    sp<SurfaceControl> colorLayer;
+    ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
+                                                      0 /* buffer height */,
+                                                      ISurfaceComposerClient::eFXSurfaceContainer));
+    ASSERT_NO_FATAL_FAILURE(
+            colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+                                     ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get()));
+
+    Transaction()
+            .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
+            .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+            .setLayer(parentLayer, mLayerZBase + 1)
+            .apply();
+    {
+        SCOPED_TRACE("default color");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
+    half3 expected = color;
+    mat3 matrix;
+    matrix[0][0] = 0.3;
+    matrix[1][0] = 0.59;
+    matrix[2][0] = 0.11;
+    matrix[0][1] = 0.3;
+    matrix[1][1] = 0.59;
+    matrix[2][1] = 0.11;
+    matrix[0][2] = 0.3;
+    matrix[1][2] = 0.59;
+    matrix[2][2] = 0.11;
+
+    // degamma before applying the matrix
+    if (mColorManagementUsed) {
+        ColorTransformHelper::DegammaColor(expected);
+    }
+
+    ColorTransformHelper::applyMatrix(expected, matrix);
+
+    if (mColorManagementUsed) {
+        ColorTransformHelper::GammaColor(expected);
+    }
+
+    const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
+                                 uint8_t(expected.b * 255), 255};
+
+    // this is handwavy, but the precison loss scaled by 255 (8-bit per
+    // channel) should be less than one
+    const uint8_t tolerance = 1;
+
+    Transaction()
+            .setColor(colorLayer, color)
+            .setColorTransform(parentLayer, matrix, vec3())
+            .apply();
+    {
+        SCOPED_TRACE("new color");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+    }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnChildAndParent) {
+    sp<SurfaceControl> parentLayer;
+    sp<SurfaceControl> colorLayer;
+    ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
+                                                      0 /* buffer height */,
+                                                      ISurfaceComposerClient::eFXSurfaceContainer));
+    ASSERT_NO_FATAL_FAILURE(
+            colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+                                     ISurfaceComposerClient::eFXSurfaceEffect, parentLayer.get()));
+
+    Transaction()
+            .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
+            .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+            .setLayer(parentLayer, mLayerZBase + 1)
+            .apply();
+    {
+        SCOPED_TRACE("default color");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
+    half3 expected = color;
+    mat3 matrixChild;
+    matrixChild[0][0] = 0.3;
+    matrixChild[1][0] = 0.59;
+    matrixChild[2][0] = 0.11;
+    matrixChild[0][1] = 0.3;
+    matrixChild[1][1] = 0.59;
+    matrixChild[2][1] = 0.11;
+    matrixChild[0][2] = 0.3;
+    matrixChild[1][2] = 0.59;
+    matrixChild[2][2] = 0.11;
+    mat3 matrixParent;
+    matrixParent[0][0] = 0.2;
+    matrixParent[1][0] = 0.4;
+    matrixParent[2][0] = 0.10;
+    matrixParent[0][1] = 0.2;
+    matrixParent[1][1] = 0.4;
+    matrixParent[2][1] = 0.10;
+    matrixParent[0][2] = 0.2;
+    matrixParent[1][2] = 0.4;
+    matrixParent[2][2] = 0.10;
+
+    // degamma before applying the matrix
+    if (mColorManagementUsed) {
+        ColorTransformHelper::DegammaColor(expected);
+    }
+
+    ColorTransformHelper::applyMatrix(expected, matrixChild);
+    ColorTransformHelper::applyMatrix(expected, matrixParent);
+
+    if (mColorManagementUsed) {
+        ColorTransformHelper::GammaColor(expected);
+    }
+
+    const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
+                                 uint8_t(expected.b * 255), 255};
+
+    // this is handwavy, but the precison loss scaled by 255 (8-bit per
+    // channel) should be less than one
+    const uint8_t tolerance = 1;
+
+    Transaction()
+            .setColor(colorLayer, color)
+            .setColorTransform(parentLayer, matrixParent, vec3())
+            .setColorTransform(colorLayer, matrixChild, vec3())
+            .apply();
+    {
+        SCOPED_TRACE("new color");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+    }
+}
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
new file mode 100644
index 0000000..f3e11d8
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 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 <gtest/gtest.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <ui/DisplayConfig.h>
+
+#include "BufferGenerator.h"
+#include "utils/ScreenshotUtils.h"
+#include "utils/TransactionUtils.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class LayerTransactionTest : public ::testing::Test {
+protected:
+    void SetUp() override {
+        mClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
+
+        ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
+
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed));
+    }
+
+    virtual void TearDown() {
+        mBlackBgSurface = 0;
+        mClient->dispose();
+        mClient = 0;
+    }
+
+    virtual sp<SurfaceControl> createLayer(const sp<SurfaceComposerClient>& client,
+                                           const char* name, uint32_t width, uint32_t height,
+                                           uint32_t flags = 0, SurfaceControl* parent = nullptr,
+                                           uint32_t* outTransformHint = nullptr,
+                                           PixelFormat format = PIXEL_FORMAT_RGBA_8888) {
+        auto layer =
+                createSurface(client, name, width, height, format, flags, parent, outTransformHint);
+
+        Transaction t;
+        t.setLayerStack(layer, mDisplayLayerStack).setLayer(layer, mLayerZBase);
+
+        status_t error = t.apply();
+        if (error != NO_ERROR) {
+            ADD_FAILURE() << "failed to initialize SurfaceControl";
+            layer.clear();
+        }
+
+        return layer;
+    }
+
+    virtual sp<SurfaceControl> createSurface(const sp<SurfaceComposerClient>& client,
+                                             const char* name, uint32_t width, uint32_t height,
+                                             PixelFormat format, uint32_t flags,
+                                             SurfaceControl* parent = nullptr,
+                                             uint32_t* outTransformHint = nullptr) {
+        auto layer = client->createSurface(String8(name), width, height, format, flags, parent,
+                                           LayerMetadata(), outTransformHint);
+        EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
+        return layer;
+    }
+
+    virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+                                           uint32_t flags = 0, SurfaceControl* parent = nullptr,
+                                           uint32_t* outTransformHint = nullptr,
+                                           PixelFormat format = PIXEL_FORMAT_RGBA_8888) {
+        return createLayer(mClient, name, width, height, flags, parent, outTransformHint, format);
+    }
+
+    sp<SurfaceControl> createColorLayer(const char* name, const Color& color,
+                                        SurfaceControl* parent = nullptr) {
+        auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */,
+                                        PIXEL_FORMAT_RGBA_8888,
+                                        ISurfaceComposerClient::eFXSurfaceEffect, parent);
+        asTransaction([&](Transaction& t) {
+            t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f});
+            t.setAlpha(colorLayer, color.a / 255.0f);
+        });
+        return colorLayer;
+    }
+
+    ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
+        // wait for previous transactions (such as setSize) to complete
+        Transaction().apply(true);
+
+        ANativeWindow_Buffer buffer = {};
+        EXPECT_EQ(NO_ERROR, layer->getSurface()->lock(&buffer, nullptr));
+
+        return buffer;
+    }
+
+    void postBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
+        ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost());
+
+        // wait for the newly posted buffer to be latched
+        waitForLayerBuffers();
+    }
+
+    virtual void fillBufferQueueLayerColor(const sp<SurfaceControl>& layer, const Color& color,
+                                           int32_t bufferWidth, int32_t bufferHeight) {
+        ANativeWindow_Buffer buffer;
+        ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+        TransactionUtils::fillANativeWindowBufferColor(buffer,
+                                                       Rect(0, 0, bufferWidth, bufferHeight),
+                                                       color);
+        postBufferQueueLayerBuffer(layer);
+    }
+
+    virtual void fillBufferStateLayerColor(const sp<SurfaceControl>& layer, const Color& color,
+                                           int32_t bufferWidth, int32_t bufferHeight) {
+        sp<GraphicBuffer> buffer =
+                new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
+                                  BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                          BufferUsage::COMPOSER_OVERLAY,
+                                  "test");
+        TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight),
+                                                 color);
+        Transaction().setBuffer(layer, buffer).apply();
+    }
+
+    void fillLayerColor(uint32_t mLayerType, const sp<SurfaceControl>& layer, const Color& color,
+                        int32_t bufferWidth, int32_t bufferHeight) {
+        switch (mLayerType) {
+            case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+                fillBufferQueueLayerColor(layer, color, bufferWidth, bufferHeight);
+                break;
+            case ISurfaceComposerClient::eFXSurfaceBufferState:
+                fillBufferStateLayerColor(layer, color, bufferWidth, bufferHeight);
+                break;
+            default:
+                ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType;
+        }
+    }
+
+    void fillLayerQuadrant(uint32_t mLayerType, const sp<SurfaceControl>& layer,
+                           int32_t bufferWidth, int32_t bufferHeight, const Color& topLeft,
+                           const Color& topRight, const Color& bottomLeft,
+                           const Color& bottomRight) {
+        switch (mLayerType) {
+            case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+                fillBufferQueueLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight,
+                                             bottomLeft, bottomRight);
+                break;
+            case ISurfaceComposerClient::eFXSurfaceBufferState:
+                fillBufferStateLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight,
+                                             bottomLeft, bottomRight);
+                break;
+            default:
+                ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType;
+        }
+    }
+
+    virtual void fillBufferQueueLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
+                                              int32_t bufferHeight, const Color& topLeft,
+                                              const Color& topRight, const Color& bottomLeft,
+                                              const Color& bottomRight) {
+        ANativeWindow_Buffer buffer;
+        ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+        ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
+
+        const int32_t halfW = bufferWidth / 2;
+        const int32_t halfH = bufferHeight / 2;
+        TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
+        TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH),
+                                                       topRight);
+        TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight),
+                                                       bottomLeft);
+        TransactionUtils::fillANativeWindowBufferColor(buffer,
+                                                       Rect(halfW, halfH, bufferWidth,
+                                                            bufferHeight),
+                                                       bottomRight);
+
+        postBufferQueueLayerBuffer(layer);
+    }
+
+    virtual void fillBufferStateLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
+                                              int32_t bufferHeight, const Color& topLeft,
+                                              const Color& topRight, const Color& bottomLeft,
+                                              const Color& bottomRight) {
+        sp<GraphicBuffer> buffer =
+                new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
+                                  BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                          BufferUsage::COMPOSER_OVERLAY,
+                                  "test");
+
+        ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
+
+        const int32_t halfW = bufferWidth / 2;
+        const int32_t halfH = bufferHeight / 2;
+        TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
+        TransactionUtils::fillGraphicBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH),
+                                                 topRight);
+        TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight),
+                                                 bottomLeft);
+        TransactionUtils::fillGraphicBufferColor(buffer,
+                                                 Rect(halfW, halfH, bufferWidth, bufferHeight),
+                                                 bottomRight);
+
+        Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply();
+    }
+
+    std::unique_ptr<ScreenCapture> screenshot() {
+        std::unique_ptr<ScreenCapture> screenshot;
+        ScreenCapture::captureScreen(&screenshot);
+        return screenshot;
+    }
+
+    void asTransaction(const std::function<void(Transaction&)>& exec) {
+        Transaction t;
+        exec(t);
+        t.apply(true);
+    }
+
+    static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
+        static BufferGenerator bufferGenerator;
+        return bufferGenerator.get(outBuffer, outFence);
+    }
+
+    sp<SurfaceComposerClient> mClient;
+
+    sp<IBinder> mDisplay;
+    uint32_t mDisplayWidth;
+    uint32_t mDisplayHeight;
+    uint32_t mDisplayLayerStack;
+    Rect mDisplayRect = Rect::INVALID_RECT;
+
+    // leave room for ~256 layers
+    const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256;
+
+    sp<SurfaceControl> mBlackBgSurface;
+    bool mColorManagementUsed;
+
+private:
+    void SetUpDisplay() {
+        mDisplay = mClient->getInternalDisplayToken();
+        ASSERT_FALSE(mDisplay == nullptr) << "failed to get display";
+
+        DisplayConfig config;
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplay, &config));
+        mDisplayRect = Rect(config.resolution);
+        mDisplayWidth = mDisplayRect.getWidth();
+        mDisplayHeight = mDisplayRect.getHeight();
+
+        // After a new buffer is queued, SurfaceFlinger is notified and will
+        // latch the new buffer on next vsync.  Let's heuristically wait for 3
+        // vsyncs.
+        mBufferPostDelay = static_cast<int32_t>(1e6 / config.refreshRate) * 3;
+
+        mDisplayLayerStack = 0;
+
+        mBlackBgSurface =
+                createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */,
+                              PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
+
+        // set layer stack (b/68888219)
+        Transaction t;
+        t.setDisplayLayerStack(mDisplay, mDisplayLayerStack);
+        t.setCrop_legacy(mBlackBgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight));
+        t.setLayerStack(mBlackBgSurface, mDisplayLayerStack);
+        t.setColor(mBlackBgSurface, half3{0, 0, 0});
+        t.setLayer(mBlackBgSurface, mLayerZBase);
+        t.apply();
+    }
+
+    void waitForLayerBuffers() {
+        // Request an empty transaction to get applied synchronously to ensure the buffer is
+        // latched.
+        Transaction().apply(true);
+        usleep(mBufferPostDelay);
+    }
+
+    int32_t mBufferPostDelay;
+
+    friend class LayerRenderPathTestHarness;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp
new file mode 100644
index 0000000..1f8f7ed
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <private/android_filesystem_config.h>
+#include <thread>
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+TEST_F(LayerTransactionTest, SetFlagsSecureEUidSystem) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<GraphicBuffer> outBuffer;
+    Transaction()
+            .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
+            .apply(true);
+    ASSERT_EQ(PERMISSION_DENIED,
+              composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+    UIDFaker f(AID_SYSTEM);
+
+    // By default the system can capture screenshots with secure layers but they
+    // will be blacked out
+    ASSERT_EQ(NO_ERROR, composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+    {
+        SCOPED_TRACE("as system");
+        auto shot = screenshot();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+
+    // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able
+    // to receive them...we are expected to take care with the results.
+    bool outCapturedSecureLayers;
+    ASSERT_EQ(NO_ERROR,
+              composer->captureScreen(mDisplay, &outBuffer, outCapturedSecureLayers,
+                                      ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), 0,
+                                      0, false, ui::ROTATION_0, true));
+    ASSERT_EQ(true, outCapturedSecureLayers);
+    ScreenCapture sc(outBuffer);
+    sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_F(LayerTransactionTest, SetTransformToDisplayInverse_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    Transaction().setTransformToDisplayInverse(layer, false).apply();
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::GREEN, 32, 32));
+
+    Transaction().setTransformToDisplayInverse(layer, true).apply();
+}
+
+TEST_F(LayerTransactionTest, SetSidebandStreamNull_BufferState) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(
+            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+    // verify this doesn't cause a crash
+    Transaction().setSidebandStream(layer, nullptr).apply();
+}
+
+TEST_F(LayerTransactionTest, ReparentToSelf) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+    Transaction().reparent(layer, layer->getHandle()).apply();
+
+    {
+        // We expect the transaction to be silently dropped, but for SurfaceFlinger
+        // to still be functioning.
+        SCOPED_TRACE("after reparent to self");
+        const Rect rect(0, 0, 32, 32);
+        auto shot = screenshot();
+        shot->expectColor(rect, Color::RED);
+        shot->expectBorder(rect, Color::BLACK);
+    }
+}
+
+// This test ensures that when we drop an app buffer in SurfaceFlinger, we merge
+// the dropped buffer's damage region into the next buffer's damage region. If
+// we don't do this, we'll report an incorrect damage region to hardware
+// composer, resulting in broken rendering. This test checks the BufferQueue
+// case.
+//
+// Unfortunately, we don't currently have a way to inspect the damage region
+// SurfaceFlinger sends to hardware composer from a test, so this test requires
+// the dev to manually watch the device's screen during the test to spot broken
+// rendering. Because the results can't be automatically verified, this test is
+// marked disabled.
+TEST_F(LayerTransactionTest, DISABLED_BufferQueueLayerMergeDamageRegionWhenDroppingBuffers) {
+    const int width = mDisplayWidth;
+    const int height = mDisplayHeight;
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
+    const auto producer = layer->getIGraphicBufferProducer();
+    const sp<IProducerListener> stubListener(new StubProducerListener);
+    IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
+    ASSERT_EQ(OK, producer->connect(stubListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput));
+
+    std::map<int, sp<GraphicBuffer>> slotMap;
+    auto slotToBuffer = [&](int slot, sp<GraphicBuffer>* buf) {
+        ASSERT_NE(nullptr, buf);
+        const auto iter = slotMap.find(slot);
+        ASSERT_NE(slotMap.end(), iter);
+        *buf = iter->second;
+    };
+
+    auto dequeue = [&](int* outSlot) {
+        ASSERT_NE(nullptr, outSlot);
+        *outSlot = -1;
+        int slot;
+        sp<Fence> fence;
+        uint64_t age;
+        FrameEventHistoryDelta timestamps;
+        const status_t dequeueResult =
+                producer->dequeueBuffer(&slot, &fence, width, height, PIXEL_FORMAT_RGBA_8888,
+                                        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                                        &age, &timestamps);
+        if (dequeueResult == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+            sp<GraphicBuffer> newBuf;
+            ASSERT_EQ(OK, producer->requestBuffer(slot, &newBuf));
+            ASSERT_NE(nullptr, newBuf.get());
+            slotMap[slot] = newBuf;
+        } else {
+            ASSERT_EQ(OK, dequeueResult);
+        }
+        *outSlot = slot;
+    };
+
+    auto queue = [&](int slot, const Region& damage, nsecs_t displayTime) {
+        IGraphicBufferProducer::QueueBufferInput input(
+                /*timestamp=*/displayTime, /*isAutoTimestamp=*/false, HAL_DATASPACE_UNKNOWN,
+                /*crop=*/Rect::EMPTY_RECT, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
+                /*transform=*/0, Fence::NO_FENCE);
+        input.setSurfaceDamage(damage);
+        IGraphicBufferProducer::QueueBufferOutput output;
+        ASSERT_EQ(OK, producer->queueBuffer(slot, input, &output));
+    };
+
+    auto fillAndPostBuffers = [&](const Color& color) {
+        int slot1;
+        ASSERT_NO_FATAL_FAILURE(dequeue(&slot1));
+        int slot2;
+        ASSERT_NO_FATAL_FAILURE(dequeue(&slot2));
+
+        sp<GraphicBuffer> buf1;
+        ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot1, &buf1));
+        sp<GraphicBuffer> buf2;
+        ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot2, &buf2));
+        TransactionUtils::fillGraphicBufferColor(buf1, Rect(width, height), color);
+        TransactionUtils::fillGraphicBufferColor(buf2, Rect(width, height), color);
+
+        const auto displayTime = systemTime() + milliseconds_to_nanoseconds(100);
+        ASSERT_NO_FATAL_FAILURE(queue(slot1, Region::INVALID_REGION, displayTime));
+        ASSERT_NO_FATAL_FAILURE(
+                queue(slot2, Region(Rect(width / 3, height / 3, 2 * width / 3, 2 * height / 3)),
+                      displayTime));
+    };
+
+    const auto startTime = systemTime();
+    const std::array<Color, 3> colors = {Color::RED, Color::GREEN, Color::BLUE};
+    int colorIndex = 0;
+    while (nanoseconds_to_seconds(systemTime() - startTime) < 10) {
+        ASSERT_NO_FATAL_FAILURE(fillAndPostBuffers(colors[colorIndex++ % colors.size()]));
+        std::this_thread::sleep_for(1s);
+    }
+
+    ASSERT_EQ(OK, producer->disconnect(NATIVE_WINDOW_API_CPU));
+}
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
new file mode 100644
index 0000000..7d4314f
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -0,0 +1,477 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <cutils/properties.h>
+#include <gui/BufferItemConsumer.h>
+#include "TransactionTestHarnesses.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class LayerTypeAndRenderTypeTransactionTest
+      : public LayerTypeTransactionHarness,
+        public ::testing::WithParamInterface<std::tuple<uint32_t, RenderPath>> {
+public:
+    LayerTypeAndRenderTypeTransactionTest()
+          : LayerTypeTransactionHarness(std::get<0>(GetParam())),
+            mRenderPathHarness(LayerRenderPathTestHarness(this, std::get<1>(GetParam()))) {}
+
+    std::unique_ptr<ScreenCapture> getScreenCapture() {
+        return mRenderPathHarness.getScreenCapture();
+    }
+
+protected:
+    LayerRenderPathTestHarness mRenderPathHarness;
+};
+
+::testing::Environment* const binderEnv =
+        ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+INSTANTIATE_TEST_CASE_P(
+        LayerTypeAndRenderTypeTransactionTests, LayerTypeAndRenderTypeTransactionTest,
+        ::testing::Combine(
+                ::testing::Values(
+                        static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
+                        static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)),
+                ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT)));
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetSizeInvalid) {
+    // cannot test robustness against invalid sizes (zero or really huge)
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZBasic) {
+    sp<SurfaceControl> layerR;
+    sp<SurfaceControl> layerG;
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
+
+    Transaction().setLayer(layerR, mLayerZBase + 1).apply();
+    {
+        SCOPED_TRACE("layerR");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    Transaction().setLayer(layerG, mLayerZBase + 2).apply();
+    {
+        SCOPED_TRACE("layerG");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
+    }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetRelativeZBug64572777) {
+    sp<SurfaceControl> layerR;
+    sp<SurfaceControl> layerG;
+
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
+
+    Transaction()
+            .setPosition(layerG, 16, 16)
+            .setRelativeLayer(layerG, layerR->getHandle(), 1)
+            .apply();
+
+    Transaction().reparent(layerG, nullptr).apply();
+
+    // layerG should have been removed
+    getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsHidden) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+
+    Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply();
+    {
+        SCOPED_TRACE("layer hidden");
+        getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
+    }
+
+    Transaction().setFlags(layer, 0, layer_state_t::eLayerHidden).apply();
+    {
+        SCOPED_TRACE("layer shown");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsOpaque) {
+    const Color translucentRed = {100, 0, 0, 100};
+    sp<SurfaceControl> layerR;
+    sp<SurfaceControl> layerG;
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, translucentRed, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
+
+    Transaction()
+            .setLayer(layerR, mLayerZBase + 1)
+            .setFlags(layerR, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque)
+            .apply();
+    {
+        SCOPED_TRACE("layerR opaque");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, 0, 0, 255});
+    }
+
+    Transaction().setFlags(layerR, 0, layer_state_t::eLayerOpaque).apply();
+    {
+        SCOPED_TRACE("layerR translucent");
+        const uint8_t g = uint8_t(255 - translucentRed.a);
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, g, 0, 255});
+    }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZNegative) {
+    sp<SurfaceControl> parent =
+            LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
+                                              ISurfaceComposerClient::eFXSurfaceContainer);
+    Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
+    sp<SurfaceControl> layerR;
+    sp<SurfaceControl> layerG;
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
+
+    Transaction()
+            .reparent(layerR, parent->getHandle())
+            .reparent(layerG, parent->getHandle())
+            .apply();
+    Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply();
+    {
+        SCOPED_TRACE("layerR");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+
+    Transaction().setLayer(layerR, -3).apply();
+    {
+        SCOPED_TRACE("layerG");
+        auto shot = getScreenCapture();
+        shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
+    }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetAlphaClamped) {
+    const Color color = {64, 0, 0, 255};
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, color, 32, 32));
+
+    Transaction().setAlpha(layer, 2.0f).apply();
+    {
+        SCOPED_TRACE("clamped to 1.0f");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), color);
+    }
+
+    Transaction().setAlpha(layer, -1.0f).apply();
+    {
+        SCOPED_TRACE("clamped to 0.0f");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+    }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) {
+    sp<SurfaceControl> layer;
+    const uint8_t size = 64;
+    const uint8_t testArea = 4;
+    const float cornerRadius = 20.0f;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size));
+
+    if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
+        Transaction()
+                .setCornerRadius(layer, cornerRadius)
+                .setCrop_legacy(layer, Rect(0, 0, size, size))
+                .apply();
+    } else {
+        Transaction()
+                .setCornerRadius(layer, cornerRadius)
+                .setFrame(layer, Rect(0, 0, size, size))
+                .apply();
+    }
+    {
+        const uint8_t bottom = size - 1;
+        const uint8_t right = size - 1;
+        auto shot = getScreenCapture();
+        // Transparent corners
+        shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK);
+        shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::BLACK);
+        shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
+        shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::BLACK);
+        // Solid center
+        shot->expectColor(Rect(size / 2 - testArea / 2, size / 2 - testArea / 2,
+                               size / 2 + testArea / 2, size / 2 + testArea / 2),
+                          Color::RED);
+    }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusRotated) {
+    sp<SurfaceControl> parent;
+    sp<SurfaceControl> child;
+    const uint8_t size = 64;
+    const uint8_t testArea = 4;
+    const float cornerRadius = 20.0f;
+    ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, size, size));
+    ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size));
+
+    auto transaction = Transaction()
+                               .setCornerRadius(parent, cornerRadius)
+                               .setCrop_legacy(parent, Rect(0, 0, size, size))
+                               .reparent(child, parent->getHandle())
+                               .setPosition(child, 0, size)
+                               // Rotate by half PI
+                               .setMatrix(child, 0.0f, -1.0f, 1.0f, 0.0f);
+    if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
+        transaction.setCrop_legacy(parent, Rect(0, 0, size, size));
+    } else {
+        transaction.setFrame(parent, Rect(0, 0, size, size));
+    }
+    transaction.apply();
+
+    {
+        const uint8_t bottom = size - 1;
+        const uint8_t right = size - 1;
+        auto shot = getScreenCapture();
+        // Edges are transparent
+        shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK);
+        shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::BLACK);
+        shot->expectColor(Rect(0, bottom - testArea, testArea, bottom - testArea), Color::BLACK);
+        shot->expectColor(Rect(right - testArea, bottom - testArea, right, bottom), Color::BLACK);
+        // Solid center
+        shot->expectColor(Rect(size / 2 - testArea / 2, size / 2 - testArea / 2,
+                               size / 2 + testArea / 2, size / 2 + testArea / 2),
+                          Color::GREEN);
+    }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) {
+    sp<SurfaceControl> parent;
+    sp<SurfaceControl> child;
+    const uint8_t size = 64;
+    const uint8_t testArea = 4;
+    const float cornerRadius = 20.0f;
+    ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, size, size));
+    ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2));
+
+    if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
+        Transaction()
+                .setCornerRadius(parent, cornerRadius)
+                .setCrop_legacy(parent, Rect(0, 0, size, size))
+                .reparent(child, parent->getHandle())
+                .setPosition(child, 0, size / 2)
+                .apply();
+    } else {
+        Transaction()
+                .setCornerRadius(parent, cornerRadius)
+                .setFrame(parent, Rect(0, 0, size, size))
+                .reparent(child, parent->getHandle())
+                .setFrame(child, Rect(0, size / 2, size, size))
+                .apply();
+    }
+    {
+        const uint8_t bottom = size - 1;
+        const uint8_t right = size - 1;
+        auto shot = getScreenCapture();
+        // Top edge of child should not have rounded corners because it's translated in the parent
+        shot->expectColor(Rect(0, size / 2, right, static_cast<int>(bottom - cornerRadius)),
+                          Color::GREEN);
+        // But bottom edges should have been clipped according to parent bounds
+        shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
+        shot->expectColor(Rect(right - testArea, bottom - testArea, right, bottom), Color::BLACK);
+    }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadius) {
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.surface_flinger.supports_background_blur", value, "0");
+    if (!atoi(value)) {
+        // This device doesn't support blurs, no-op.
+        return;
+    }
+
+    auto size = 256;
+    auto center = size / 2;
+    auto blurRadius = 50;
+
+    sp<SurfaceControl> backgroundLayer;
+    ASSERT_NO_FATAL_FAILURE(backgroundLayer = createLayer("background", size, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(backgroundLayer, Color::GREEN, size, size));
+
+    sp<SurfaceControl> leftLayer;
+    ASSERT_NO_FATAL_FAILURE(leftLayer = createLayer("left", size / 2, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(leftLayer, Color::RED, size / 2, size));
+
+    sp<SurfaceControl> blurLayer;
+    ASSERT_NO_FATAL_FAILURE(blurLayer = createLayer("blur", size, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(blurLayer, Color::TRANSPARENT, size, size));
+
+    Transaction().setBackgroundBlurRadius(blurLayer, blurRadius).apply();
+
+    auto shot = getScreenCapture();
+    // Edges are mixed
+    shot->expectColor(Rect(center - 1, center - 5, center, center + 5), Color{150, 150, 0, 255},
+                      50 /* tolerance */);
+    shot->expectColor(Rect(center, center - 5, center + 1, center + 5), Color{150, 150, 0, 255},
+                      50 /* tolerance */);
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusOnMultipleLayers) {
+    char value[PROPERTY_VALUE_MAX];
+    property_get("ro.surface_flinger.supports_background_blur", value, "0");
+    if (!atoi(value)) {
+        // This device doesn't support blurs, no-op.
+        return;
+    }
+
+    auto size = 256;
+    auto center = size / 2;
+    auto blurRadius = 50;
+
+    sp<SurfaceControl> backgroundLayer;
+    ASSERT_NO_FATAL_FAILURE(backgroundLayer = createLayer("background", size, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(backgroundLayer, Color::GREEN, size, size));
+
+    sp<SurfaceControl> leftLayer;
+    ASSERT_NO_FATAL_FAILURE(leftLayer = createLayer("left", size / 2, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(leftLayer, Color::RED, size / 2, size));
+
+    sp<SurfaceControl> blurLayer1;
+    auto centralSquareSize = size / 2;
+    ASSERT_NO_FATAL_FAILURE(blurLayer1 =
+                                    createLayer("blur1", centralSquareSize, centralSquareSize));
+    ASSERT_NO_FATAL_FAILURE(
+            fillLayerColor(blurLayer1, Color::BLUE, centralSquareSize, centralSquareSize));
+
+    sp<SurfaceControl> blurLayer2;
+    ASSERT_NO_FATAL_FAILURE(blurLayer2 = createLayer("blur2", size, size));
+    ASSERT_NO_FATAL_FAILURE(
+            fillLayerColor(blurLayer2, Color::TRANSPARENT, centralSquareSize, centralSquareSize));
+
+    Transaction()
+            .setBackgroundBlurRadius(blurLayer1, blurRadius)
+            .setBackgroundBlurRadius(blurLayer2, blurRadius)
+            .apply();
+
+    auto shot = getScreenCapture();
+    shot->expectColor(Rect(center - 5, center - 5, center, center), Color{100, 100, 100, 255},
+                      40 /* tolerance */);
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) {
+    sp<SurfaceControl> bufferLayer;
+    ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED, 32, 32));
+
+    // color is ignored
+    Transaction().setColor(bufferLayer, half3(0.0f, 1.0f, 0.0f)).apply();
+    getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetLayerStackBasic) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+
+    Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
+    {
+        SCOPED_TRACE("non-existing layer stack");
+        getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
+    }
+
+    Transaction().setLayerStack(layer, mDisplayLayerStack).apply();
+    {
+        SCOPED_TRACE("original layer stack");
+        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+    }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBufferFormat) {
+    int32_t width = 100;
+    int32_t height = 100;
+    Rect crop = Rect(0, 0, width, height);
+
+    sp<SurfaceControl> behindLayer = createColorLayer("Behind layer", Color::RED);
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height, 0, nullptr, nullptr,
+                                                PIXEL_FORMAT_RGBX_8888));
+
+    Transaction()
+            .setLayer(layer, INT32_MAX - 1)
+            .show(layer)
+            .setLayerStack(behindLayer, mDisplayLayerStack)
+            .setCrop_legacy(behindLayer, crop)
+            .setLayer(behindLayer, INT32_MAX - 2)
+            .show(behindLayer)
+            .apply();
+
+    sp<Surface> surface = layer->getSurface();
+
+    sp<GraphicBuffer> buffer =
+            new GraphicBuffer(width, height, PIXEL_FORMAT_RGBX_8888, 1,
+                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                      BufferUsage::COMPOSER_OVERLAY,
+                              "test");
+    ASSERT_NO_FATAL_FAILURE(
+            TransactionUtils::fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT));
+
+    if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
+        Surface::attachAndQueueBufferWithDataspace(surface.get(), buffer, ui::Dataspace::V0_SRGB);
+    } else {
+        Transaction().setBuffer(layer, buffer).apply();
+    }
+
+    {
+        SCOPED_TRACE("Buffer Opaque Format");
+        auto shot = screenshot();
+        shot->expectColor(crop, Color::BLACK);
+    }
+
+    buffer = new GraphicBuffer(width, height, PIXEL_FORMAT_RGBA_8888, 1,
+                               BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+                                       BufferUsage::COMPOSER_OVERLAY,
+                               "test");
+    ASSERT_NO_FATAL_FAILURE(
+            TransactionUtils::fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT));
+
+    if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
+        Surface::attachAndQueueBufferWithDataspace(surface.get(), buffer, ui::Dataspace::V0_SRGB);
+    } else {
+        Transaction().setBuffer(layer, buffer).apply();
+    }
+
+    {
+        SCOPED_TRACE("Buffer Transparent Format");
+        auto shot = screenshot();
+        shot->expectColor(crop, Color::RED);
+    }
+}
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
new file mode 100644
index 0000000..84780ba
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <gui/BufferItemConsumer.h>
+#include "TransactionTestHarnesses.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class LayerTypeTransactionTest : public LayerTypeTransactionHarness,
+                                 public ::testing::WithParamInterface<uint32_t> {
+public:
+    LayerTypeTransactionTest() : LayerTypeTransactionHarness(GetParam()) {}
+};
+
+::testing::Environment* const binderEnv =
+        ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+INSTANTIATE_TEST_CASE_P(
+        LayerTypeTransactionTests, LayerTypeTransactionTest,
+        ::testing::Values(static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
+                          static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)));
+
+TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) {
+    sp<SurfaceControl> parent =
+            LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
+                                              ISurfaceComposerClient::eFXSurfaceContainer);
+    Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
+    sp<SurfaceControl> layerR;
+    sp<SurfaceControl> layerG;
+    sp<SurfaceControl> layerB;
+    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
+    ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE, 32, 32));
+
+    Transaction().reparent(layerB, parent->getHandle()).apply();
+
+    // layerR = mLayerZBase, layerG = layerR - 1, layerB = -2
+    Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).setLayer(layerB, -2).apply();
+
+    std::unique_ptr<ScreenCapture> screenshot;
+    // only layerB is in this range
+    sp<IBinder> parentHandle = parent->getHandle();
+    ScreenCapture::captureLayers(&screenshot, parentHandle, Rect(0, 0, 32, 32));
+    screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+}
+
+TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) {
+    sp<SurfaceControl> parent =
+            LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
+                                              ISurfaceComposerClient::eFXSurfaceEffect);
+
+    sp<SurfaceControl> childLayer;
+    ASSERT_NO_FATAL_FAILURE(
+            childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
+                                                           0 /* buffer height */,
+                                                           ISurfaceComposerClient::eFXSurfaceEffect,
+                                                           parent.get()));
+    Transaction()
+            .setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
+            .setColor(parent, half3{0.0f, 0.0f, 0.0f})
+            .show(childLayer)
+            .show(parent)
+            .setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight))
+            .setCrop_legacy(childLayer, Rect(0, 0, 20, 30))
+            .apply();
+
+    Transaction()
+            .setRelativeLayer(childLayer, parent->getHandle(), -1)
+            .setLayer(childLayer, 1)
+            .apply();
+
+    {
+        SCOPED_TRACE("setLayer above");
+        // Set layer should get applied and place the child above.
+        std::unique_ptr<ScreenCapture> screenshot;
+        ScreenCapture::captureScreen(&screenshot);
+        screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED);
+    }
+
+    Transaction()
+            .setLayer(childLayer, 1)
+            .setRelativeLayer(childLayer, parent->getHandle(), -1)
+            .apply();
+
+    {
+        SCOPED_TRACE("setRelative below");
+        // Set relative layer should get applied and place the child below.
+        std::unique_ptr<ScreenCapture> screenshot;
+        ScreenCapture::captureScreen(&screenshot);
+        screenshot->expectColor(Rect(0, 0, 20, 30), Color::BLACK);
+    }
+}
+
+TEST_P(LayerTypeTransactionTest, HideRelativeParentHidesLayer) {
+    sp<SurfaceControl> parent =
+            LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
+                                              ISurfaceComposerClient::eFXSurfaceEffect);
+    sp<SurfaceControl> relativeParent =
+            LayerTransactionTest::createLayer("RelativeParent", 0 /* buffer width */,
+                                              0 /* buffer height */,
+                                              ISurfaceComposerClient::eFXSurfaceEffect);
+
+    sp<SurfaceControl> childLayer;
+    ASSERT_NO_FATAL_FAILURE(
+            childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
+                                                           0 /* buffer height */,
+                                                           ISurfaceComposerClient::eFXSurfaceEffect,
+                                                           parent.get()));
+    Transaction()
+            .setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
+            .setColor(parent, half3{0.0f, 0.0f, 0.0f})
+            .setColor(relativeParent, half3{0.0f, 1.0f, 0.0f})
+            .show(childLayer)
+            .show(parent)
+            .show(relativeParent)
+            .setLayer(parent, mLayerZBase - 1)
+            .setLayer(relativeParent, mLayerZBase)
+            .apply();
+
+    Transaction().setRelativeLayer(childLayer, relativeParent->getHandle(), 1).apply();
+
+    {
+        SCOPED_TRACE("setLayer above");
+        // Set layer should get applied and place the child above.
+        std::unique_ptr<ScreenCapture> screenshot;
+        ScreenCapture::captureScreen(&screenshot);
+        screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED);
+    }
+
+    Transaction().hide(relativeParent).apply();
+
+    {
+        SCOPED_TRACE("hide relative parent");
+        // The relative should no longer be visible.
+        std::unique_ptr<ScreenCapture> screenshot;
+        ScreenCapture::captureScreen(&screenshot);
+        screenshot->expectColor(Rect(0, 0, 20, 30), Color::BLACK);
+    }
+}
+
+TEST_P(LayerTypeTransactionTest, SetFlagsSecure) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+
+    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+    sp<GraphicBuffer> outBuffer;
+    Transaction()
+            .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
+            .apply(true);
+    ASSERT_EQ(PERMISSION_DENIED,
+              composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+    Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true);
+    ASSERT_EQ(NO_ERROR, composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+}
+TEST_P(LayerTypeTransactionTest, RefreshRateIsInitialized) {
+    sp<SurfaceControl> layer;
+    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+
+    sp<IBinder> handle = layer->getHandle();
+    ASSERT_TRUE(handle != nullptr);
+
+    FrameStats frameStats;
+    mClient->getLayerFrameStats(handle, &frameStats);
+
+    ASSERT_GT(frameStats.refreshPeriodNano, static_cast<nsecs_t>(0));
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
new file mode 100644
index 0000000..cdd9d92
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -0,0 +1,1719 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+        ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class LayerUpdateTest : public LayerTransactionTest {
+protected:
+    virtual void SetUp() {
+        LayerTransactionTest::SetUp();
+        ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+        const auto display = SurfaceComposerClient::getInternalDisplayToken();
+        ASSERT_FALSE(display == nullptr);
+
+        DisplayConfig config;
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+        const ui::Size& resolution = config.resolution;
+
+        // Background surface
+        mBGSurfaceControl = createLayer(String8("BG Test Surface"), resolution.getWidth(),
+                                        resolution.getHeight(), 0);
+        ASSERT_TRUE(mBGSurfaceControl != nullptr);
+        ASSERT_TRUE(mBGSurfaceControl->isValid());
+        TransactionUtils::fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195);
+
+        // Foreground surface
+        mFGSurfaceControl = createLayer(String8("FG Test Surface"), 64, 64, 0);
+
+        ASSERT_TRUE(mFGSurfaceControl != nullptr);
+        ASSERT_TRUE(mFGSurfaceControl->isValid());
+
+        TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+
+        // Synchronization surface
+        mSyncSurfaceControl = createLayer(String8("Sync Test Surface"), 1, 1, 0);
+        ASSERT_TRUE(mSyncSurfaceControl != nullptr);
+        ASSERT_TRUE(mSyncSurfaceControl->isValid());
+
+        TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+
+        asTransaction([&](Transaction& t) {
+            t.setDisplayLayerStack(display, 0);
+
+            t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl);
+
+            t.setLayer(mFGSurfaceControl, INT32_MAX - 1)
+                    .setPosition(mFGSurfaceControl, 64, 64)
+                    .show(mFGSurfaceControl);
+
+            t.setLayer(mSyncSurfaceControl, INT32_MAX - 1)
+                    .setPosition(mSyncSurfaceControl, resolution.getWidth() - 2,
+                                 resolution.getHeight() - 2)
+                    .show(mSyncSurfaceControl);
+        });
+    }
+
+    virtual void TearDown() {
+        LayerTransactionTest::TearDown();
+        mBGSurfaceControl = 0;
+        mFGSurfaceControl = 0;
+        mSyncSurfaceControl = 0;
+    }
+
+    void waitForPostedBuffers() {
+        // Since the sync surface is in synchronous mode (i.e. double buffered)
+        // posting three buffers to it should ensure that at least two
+        // SurfaceFlinger::handlePageFlip calls have been made, which should
+        // guaranteed that a buffer posted to another Surface has been retired.
+        TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+        TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+        TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+    }
+
+    sp<SurfaceControl> mBGSurfaceControl;
+    sp<SurfaceControl> mFGSurfaceControl;
+
+    // This surface is used to ensure that the buffers posted to
+    // mFGSurfaceControl have been picked up by SurfaceFlinger.
+    sp<SurfaceControl> mSyncSurfaceControl;
+};
+
+TEST_F(LayerUpdateTest, RelativesAreNotDetached) {
+    std::unique_ptr<ScreenCapture> sc;
+
+    sp<SurfaceControl> relative = createLayer(String8("relativeTestSurface"), 10, 10, 0);
+    TransactionUtils::fillSurfaceRGBA8(relative, 10, 10, 10);
+    waitForPostedBuffers();
+
+    Transaction{}
+            .setRelativeLayer(relative, mFGSurfaceControl->getHandle(), 1)
+            .setPosition(relative, 64, 64)
+            .apply();
+
+    {
+        // The relative should be on top of the FG control.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(64, 64, 10, 10, 10);
+    }
+    Transaction{}.detachChildren(mFGSurfaceControl).apply();
+
+    {
+        // Nothing should change at this point.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(64, 64, 10, 10, 10);
+    }
+
+    Transaction{}.hide(relative).apply();
+
+    {
+        // Ensure that the relative was actually hidden, rather than
+        // being left in the detached but visible state.
+        ScreenCapture::captureScreen(&sc);
+        sc->expectFGColor(64, 64);
+    }
+}
+
+class GeometryLatchingTest : public LayerUpdateTest {
+protected:
+    void EXPECT_INITIAL_STATE(const char* trace) {
+        SCOPED_TRACE(trace);
+        ScreenCapture::captureScreen(&sc);
+        // We find the leading edge of the FG surface.
+        sc->expectFGColor(127, 127);
+        sc->expectBGColor(128, 128);
+    }
+
+    void lockAndFillFGBuffer() {
+        TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63, false);
+    }
+
+    void unlockFGBuffer() {
+        sp<Surface> s = mFGSurfaceControl->getSurface();
+        ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+        waitForPostedBuffers();
+    }
+
+    void completeFGResize() {
+        TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+        waitForPostedBuffers();
+    }
+    void restoreInitialState() {
+        asTransaction([&](Transaction& t) {
+            t.setSize(mFGSurfaceControl, 64, 64);
+            t.setPosition(mFGSurfaceControl, 64, 64);
+            t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
+        });
+
+        EXPECT_INITIAL_STATE("After restoring initial state");
+    }
+    std::unique_ptr<ScreenCapture> sc;
+};
+
+class CropLatchingTest : public GeometryLatchingTest {
+protected:
+    void EXPECT_CROPPED_STATE(const char* trace) {
+        SCOPED_TRACE(trace);
+        ScreenCapture::captureScreen(&sc);
+        // The edge should be moved back one pixel by our crop.
+        sc->expectFGColor(126, 126);
+        sc->expectBGColor(127, 127);
+        sc->expectBGColor(128, 128);
+    }
+
+    void EXPECT_RESIZE_STATE(const char* trace) {
+        SCOPED_TRACE(trace);
+        ScreenCapture::captureScreen(&sc);
+        // The FG is now resized too 128,128 at 64,64
+        sc->expectFGColor(64, 64);
+        sc->expectFGColor(191, 191);
+        sc->expectBGColor(192, 192);
+    }
+};
+
+TEST_F(LayerUpdateTest, DeferredTransactionTest) {
+    std::unique_ptr<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before anything");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectBGColor(32, 32);
+        sc->expectFGColor(96, 96);
+        sc->expectBGColor(160, 160);
+    }
+
+    // set up two deferred transactions on different frames
+    asTransaction([&](Transaction& t) {
+        t.setAlpha(mFGSurfaceControl, 0.75);
+        t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+                                       mSyncSurfaceControl->getSurface()->getNextFrameNumber());
+    });
+
+    asTransaction([&](Transaction& t) {
+        t.setPosition(mFGSurfaceControl, 128, 128);
+        t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+                                       mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+    });
+
+    {
+        SCOPED_TRACE("before any trigger");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectBGColor(32, 32);
+        sc->expectFGColor(96, 96);
+        sc->expectBGColor(160, 160);
+    }
+
+    // should trigger the first deferred transaction, but not the second one
+    TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+    {
+        SCOPED_TRACE("after first trigger");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectBGColor(32, 32);
+        sc->checkPixel(96, 96, 162, 63, 96);
+        sc->expectBGColor(160, 160);
+    }
+
+    // should show up immediately since it's not deferred
+    asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 1.0); });
+
+    // trigger the second deferred transaction
+    TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+    {
+        SCOPED_TRACE("after second trigger");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectBGColor(32, 32);
+        sc->expectBGColor(96, 96);
+        sc->expectFGColor(160, 160);
+    }
+}
+
+TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) {
+    std::unique_ptr<ScreenCapture> sc;
+
+    sp<SurfaceControl> childNoBuffer =
+            createSurface(mClient, "Bufferless child", 0 /* buffer width */, 0 /* buffer height */,
+                          PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    sp<SurfaceControl> childBuffer = createSurface(mClient, "Buffered child", 20, 20,
+                                                   PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get());
+    TransactionUtils::fillSurfaceRGBA8(childBuffer, 200, 200, 200);
+    SurfaceComposerClient::Transaction{}
+            .setCrop_legacy(childNoBuffer, Rect(0, 0, 10, 10))
+            .show(childNoBuffer)
+            .show(childBuffer)
+            .apply(true);
+    {
+        ScreenCapture::captureScreen(&sc);
+        sc->expectChildColor(73, 73);
+        sc->expectFGColor(74, 74);
+    }
+    SurfaceComposerClient::Transaction{}
+            .setCrop_legacy(childNoBuffer, Rect(0, 0, 20, 20))
+            .apply(true);
+    {
+        ScreenCapture::captureScreen(&sc);
+        sc->expectChildColor(73, 73);
+        sc->expectChildColor(74, 74);
+    }
+}
+
+TEST_F(LayerUpdateTest, MergingTransactions) {
+    std::unique_ptr<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before move");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectBGColor(0, 12);
+        sc->expectFGColor(75, 75);
+        sc->expectBGColor(145, 145);
+    }
+
+    Transaction t1, t2;
+    t1.setPosition(mFGSurfaceControl, 128, 128);
+    t2.setPosition(mFGSurfaceControl, 0, 0);
+    // We expect that the position update from t2 now
+    // overwrites the position update from t1.
+    t1.merge(std::move(t2));
+    t1.apply();
+
+    {
+        ScreenCapture::captureScreen(&sc);
+        sc->expectFGColor(1, 1);
+    }
+}
+
+TEST_F(LayerUpdateTest, MergingTransactionFlags) {
+    Transaction().hide(mFGSurfaceControl).apply();
+    std::unique_ptr<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before merge");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectBGColor(0, 12);
+        sc->expectBGColor(75, 75);
+        sc->expectBGColor(145, 145);
+    }
+
+    Transaction t1, t2;
+    t1.show(mFGSurfaceControl);
+    t2.setFlags(mFGSurfaceControl, 0 /* flags */, layer_state_t::eLayerSecure /* mask */);
+    t1.merge(std::move(t2));
+    t1.apply();
+
+    {
+        SCOPED_TRACE("after merge");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectFGColor(75, 75);
+    }
+}
+
+class ChildLayerTest : public LayerUpdateTest {
+protected:
+    void SetUp() override {
+        LayerUpdateTest::SetUp();
+        mChild = createSurface(mClient, "Child surface", 10, 15, PIXEL_FORMAT_RGBA_8888, 0,
+                               mFGSurfaceControl.get());
+        TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+        {
+            SCOPED_TRACE("before anything");
+            mCapture = screenshot();
+            mCapture->expectChildColor(64, 64);
+        }
+    }
+    void TearDown() override {
+        LayerUpdateTest::TearDown();
+        mChild = 0;
+    }
+
+    sp<SurfaceControl> mChild;
+    std::unique_ptr<ScreenCapture> mCapture;
+};
+
+TEST_F(ChildLayerTest, ChildLayerPositioning) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        mCapture = screenshot();
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // But 10 pixels in we should see the child surface
+        mCapture->expectChildColor(74, 74);
+        // And 10 more pixels we should be back to the foreground surface
+        mCapture->expectFGColor(84, 84);
+    }
+
+    asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); });
+
+    {
+        mCapture = screenshot();
+        // Top left of foreground should now be at 0, 0
+        mCapture->expectFGColor(0, 0);
+        // But 10 pixels in we should see the child surface
+        mCapture->expectChildColor(10, 10);
+        // And 10 more pixels we should be back to the foreground surface
+        mCapture->expectFGColor(20, 20);
+    }
+}
+
+TEST_F(ChildLayerTest, ChildLayerCropping) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+        t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
+    });
+
+    {
+        mCapture = screenshot();
+        mCapture->expectChildColor(0, 0);
+        mCapture->expectChildColor(4, 4);
+        mCapture->expectBGColor(5, 5);
+    }
+}
+
+TEST_F(ChildLayerTest, ChildLayerConstraints) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+        t.setPosition(mChild, 63, 63);
+    });
+
+    {
+        mCapture = screenshot();
+        mCapture->expectFGColor(0, 0);
+        // Last pixel in foreground should now be the child.
+        mCapture->expectChildColor(63, 63);
+        // But the child should be constrained and the next pixel
+        // must be the background
+        mCapture->expectBGColor(64, 64);
+    }
+}
+
+TEST_F(ChildLayerTest, ChildLayerScaling) {
+    asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); });
+
+    // Find the boundary between the parent and child
+    {
+        mCapture = screenshot();
+        mCapture->expectChildColor(9, 9);
+        mCapture->expectFGColor(10, 10);
+    }
+
+    asTransaction([&](Transaction& t) { t.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0); });
+
+    // The boundary should be twice as far from the origin now.
+    // The pixels from the last test should all be child now
+    {
+        mCapture = screenshot();
+        mCapture->expectChildColor(9, 9);
+        mCapture->expectChildColor(10, 10);
+        mCapture->expectChildColor(19, 19);
+        mCapture->expectFGColor(20, 20);
+    }
+}
+
+// A child with a scale transform should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildLayerScalingCroppedByParent) {
+    asTransaction([&](Transaction& t) {
+        t.setPosition(mFGSurfaceControl, 0, 0);
+        t.setPosition(mChild, 0, 0);
+    });
+
+    // Find the boundary between the parent and child.
+    {
+        mCapture = screenshot();
+        mCapture->expectChildColor(0, 0);
+        mCapture->expectChildColor(9, 9);
+        mCapture->expectFGColor(10, 10);
+    }
+
+    asTransaction([&](Transaction& t) { t.setMatrix(mChild, 10.0, 0, 0, 10.0); });
+
+    // The child should fill its parent bounds and be cropped by it.
+    {
+        mCapture = screenshot();
+        mCapture->expectChildColor(0, 0);
+        mCapture->expectChildColor(63, 63);
+        mCapture->expectBGColor(64, 64);
+    }
+}
+
+TEST_F(ChildLayerTest, ChildLayerAlpha) {
+    TransactionUtils::fillSurfaceRGBA8(mBGSurfaceControl, 0, 0, 254);
+    TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 254, 0, 0);
+    TransactionUtils::fillSurfaceRGBA8(mChild, 0, 254, 0);
+    waitForPostedBuffers();
+
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+    });
+
+    {
+        mCapture = screenshot();
+        // Unblended child color
+        mCapture->checkPixel(0, 0, 0, 254, 0);
+    }
+
+    asTransaction([&](Transaction& t) { t.setAlpha(mChild, 0.5); });
+
+    {
+        mCapture = screenshot();
+        // Child and BG blended.
+        mCapture->checkPixel(0, 0, 127, 127, 0);
+    }
+
+    asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 0.5); });
+
+    {
+        mCapture = screenshot();
+        // Child and BG blended.
+        mCapture->checkPixel(0, 0, 95, 64, 95);
+    }
+}
+
+TEST_F(ChildLayerTest, ReparentChildren) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        mCapture = screenshot();
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // But 10 pixels in we should see the child surface
+        mCapture->expectChildColor(74, 74);
+        // And 10 more pixels we should be back to the foreground surface
+        mCapture->expectFGColor(84, 84);
+    }
+
+    asTransaction([&](Transaction& t) {
+        t.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
+    });
+
+    {
+        mCapture = screenshot();
+        mCapture->expectFGColor(64, 64);
+        // In reparenting we should have exposed the entire foreground surface.
+        mCapture->expectFGColor(74, 74);
+        // And the child layer should now begin at 10, 10 (since the BG
+        // layer is at (0, 0)).
+        mCapture->expectBGColor(9, 9);
+        mCapture->expectChildColor(10, 10);
+    }
+}
+
+TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) {
+    sp<SurfaceControl> mGrandChild =
+            createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+    TransactionUtils::fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
+
+    {
+        SCOPED_TRACE("Grandchild visible");
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->checkPixel(64, 64, 111, 111, 111);
+    }
+
+    Transaction().reparent(mChild, nullptr).apply();
+    mChild.clear();
+
+    {
+        SCOPED_TRACE("After destroying child");
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->expectFGColor(64, 64);
+    }
+
+    asTransaction([&](Transaction& t) { t.reparent(mGrandChild, mFGSurfaceControl->getHandle()); });
+
+    {
+        SCOPED_TRACE("After reparenting grandchild");
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->checkPixel(64, 64, 111, 111, 111);
+    }
+}
+
+TEST_F(ChildLayerTest, ChildrenRelativeZSurvivesParentDestruction) {
+    sp<SurfaceControl> mGrandChild =
+            createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+    TransactionUtils::fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
+
+    // draw grand child behind the foreground surface
+    asTransaction([&](Transaction& t) {
+        t.setRelativeLayer(mGrandChild, mFGSurfaceControl->getHandle(), -1);
+    });
+
+    {
+        SCOPED_TRACE("Child visible");
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->checkPixel(64, 64, 200, 200, 200);
+    }
+
+    asTransaction([&](Transaction& t) {
+        t.reparent(mChild, nullptr);
+        t.reparentChildren(mChild, mFGSurfaceControl->getHandle());
+    });
+
+    {
+        SCOPED_TRACE("foreground visible reparenting grandchild");
+        ScreenCapture::captureScreen(&mCapture);
+        mCapture->checkPixel(64, 64, 195, 63, 63);
+    }
+}
+
+TEST_F(ChildLayerTest, DetachChildrenSameClient) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        mCapture = screenshot();
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // But 10 pixels in we should see the child surface
+        mCapture->expectChildColor(74, 74);
+        // And 10 more pixels we should be back to the foreground surface
+        mCapture->expectFGColor(84, 84);
+    }
+
+    asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
+
+    asTransaction([&](Transaction& t) { t.hide(mChild); });
+
+    // Since the child has the same client as the parent, it will not get
+    // detached and will be hidden.
+    {
+        mCapture = screenshot();
+        mCapture->expectFGColor(64, 64);
+        mCapture->expectFGColor(74, 74);
+        mCapture->expectFGColor(84, 84);
+    }
+}
+
+TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
+    sp<SurfaceComposerClient> mNewComposerClient = new SurfaceComposerClient;
+    sp<SurfaceControl> mChildNewClient =
+            createSurface(mNewComposerClient, "New Child Test Surface", 10, 10,
+                          PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+    ASSERT_TRUE(mChildNewClient->isValid());
+
+    TransactionUtils::fillSurfaceRGBA8(mChildNewClient, 200, 200, 200);
+
+    asTransaction([&](Transaction& t) {
+        t.hide(mChild);
+        t.show(mChildNewClient);
+        t.setPosition(mChildNewClient, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        mCapture = screenshot();
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // But 10 pixels in we should see the child surface
+        mCapture->expectChildColor(74, 74);
+        // And 10 more pixels we should be back to the foreground surface
+        mCapture->expectFGColor(84, 84);
+    }
+
+    asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
+
+    asTransaction([&](Transaction& t) { t.hide(mChildNewClient); });
+
+    // Nothing should have changed.
+    {
+        mCapture = screenshot();
+        mCapture->expectFGColor(64, 64);
+        mCapture->expectChildColor(74, 74);
+        mCapture->expectFGColor(84, 84);
+    }
+}
+
+TEST_F(ChildLayerTest, DetachChildrenThenAttach) {
+    sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+    sp<SurfaceControl> childNewClient =
+            newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+    ASSERT_TRUE(childNewClient != nullptr);
+    ASSERT_TRUE(childNewClient->isValid());
+
+    TransactionUtils::fillSurfaceRGBA8(childNewClient, 200, 200, 200);
+
+    Transaction()
+            .hide(mChild)
+            .show(childNewClient)
+            .setPosition(childNewClient, 10, 10)
+            .setPosition(mFGSurfaceControl, 64, 64)
+            .apply();
+
+    {
+        mCapture = screenshot();
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // But 10 pixels in we should see the child surface
+        mCapture->expectChildColor(74, 74);
+        // And 10 more pixels we should be back to the foreground surface
+        mCapture->expectFGColor(84, 84);
+    }
+
+    Transaction().detachChildren(mFGSurfaceControl).apply();
+    Transaction().hide(childNewClient).apply();
+
+    // Nothing should have changed.
+    {
+        mCapture = screenshot();
+        mCapture->expectFGColor(64, 64);
+        mCapture->expectChildColor(74, 74);
+        mCapture->expectFGColor(84, 84);
+    }
+
+    sp<SurfaceControl> newParentSurface = createLayer(String8("New Parent Surface"), 32, 32, 0);
+    fillLayerColor(ISurfaceComposerClient::eFXSurfaceBufferQueue, newParentSurface, Color::RED, 32,
+                   32);
+    Transaction()
+            .setLayer(newParentSurface, INT32_MAX - 1)
+            .show(newParentSurface)
+            .setPosition(newParentSurface, 20, 20)
+            .reparent(childNewClient, newParentSurface->getHandle())
+            .apply();
+    {
+        mCapture = screenshot();
+        // Child is now hidden.
+        mCapture->expectColor(Rect(20, 20, 52, 52), Color::RED);
+    }
+}
+TEST_F(ChildLayerTest, DetachChildrenWithDeferredTransaction) {
+    sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+    sp<SurfaceControl> childNewClient =
+            newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+    ASSERT_TRUE(childNewClient != nullptr);
+    ASSERT_TRUE(childNewClient->isValid());
+
+    TransactionUtils::fillSurfaceRGBA8(childNewClient, 200, 200, 200);
+
+    Transaction()
+            .hide(mChild)
+            .show(childNewClient)
+            .setPosition(childNewClient, 10, 10)
+            .setPosition(mFGSurfaceControl, 64, 64)
+            .apply();
+
+    {
+        mCapture = screenshot();
+        Rect rect = Rect(74, 74, 84, 84);
+        mCapture->expectBorder(rect, Color{195, 63, 63, 255});
+        mCapture->expectColor(rect, Color{200, 200, 200, 255});
+    }
+
+    Transaction()
+            .deferTransactionUntil_legacy(childNewClient, mFGSurfaceControl->getHandle(),
+                                          mFGSurfaceControl->getSurface()->getNextFrameNumber())
+            .apply();
+    Transaction().detachChildren(mFGSurfaceControl).apply();
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(mFGSurfaceControl, Color::RED, 32, 32));
+
+    // BufferLayer can still dequeue buffers even though there's a detached layer with a
+    // deferred transaction.
+    {
+        SCOPED_TRACE("new buffer");
+        mCapture = screenshot();
+        Rect rect = Rect(74, 74, 84, 84);
+        mCapture->expectBorder(rect, Color::RED);
+        mCapture->expectColor(rect, Color{200, 200, 200, 255});
+    }
+}
+
+TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+    });
+
+    {
+        mCapture = screenshot();
+        // We've positioned the child in the top left.
+        mCapture->expectChildColor(0, 0);
+        // But it's only 10x15.
+        mCapture->expectFGColor(10, 15);
+    }
+
+    asTransaction([&](Transaction& t) {
+        t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        // We cause scaling by 2.
+        t.setSize(mFGSurfaceControl, 128, 128);
+    });
+
+    {
+        mCapture = screenshot();
+        // We've positioned the child in the top left.
+        mCapture->expectChildColor(0, 0);
+        mCapture->expectChildColor(10, 10);
+        mCapture->expectChildColor(19, 29);
+        // And now it should be scaled all the way to 20x30
+        mCapture->expectFGColor(20, 30);
+    }
+}
+
+// Regression test for b/37673612
+TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+    });
+
+    {
+        mCapture = screenshot();
+        // We've positioned the child in the top left.
+        mCapture->expectChildColor(0, 0);
+        mCapture->expectChildColor(9, 14);
+        // But it's only 10x15.
+        mCapture->expectFGColor(10, 15);
+    }
+    // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
+    // the WM specified state size.
+    asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
+    sp<Surface> s = mFGSurfaceControl->getSurface();
+    auto anw = static_cast<ANativeWindow*>(s.get());
+    native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+    native_window_set_buffers_dimensions(anw, 64, 128);
+    TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+    waitForPostedBuffers();
+
+    {
+        // The child should still be in the same place and not have any strange scaling as in
+        // b/37673612.
+        mCapture = screenshot();
+        mCapture->expectChildColor(0, 0);
+        mCapture->expectFGColor(10, 10);
+    }
+}
+
+// A child with a buffer transform from its parents should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferTransform) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+        t.setSize(mChild, 100, 100);
+    });
+    TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+    {
+        mCapture = screenshot();
+
+        mCapture->expectChildColor(0, 0);
+        mCapture->expectChildColor(63, 63);
+        mCapture->expectBGColor(64, 64);
+    }
+
+    asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
+    sp<Surface> s = mFGSurfaceControl->getSurface();
+    auto anw = static_cast<ANativeWindow*>(s.get());
+    // Apply a 90 transform on the buffer.
+    native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+    native_window_set_buffers_dimensions(anw, 64, 128);
+    TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+    waitForPostedBuffers();
+
+    // The child should be cropped by the new parent bounds.
+    {
+        mCapture = screenshot();
+        mCapture->expectChildColor(0, 0);
+        mCapture->expectChildColor(99, 63);
+        mCapture->expectFGColor(100, 63);
+        mCapture->expectBGColor(128, 64);
+    }
+}
+
+// A child with a scale transform from its parents should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferScale) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+        t.setSize(mChild, 200, 200);
+    });
+    TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+    {
+        mCapture = screenshot();
+
+        mCapture->expectChildColor(0, 0);
+        mCapture->expectChildColor(63, 63);
+        mCapture->expectBGColor(64, 64);
+    }
+
+    asTransaction([&](Transaction& t) {
+        t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        // Set a scaling by 2.
+        t.setSize(mFGSurfaceControl, 128, 128);
+    });
+
+    // Child should inherit its parents scale but should be cropped by its parent bounds.
+    {
+        mCapture = screenshot();
+        mCapture->expectChildColor(0, 0);
+        mCapture->expectChildColor(127, 127);
+        mCapture->expectBGColor(128, 128);
+    }
+}
+
+// Regression test for b/127368943
+// Child should ignore the buffer transform but apply parent scale transform.
+TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 0, 0);
+        t.setPosition(mFGSurfaceControl, 0, 0);
+    });
+
+    {
+        mCapture = screenshot();
+        mCapture->expectChildColor(0, 0);
+        mCapture->expectChildColor(9, 14);
+        mCapture->expectFGColor(10, 15);
+    }
+
+    // Change the size of the foreground to 128 * 64 so we can test rotation as well.
+    asTransaction([&](Transaction& t) {
+        t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        t.setSize(mFGSurfaceControl, 128, 64);
+    });
+    sp<Surface> s = mFGSurfaceControl->getSurface();
+    auto anw = static_cast<ANativeWindow*>(s.get());
+    // Apply a 90 transform on the buffer and submit a buffer half the expected size so that we
+    // have an effective scale of 2.0 applied to the buffer along with a rotation transform.
+    native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+    native_window_set_buffers_dimensions(anw, 32, 64);
+    TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+    waitForPostedBuffers();
+
+    // The child should ignore the buffer transform but apply the 2.0 scale from parent.
+    {
+        mCapture = screenshot();
+        mCapture->expectChildColor(0, 0);
+        mCapture->expectChildColor(19, 29);
+        mCapture->expectFGColor(20, 30);
+    }
+}
+
+TEST_F(ChildLayerTest, Bug36858924) {
+    // Destroy the child layer
+    mChild.clear();
+
+    // Now recreate it as hidden
+    mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888,
+                           ISurfaceComposerClient::eHidden, mFGSurfaceControl.get());
+
+    // Show the child layer in a deferred transaction
+    asTransaction([&](Transaction& t) {
+        t.deferTransactionUntil_legacy(mChild, mFGSurfaceControl->getHandle(),
+                                       mFGSurfaceControl->getSurface()->getNextFrameNumber());
+        t.show(mChild);
+    });
+
+    // Render the foreground surface a few times
+    //
+    // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third
+    // frame because SurfaceFlinger would never process the deferred transaction and would therefore
+    // never acquire/release the first buffer
+    ALOGI("Filling 1");
+    TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
+    ALOGI("Filling 2");
+    TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 0, 255);
+    ALOGI("Filling 3");
+    TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 255, 0, 0);
+    ALOGI("Filling 4");
+    TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
+}
+
+TEST_F(ChildLayerTest, Reparent) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        mCapture = screenshot();
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // But 10 pixels in we should see the child surface
+        mCapture->expectChildColor(74, 74);
+        // And 10 more pixels we should be back to the foreground surface
+        mCapture->expectFGColor(84, 84);
+    }
+
+    asTransaction([&](Transaction& t) { t.reparent(mChild, mBGSurfaceControl->getHandle()); });
+
+    {
+        mCapture = screenshot();
+        mCapture->expectFGColor(64, 64);
+        // In reparenting we should have exposed the entire foreground surface.
+        mCapture->expectFGColor(74, 74);
+        // And the child layer should now begin at 10, 10 (since the BG
+        // layer is at (0, 0)).
+        mCapture->expectBGColor(9, 9);
+        mCapture->expectChildColor(10, 10);
+    }
+}
+
+TEST_F(ChildLayerTest, ReparentToNoParent) {
+    asTransaction([&](Transaction& t) {
+        t.show(mChild);
+        t.setPosition(mChild, 10, 10);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        mCapture = screenshot();
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // But 10 pixels in we should see the child surface
+        mCapture->expectChildColor(74, 74);
+        // And 10 more pixels we should be back to the foreground surface
+        mCapture->expectFGColor(84, 84);
+    }
+    asTransaction([&](Transaction& t) { t.reparent(mChild, nullptr); });
+    {
+        mCapture = screenshot();
+        // The surface should now be offscreen.
+        mCapture->expectFGColor(64, 64);
+        mCapture->expectFGColor(74, 74);
+        mCapture->expectFGColor(84, 84);
+    }
+}
+
+TEST_F(ChildLayerTest, ReparentFromNoParent) {
+    sp<SurfaceControl> newSurface = createLayer(String8("New Surface"), 10, 10, 0);
+    ASSERT_TRUE(newSurface != nullptr);
+    ASSERT_TRUE(newSurface->isValid());
+
+    TransactionUtils::fillSurfaceRGBA8(newSurface, 63, 195, 63);
+    asTransaction([&](Transaction& t) {
+        t.hide(mChild);
+        t.show(newSurface);
+        t.setPosition(newSurface, 10, 10);
+        t.setLayer(newSurface, INT32_MAX - 2);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+    });
+
+    {
+        mCapture = screenshot();
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // At 10, 10 we should see the new surface
+        mCapture->checkPixel(10, 10, 63, 195, 63);
+    }
+
+    asTransaction([&](Transaction& t) { t.reparent(newSurface, mFGSurfaceControl->getHandle()); });
+
+    {
+        mCapture = screenshot();
+        // newSurface will now be a child of mFGSurface so it will be 10, 10 offset from
+        // mFGSurface, putting it at 74, 74.
+        mCapture->expectFGColor(64, 64);
+        mCapture->checkPixel(74, 74, 63, 195, 63);
+        mCapture->expectFGColor(84, 84);
+    }
+}
+
+TEST_F(ChildLayerTest, NestedChildren) {
+    sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 10, 10,
+                                                  PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+    TransactionUtils::fillSurfaceRGBA8(grandchild, 50, 50, 50);
+
+    {
+        mCapture = screenshot();
+        // Expect the grandchild to begin at 64, 64 because it's a child of mChild layer
+        // which begins at 64, 64
+        mCapture->checkPixel(64, 64, 50, 50, 50);
+    }
+}
+
+TEST_F(ChildLayerTest, ChildLayerRelativeLayer) {
+    sp<SurfaceControl> relative = createLayer(String8("Relative surface"), 128, 128, 0);
+    TransactionUtils::fillSurfaceRGBA8(relative, 255, 255, 255);
+
+    Transaction t;
+    t.setLayer(relative, INT32_MAX)
+            .setRelativeLayer(mChild, relative->getHandle(), 1)
+            .setPosition(mFGSurfaceControl, 0, 0)
+            .apply(true);
+
+    // We expect that the child should have been elevated above our
+    // INT_MAX layer even though it's not a child of it.
+    {
+        mCapture = screenshot();
+        mCapture->expectChildColor(0, 0);
+        mCapture->expectChildColor(9, 9);
+        mCapture->checkPixel(10, 10, 255, 255, 255);
+    }
+}
+
+class BoundlessLayerTest : public LayerUpdateTest {
+protected:
+    std::unique_ptr<ScreenCapture> mCapture;
+};
+
+// Verify setting a size on a buffer layer has no effect.
+TEST_F(BoundlessLayerTest, BufferLayerIgnoresSize) {
+    sp<SurfaceControl> bufferLayer =
+            createSurface(mClient, "BufferLayer", 45, 45, PIXEL_FORMAT_RGBA_8888, 0,
+                          mFGSurfaceControl.get());
+    ASSERT_TRUE(bufferLayer->isValid());
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::BLACK, 30, 30));
+    asTransaction([&](Transaction& t) { t.show(bufferLayer); });
+    {
+        mCapture = screenshot();
+        // Top left of background must now be visible
+        mCapture->expectBGColor(0, 0);
+        // Foreground Surface bounds must be color layer
+        mCapture->expectColor(Rect(64, 64, 94, 94), Color::BLACK);
+        // Buffer layer should not extend past buffer bounds
+        mCapture->expectFGColor(95, 95);
+    }
+}
+
+// Verify a boundless color layer will fill its parent bounds. The parent has a buffer size
+// which will crop the color layer.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) {
+    sp<SurfaceControl> colorLayer =
+            createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+                          ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get());
+    ASSERT_TRUE(colorLayer->isValid());
+    asTransaction([&](Transaction& t) {
+        t.setColor(colorLayer, half3{0, 0, 0});
+        t.show(colorLayer);
+    });
+    {
+        mCapture = screenshot();
+        // Top left of background must now be visible
+        mCapture->expectBGColor(0, 0);
+        // Foreground Surface bounds must be color layer
+        mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+        // Color layer should not extend past foreground bounds
+        mCapture->expectBGColor(129, 129);
+    }
+}
+
+// Verify a boundless color layer will fill its parent bounds. The parent has no buffer but has
+// a crop which will be used to crop the color layer.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) {
+    sp<SurfaceControl> cropLayer = createSurface(mClient, "CropLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+                                                 0 /* flags */, mFGSurfaceControl.get());
+    ASSERT_TRUE(cropLayer->isValid());
+    sp<SurfaceControl> colorLayer =
+            createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+                          ISurfaceComposerClient::eFXSurfaceEffect, cropLayer.get());
+    ASSERT_TRUE(colorLayer->isValid());
+    asTransaction([&](Transaction& t) {
+        t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10));
+        t.setColor(colorLayer, half3{0, 0, 0});
+        t.show(cropLayer);
+        t.show(colorLayer);
+    });
+    {
+        mCapture = screenshot();
+        // Top left of background must now be visible
+        mCapture->expectBGColor(0, 0);
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // 5 pixels from the foreground we should see the child surface
+        mCapture->expectColor(Rect(69, 69, 74, 74), Color::BLACK);
+        // 10 pixels from the foreground we should be back to the foreground surface
+        mCapture->expectFGColor(74, 74);
+    }
+}
+
+// Verify for boundless layer with no children, their transforms have no effect.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) {
+    sp<SurfaceControl> colorLayer =
+            createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+                          ISurfaceComposerClient::eFXSurfaceEffect, mFGSurfaceControl.get());
+    ASSERT_TRUE(colorLayer->isValid());
+    asTransaction([&](Transaction& t) {
+        t.setPosition(colorLayer, 320, 320);
+        t.setMatrix(colorLayer, 2, 0, 0, 2);
+        t.setColor(colorLayer, half3{0, 0, 0});
+        t.show(colorLayer);
+    });
+    {
+        mCapture = screenshot();
+        // Top left of background must now be visible
+        mCapture->expectBGColor(0, 0);
+        // Foreground Surface bounds must be color layer
+        mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+        // Color layer should not extend past foreground bounds
+        mCapture->expectBGColor(129, 129);
+    }
+}
+
+// Verify for boundless layer with children, their transforms have an effect.
+TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerCanSetTransform) {
+    sp<SurfaceControl> boundlessLayerRightShift =
+            createSurface(mClient, "BoundlessLayerRightShift", 0, 0, PIXEL_FORMAT_RGBA_8888,
+                          0 /* flags */, mFGSurfaceControl.get());
+    ASSERT_TRUE(boundlessLayerRightShift->isValid());
+    sp<SurfaceControl> boundlessLayerDownShift =
+            createSurface(mClient, "BoundlessLayerLeftShift", 0, 0, PIXEL_FORMAT_RGBA_8888,
+                          0 /* flags */, boundlessLayerRightShift.get());
+    ASSERT_TRUE(boundlessLayerDownShift->isValid());
+    sp<SurfaceControl> colorLayer =
+            createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+                          ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayerDownShift.get());
+    ASSERT_TRUE(colorLayer->isValid());
+    asTransaction([&](Transaction& t) {
+        t.setPosition(boundlessLayerRightShift, 32, 0);
+        t.show(boundlessLayerRightShift);
+        t.setPosition(boundlessLayerDownShift, 0, 32);
+        t.show(boundlessLayerDownShift);
+        t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+        t.setColor(colorLayer, half3{0, 0, 0});
+        t.show(colorLayer);
+    });
+    {
+        mCapture = screenshot();
+        // Top left of background must now be visible
+        mCapture->expectBGColor(0, 0);
+        // Top left of foreground must now be visible
+        mCapture->expectFGColor(64, 64);
+        // Foreground Surface bounds must be color layer
+        mCapture->expectColor(Rect(96, 96, 128, 128), Color::BLACK);
+        // Color layer should not extend past foreground bounds
+        mCapture->expectBGColor(129, 129);
+    }
+}
+
+// Verify child layers do not get clipped if they temporarily move into the negative
+// coordinate space as the result of an intermediate transformation.
+TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) {
+    sp<SurfaceControl> boundlessLayer =
+            mClient->createSurface(String8("BoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+                                   0 /* flags */, mFGSurfaceControl.get());
+    ASSERT_TRUE(boundlessLayer != nullptr);
+    ASSERT_TRUE(boundlessLayer->isValid());
+    sp<SurfaceControl> colorLayer =
+            mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+                                   ISurfaceComposerClient::eFXSurfaceEffect, boundlessLayer.get());
+    ASSERT_TRUE(colorLayer != nullptr);
+    ASSERT_TRUE(colorLayer->isValid());
+    asTransaction([&](Transaction& t) {
+        // shift child layer off bounds. If this layer was not boundless, we will
+        // expect the child layer to be cropped.
+        t.setPosition(boundlessLayer, 32, 32);
+        t.show(boundlessLayer);
+        t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+        // undo shift by parent
+        t.setPosition(colorLayer, -32, -32);
+        t.setColor(colorLayer, half3{0, 0, 0});
+        t.show(colorLayer);
+    });
+    {
+        mCapture = screenshot();
+        // Top left of background must now be visible
+        mCapture->expectBGColor(0, 0);
+        // Foreground Surface bounds must be color layer
+        mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+        // Color layer should not extend past foreground bounds
+        mCapture->expectBGColor(129, 129);
+    }
+}
+
+// Verify for boundless root layers with children, their transforms have an effect.
+TEST_F(BoundlessLayerTest, RootBoundlessLayerCanSetTransform) {
+    sp<SurfaceControl> rootBoundlessLayer = createSurface(mClient, "RootBoundlessLayer", 0, 0,
+                                                          PIXEL_FORMAT_RGBA_8888, 0 /* flags */);
+    ASSERT_TRUE(rootBoundlessLayer->isValid());
+    sp<SurfaceControl> colorLayer =
+            createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+                          ISurfaceComposerClient::eFXSurfaceEffect, rootBoundlessLayer.get());
+
+    ASSERT_TRUE(colorLayer->isValid());
+    asTransaction([&](Transaction& t) {
+        t.setLayer(rootBoundlessLayer, INT32_MAX - 1);
+        t.setPosition(rootBoundlessLayer, 32, 32);
+        t.show(rootBoundlessLayer);
+        t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+        t.setColor(colorLayer, half3{0, 0, 0});
+        t.show(colorLayer);
+        t.hide(mFGSurfaceControl);
+    });
+    {
+        mCapture = screenshot();
+        // Top left of background must now be visible
+        mCapture->expectBGColor(0, 0);
+        // Top left of foreground must now be visible
+        mCapture->expectBGColor(31, 31);
+        // Foreground Surface bounds must be color layer
+        mCapture->expectColor(Rect(32, 32, 96, 96), Color::BLACK);
+        // Color layer should not extend past foreground bounds
+        mCapture->expectBGColor(97, 97);
+    }
+}
+
+class ScreenCaptureTest : public LayerUpdateTest {
+protected:
+    std::unique_ptr<ScreenCapture> mCapture;
+};
+
+TEST_F(ScreenCaptureTest, CaptureSingleLayer) {
+    auto bgHandle = mBGSurfaceControl->getHandle();
+    ScreenCapture::captureLayers(&mCapture, bgHandle);
+    mCapture->expectBGColor(0, 0);
+    // Doesn't capture FG layer which is at 64, 64
+    mCapture->expectBGColor(64, 64);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerWithChild) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+
+    SurfaceComposerClient::Transaction().show(child).apply(true);
+
+    // Captures mFGSurfaceControl layer and its child.
+    ScreenCapture::captureLayers(&mCapture, fgHandle);
+    mCapture->expectFGColor(10, 10);
+    mCapture->expectChildColor(0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerChildOnly) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+
+    SurfaceComposerClient::Transaction().show(child).apply(true);
+
+    // Captures mFGSurfaceControl's child
+    ScreenCapture::captureChildLayers(&mCapture, fgHandle);
+    mCapture->checkPixel(10, 10, 0, 0, 0);
+    mCapture->expectChildColor(0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerExclude) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+    sp<SurfaceControl> child2 = createSurface(mClient, "Child surface", 10, 10,
+                                              PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    TransactionUtils::fillSurfaceRGBA8(child2, 200, 0, 200);
+
+    SurfaceComposerClient::Transaction()
+            .show(child)
+            .show(child2)
+            .setLayer(child, 1)
+            .setLayer(child2, 2)
+            .apply(true);
+
+    // Child2 would be visible but its excluded, so we should see child1 color instead.
+    ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
+    mCapture->checkPixel(10, 10, 0, 0, 0);
+    mCapture->checkPixel(0, 0, 200, 200, 200);
+}
+
+// Like the last test but verifies that children are also exclude.
+TEST_F(ScreenCaptureTest, CaptureLayerExcludeTree) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+    sp<SurfaceControl> child2 = createSurface(mClient, "Child surface", 10, 10,
+                                              PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    TransactionUtils::fillSurfaceRGBA8(child2, 200, 0, 200);
+    sp<SurfaceControl> child3 = createSurface(mClient, "Child surface", 10, 10,
+                                              PIXEL_FORMAT_RGBA_8888, 0, child2.get());
+    TransactionUtils::fillSurfaceRGBA8(child2, 200, 0, 200);
+
+    SurfaceComposerClient::Transaction()
+            .show(child)
+            .show(child2)
+            .show(child3)
+            .setLayer(child, 1)
+            .setLayer(child2, 2)
+            .apply(true);
+
+    // Child2 would be visible but its excluded, so we should see child1 color instead.
+    ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
+    mCapture->checkPixel(10, 10, 0, 0, 0);
+    mCapture->checkPixel(0, 0, 200, 200, 200);
+}
+
+TEST_F(ScreenCaptureTest, CaptureTransparent) {
+    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+    TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+
+    SurfaceComposerClient::Transaction().show(child).apply(true);
+
+    auto childHandle = child->getHandle();
+
+    // Captures child
+    ScreenCapture::captureLayers(&mCapture, childHandle, {0, 0, 10, 20});
+    mCapture->expectColor(Rect(0, 0, 9, 9), {200, 200, 200, 255});
+    // Area outside of child's bounds is transparent.
+    mCapture->expectColor(Rect(0, 10, 9, 19), {0, 0, 0, 0});
+}
+
+TEST_F(ScreenCaptureTest, DontCaptureRelativeOutsideTree) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    ASSERT_NE(nullptr, child.get()) << "failed to create surface";
+    sp<SurfaceControl> relative = createLayer(String8("Relative surface"), 10, 10, 0);
+    TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+    TransactionUtils::fillSurfaceRGBA8(relative, 100, 100, 100);
+
+    SurfaceComposerClient::Transaction()
+            .show(child)
+            // Set relative layer above fg layer so should be shown above when computing all layers.
+            .setRelativeLayer(relative, fgHandle, 1)
+            .show(relative)
+            .apply(true);
+
+    // Captures mFGSurfaceControl layer and its child. Relative layer shouldn't be captured.
+    ScreenCapture::captureLayers(&mCapture, fgHandle);
+    mCapture->expectFGColor(10, 10);
+    mCapture->expectChildColor(0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureRelativeInTree) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    sp<SurfaceControl> relative = createSurface(mClient, "Relative surface", 10, 10,
+                                                PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+    TransactionUtils::fillSurfaceRGBA8(relative, 100, 100, 100);
+
+    SurfaceComposerClient::Transaction()
+            .show(child)
+            // Set relative layer below fg layer but relative to child layer so it should be shown
+            // above child layer.
+            .setLayer(relative, -1)
+            .setRelativeLayer(relative, child->getHandle(), 1)
+            .show(relative)
+            .apply(true);
+
+    // Captures mFGSurfaceControl layer and its children. Relative layer is a child of fg so its
+    // relative value should be taken into account, placing it above child layer.
+    ScreenCapture::captureLayers(&mCapture, fgHandle);
+    mCapture->expectFGColor(10, 10);
+    // Relative layer is showing on top of child layer
+    mCapture->expectColor(Rect(0, 0, 9, 9), {100, 100, 100, 255});
+}
+
+TEST_F(ScreenCaptureTest, CaptureBoundlessLayerWithSourceCrop) {
+    sp<SurfaceControl> child = createColorLayer("Child layer", Color::RED, mFGSurfaceControl.get());
+    SurfaceComposerClient::Transaction().show(child).apply(true);
+
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    sp<GraphicBuffer> outBuffer;
+    Rect sourceCrop(0, 0, 10, 10);
+    ASSERT_EQ(NO_ERROR, sf->captureLayers(child->getHandle(), &outBuffer, sourceCrop));
+    ScreenCapture sc(outBuffer);
+
+    sc.expectColor(Rect(0, 0, 9, 9), Color::RED);
+}
+
+TEST_F(ScreenCaptureTest, CaptureBoundedLayerWithoutSourceCrop) {
+    sp<SurfaceControl> child = createColorLayer("Child layer", Color::RED, mFGSurfaceControl.get());
+    Rect layerCrop(0, 0, 10, 10);
+    SurfaceComposerClient::Transaction().setCrop_legacy(child, layerCrop).show(child).apply(true);
+
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    sp<GraphicBuffer> outBuffer;
+    Rect sourceCrop = Rect();
+    ASSERT_EQ(NO_ERROR, sf->captureLayers(child->getHandle(), &outBuffer, sourceCrop));
+    ScreenCapture sc(outBuffer);
+
+    sc.expectColor(Rect(0, 0, 9, 9), Color::RED);
+}
+
+TEST_F(ScreenCaptureTest, CaptureBoundlessLayerWithoutSourceCropFails) {
+    sp<SurfaceControl> child = createColorLayer("Child layer", Color::RED, mFGSurfaceControl.get());
+    SurfaceComposerClient::Transaction().show(child).apply(true);
+
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    sp<GraphicBuffer> outBuffer;
+    Rect sourceCrop = Rect();
+
+    ASSERT_EQ(BAD_VALUE, sf->captureLayers(child->getHandle(), &outBuffer, sourceCrop));
+}
+
+TEST_F(ScreenCaptureTest, CaptureBufferLayerWithoutBufferFails) {
+    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    SurfaceComposerClient::Transaction().show(child).apply(true);
+
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    sp<GraphicBuffer> outBuffer;
+    Rect sourceCrop = Rect();
+    ASSERT_EQ(BAD_VALUE, sf->captureLayers(child->getHandle(), &outBuffer, sourceCrop));
+
+    TransactionUtils::fillSurfaceRGBA8(child, Color::RED);
+    SurfaceComposerClient::Transaction().apply(true);
+    ASSERT_EQ(NO_ERROR, sf->captureLayers(child->getHandle(), &outBuffer, sourceCrop));
+    ScreenCapture sc(outBuffer);
+    sc.expectColor(Rect(0, 0, 9, 9), Color::RED);
+}
+
+// In the following tests we verify successful skipping of a parent layer,
+// so we use the same verification logic and only change how we mutate
+// the parent layer to verify that various properties are ignored.
+class ScreenCaptureChildOnlyTest : public LayerUpdateTest {
+public:
+    void SetUp() override {
+        LayerUpdateTest::SetUp();
+
+        mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0,
+                               mFGSurfaceControl.get());
+        TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+        SurfaceComposerClient::Transaction().show(mChild).apply(true);
+    }
+
+    void verify(std::function<void()> verifyStartingState) {
+        // Verify starting state before a screenshot is taken.
+        verifyStartingState();
+
+        // Verify child layer does not inherit any of the properties of its
+        // parent when its screenshot is captured.
+        auto fgHandle = mFGSurfaceControl->getHandle();
+        ScreenCapture::captureChildLayers(&mCapture, fgHandle);
+        mCapture->checkPixel(10, 10, 0, 0, 0);
+        mCapture->expectChildColor(0, 0);
+
+        // Verify all assumptions are still true after the screenshot is taken.
+        verifyStartingState();
+    }
+
+    std::unique_ptr<ScreenCapture> mCapture;
+    sp<SurfaceControl> mChild;
+};
+
+// Regression test b/76099859
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentVisibility) {
+    SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
+
+    // Even though the parent is hidden we should still capture the child.
+
+    // Before and after reparenting, verify child is properly hidden
+    // when rendering full-screen.
+    verify([&] { screenshot()->expectBGColor(64, 64); });
+}
+
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentCrop) {
+    SurfaceComposerClient::Transaction()
+            .setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 1, 1))
+            .apply(true);
+
+    // Even though the parent is cropped out we should still capture the child.
+
+    // Before and after reparenting, verify child is cropped by parent.
+    verify([&] { screenshot()->expectBGColor(65, 65); });
+}
+
+// Regression test b/124372894
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) {
+    SurfaceComposerClient::Transaction().setMatrix(mFGSurfaceControl, 2, 0, 0, 2).apply(true);
+
+    // We should not inherit the parent scaling.
+
+    // Before and after reparenting, verify child is properly scaled.
+    verify([&] { screenshot()->expectChildColor(80, 80); });
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) {
+    auto fgHandle = mFGSurfaceControl->getHandle();
+
+    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+
+    sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 5, 5,
+                                                  PIXEL_FORMAT_RGBA_8888, 0, child.get());
+
+    TransactionUtils::fillSurfaceRGBA8(grandchild, 50, 50, 50);
+    SurfaceComposerClient::Transaction()
+            .show(child)
+            .setPosition(grandchild, 5, 5)
+            .show(grandchild)
+            .apply(true);
+
+    // Captures mFGSurfaceControl, its child, and the grandchild.
+    ScreenCapture::captureLayers(&mCapture, fgHandle);
+    mCapture->expectFGColor(10, 10);
+    mCapture->expectChildColor(0, 0);
+    mCapture->checkPixel(5, 5, 50, 50, 50);
+}
+
+TEST_F(ScreenCaptureTest, CaptureChildOnly) {
+    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+    auto childHandle = child->getHandle();
+
+    SurfaceComposerClient::Transaction().setPosition(child, 5, 5).show(child).apply(true);
+
+    // Captures only the child layer, and not the parent.
+    ScreenCapture::captureLayers(&mCapture, childHandle);
+    mCapture->expectChildColor(0, 0);
+    mCapture->expectChildColor(9, 9);
+}
+
+TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) {
+    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+    auto childHandle = child->getHandle();
+
+    sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 5, 5,
+                                                  PIXEL_FORMAT_RGBA_8888, 0, child.get());
+    TransactionUtils::fillSurfaceRGBA8(grandchild, 50, 50, 50);
+
+    SurfaceComposerClient::Transaction()
+            .show(child)
+            .setPosition(grandchild, 5, 5)
+            .show(grandchild)
+            .apply(true);
+
+    auto grandchildHandle = grandchild->getHandle();
+
+    // Captures only the grandchild.
+    ScreenCapture::captureLayers(&mCapture, grandchildHandle);
+    mCapture->checkPixel(0, 0, 50, 50, 50);
+    mCapture->checkPixel(4, 4, 50, 50, 50);
+}
+
+TEST_F(ScreenCaptureTest, CaptureCrop) {
+    sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+    sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
+                                                 PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
+
+    SurfaceComposerClient::Transaction()
+            .setLayer(redLayer, INT32_MAX - 1)
+            .show(redLayer)
+            .show(blueLayer)
+            .apply(true);
+
+    auto redLayerHandle = redLayer->getHandle();
+
+    // Capturing full screen should have both red and blue are visible.
+    ScreenCapture::captureLayers(&mCapture, redLayerHandle);
+    mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
+    // red area below the blue area
+    mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
+    // red area to the right of the blue area
+    mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
+
+    const Rect crop = Rect(0, 0, 30, 30);
+    ScreenCapture::captureLayers(&mCapture, redLayerHandle, crop);
+    // Capturing the cropped screen, cropping out the shown red area, should leave only the blue
+    // area visible.
+    mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
+    mCapture->checkPixel(30, 30, 0, 0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureSize) {
+    sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+    sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
+                                                 PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
+
+    SurfaceComposerClient::Transaction()
+            .setLayer(redLayer, INT32_MAX - 1)
+            .show(redLayer)
+            .show(blueLayer)
+            .apply(true);
+
+    auto redLayerHandle = redLayer->getHandle();
+
+    // Capturing full screen should have both red and blue are visible.
+    ScreenCapture::captureLayers(&mCapture, redLayerHandle);
+    mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
+    // red area below the blue area
+    mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
+    // red area to the right of the blue area
+    mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
+
+    ScreenCapture::captureLayers(&mCapture, redLayerHandle, Rect::EMPTY_RECT, 0.5);
+    // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area.
+    mCapture->expectColor(Rect(0, 0, 14, 14), Color::BLUE);
+    // red area below the blue area
+    mCapture->expectColor(Rect(0, 15, 29, 29), Color::RED);
+    // red area to the right of the blue area
+    mCapture->expectColor(Rect(15, 0, 29, 29), Color::RED);
+    mCapture->checkPixel(30, 30, 0, 0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
+    sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+
+    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
+
+    auto redLayerHandle = redLayer->getHandle();
+    Transaction().reparent(redLayer, nullptr).apply();
+    redLayer.clear();
+    SurfaceComposerClient::Transaction().apply(true);
+
+    sp<GraphicBuffer> outBuffer;
+
+    // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
+    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+    ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, &outBuffer, Rect::EMPTY_RECT, 1.0));
+}
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
new file mode 100644
index 0000000..b49bd54
--- /dev/null
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class MirrorLayerTest : public LayerTransactionTest {
+protected:
+    virtual void SetUp() {
+        LayerTransactionTest::SetUp();
+        ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+        const auto display = SurfaceComposerClient::getInternalDisplayToken();
+        ASSERT_FALSE(display == nullptr);
+
+        mParentLayer = createColorLayer("Parent layer", Color::RED);
+        mChildLayer = createColorLayer("Child layer", Color::GREEN, mParentLayer.get());
+        asTransaction([&](Transaction& t) {
+            t.setDisplayLayerStack(display, 0);
+            t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer);
+            t.setCrop_legacy(mChildLayer, Rect(0, 0, 400, 400)).show(mChildLayer);
+            t.setPosition(mChildLayer, 50, 50);
+            t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+            t.setFlags(mChildLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+        });
+    }
+
+    virtual void TearDown() {
+        LayerTransactionTest::TearDown();
+        mParentLayer = 0;
+        mChildLayer = 0;
+    }
+
+    sp<SurfaceControl> mParentLayer;
+    sp<SurfaceControl> mChildLayer;
+};
+
+TEST_F(MirrorLayerTest, MirrorColorLayer) {
+    sp<SurfaceControl> grandchild =
+            createColorLayer("Grandchild layer", Color::BLUE, mChildLayer.get());
+    Transaction()
+            .setFlags(grandchild, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque)
+            .setCrop_legacy(grandchild, Rect(0, 0, 200, 200))
+            .show(grandchild)
+            .apply();
+
+    // Mirror mChildLayer
+    sp<SurfaceControl> mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
+    ASSERT_NE(mirrorLayer, nullptr);
+
+    // Add mirrorLayer as child of mParentLayer so it's shown on the display
+    Transaction()
+            .reparent(mirrorLayer, mParentLayer->getHandle())
+            .setPosition(mirrorLayer, 500, 500)
+            .show(mirrorLayer)
+            .apply();
+
+    {
+        SCOPED_TRACE("Initial Mirror");
+        auto shot = screenshot();
+        // Grandchild mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+
+    // Set color to white on grandchild layer.
+    Transaction().setColor(grandchild, half3{1, 1, 1}).apply();
+    {
+        SCOPED_TRACE("Updated Grandchild Layer Color");
+        auto shot = screenshot();
+        // Grandchild mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+
+    // Set color to black on child layer.
+    Transaction().setColor(mChildLayer, half3{0, 0, 0}).apply();
+    {
+        SCOPED_TRACE("Updated Child Layer Color");
+        auto shot = screenshot();
+        // Grandchild mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+    }
+
+    // Remove grandchild layer
+    Transaction().reparent(grandchild, nullptr).apply();
+    {
+        SCOPED_TRACE("Removed Grandchild Layer");
+        auto shot = screenshot();
+        // Grandchild mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::BLACK);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+    }
+
+    // Remove child layer
+    Transaction().reparent(mChildLayer, nullptr).apply();
+    {
+        SCOPED_TRACE("Removed Child Layer");
+        auto shot = screenshot();
+        // Grandchild mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::RED);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::RED);
+    }
+
+    // Add grandchild layer to offscreen layer
+    Transaction().reparent(grandchild, mChildLayer->getHandle()).apply();
+    {
+        SCOPED_TRACE("Added Grandchild Layer");
+        auto shot = screenshot();
+        // Grandchild mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::RED);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::RED);
+    }
+
+    // Add child layer
+    Transaction().reparent(mChildLayer, mParentLayer->getHandle()).apply();
+    {
+        SCOPED_TRACE("Added Child Layer");
+        auto shot = screenshot();
+        // Grandchild mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+    }
+}
+
+TEST_F(MirrorLayerTest, MirrorBufferLayer) {
+    sp<SurfaceControl> bufferQueueLayer =
+            createLayer("BufferQueueLayer", 200, 200, 0, mChildLayer.get());
+    fillBufferQueueLayerColor(bufferQueueLayer, Color::BLUE, 200, 200);
+    Transaction().show(bufferQueueLayer).apply();
+
+    sp<SurfaceControl> mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
+    Transaction()
+            .reparent(mirrorLayer, mParentLayer->getHandle())
+            .setPosition(mirrorLayer, 500, 500)
+            .show(mirrorLayer)
+            .apply();
+
+    {
+        SCOPED_TRACE("Initial Mirror BufferQueueLayer");
+        auto shot = screenshot();
+        // Buffer mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+
+    fillBufferQueueLayerColor(bufferQueueLayer, Color::WHITE, 200, 200);
+    {
+        SCOPED_TRACE("Update BufferQueueLayer");
+        auto shot = screenshot();
+        // Buffer mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+
+    Transaction().reparent(bufferQueueLayer, nullptr).apply();
+    {
+        SCOPED_TRACE("Removed BufferQueueLayer");
+        auto shot = screenshot();
+        // Buffer mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::GREEN);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+
+    sp<SurfaceControl> bufferStateLayer =
+            createLayer("BufferStateLayer", 200, 200, ISurfaceComposerClient::eFXSurfaceBufferState,
+                        mChildLayer.get());
+    fillBufferStateLayerColor(bufferStateLayer, Color::BLUE, 200, 200);
+    Transaction().setFrame(bufferStateLayer, Rect(0, 0, 200, 200)).show(bufferStateLayer).apply();
+
+    {
+        SCOPED_TRACE("Initial Mirror BufferStateLayer");
+        auto shot = screenshot();
+        // Buffer mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+
+    fillBufferStateLayerColor(bufferStateLayer, Color::WHITE, 200, 200);
+    {
+        SCOPED_TRACE("Update BufferStateLayer");
+        auto shot = screenshot();
+        // Buffer mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+
+    Transaction().reparent(bufferStateLayer, nullptr).apply();
+    {
+        SCOPED_TRACE("Removed BufferStateLayer");
+        auto shot = screenshot();
+        // Buffer mirror
+        shot->expectColor(Rect(550, 550, 750, 750), Color::GREEN);
+        // Child mirror
+        shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+    }
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
new file mode 100644
index 0000000..06e8761
--- /dev/null
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <ui/DisplayState.h>
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+        ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class MultiDisplayLayerBoundsTest : public LayerTransactionTest {
+protected:
+    virtual void SetUp() {
+        LayerTransactionTest::SetUp();
+        ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+        mMainDisplay = SurfaceComposerClient::getInternalDisplayToken();
+        SurfaceComposerClient::getDisplayState(mMainDisplay, &mMainDisplayState);
+        SurfaceComposerClient::getActiveDisplayConfig(mMainDisplay, &mMainDisplayConfig);
+
+        sp<IGraphicBufferConsumer> consumer;
+        BufferQueue::createBufferQueue(&mProducer, &consumer);
+        consumer->setConsumerName(String8("Virtual disp consumer"));
+        consumer->setDefaultBufferSize(mMainDisplayConfig.resolution.getWidth(),
+                                       mMainDisplayConfig.resolution.getHeight());
+    }
+
+    virtual void TearDown() {
+        SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
+        LayerTransactionTest::TearDown();
+        mColorLayer = 0;
+    }
+
+    void createDisplay(const ui::Size& layerStackSize, uint32_t layerStack) {
+        mVirtualDisplay =
+                SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), false /*secure*/);
+        asTransaction([&](Transaction& t) {
+            t.setDisplaySurface(mVirtualDisplay, mProducer);
+            t.setDisplayLayerStack(mVirtualDisplay, layerStack);
+            t.setDisplayProjection(mVirtualDisplay, mMainDisplayState.orientation,
+                                   Rect(layerStackSize), Rect(mMainDisplayConfig.resolution));
+        });
+    }
+
+    void createColorLayer(uint32_t layerStack) {
+        mColorLayer =
+                createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */,
+                              PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect);
+        ASSERT_TRUE(mColorLayer != nullptr);
+        ASSERT_TRUE(mColorLayer->isValid());
+        asTransaction([&](Transaction& t) {
+            t.setLayerStack(mColorLayer, layerStack);
+            t.setCrop_legacy(mColorLayer, Rect(0, 0, 30, 40));
+            t.setLayer(mColorLayer, INT32_MAX - 2);
+            t.setColor(mColorLayer,
+                       half3{mExpectedColor.r / 255.0f, mExpectedColor.g / 255.0f,
+                             mExpectedColor.b / 255.0f});
+            t.show(mColorLayer);
+        });
+    }
+
+    ui::DisplayState mMainDisplayState;
+    DisplayConfig mMainDisplayConfig;
+    sp<IBinder> mMainDisplay;
+    sp<IBinder> mVirtualDisplay;
+    sp<IGraphicBufferProducer> mProducer;
+    sp<SurfaceControl> mColorLayer;
+    Color mExpectedColor = {63, 63, 195, 255};
+};
+
+TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) {
+    createDisplay(mMainDisplayState.viewport, 1 /* layerStack */);
+    createColorLayer(1 /* layerStack */);
+
+    asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
+
+    // Verify color layer does not render on main display.
+    std::unique_ptr<ScreenCapture> sc;
+    ScreenCapture::captureScreen(&sc, mMainDisplay);
+    sc->expectColor(Rect(10, 10, 40, 50), {0, 0, 0, 255});
+    sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+
+    // Verify color layer renders correctly on virtual display.
+    ScreenCapture::captureScreen(&sc, mVirtualDisplay);
+    sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+    sc->expectColor(Rect(1, 1, 9, 9), {0, 0, 0, 255});
+}
+
+TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) {
+    // Create a display and set its layer stack to the main display's layer stack so
+    // the contents of the main display are mirrored on to the virtual display.
+
+    // Assumption here is that the new mirrored display has the same viewport as the
+    // primary display that it is mirroring.
+    createDisplay(mMainDisplayState.viewport, 0 /* layerStack */);
+    createColorLayer(0 /* layerStack */);
+
+    asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
+
+    // Verify color layer renders correctly on main display and it is mirrored on the
+    // virtual display.
+    std::unique_ptr<ScreenCapture> sc;
+    ScreenCapture::captureScreen(&sc, mMainDisplay);
+    sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+    sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+
+    ScreenCapture::captureScreen(&sc, mVirtualDisplay);
+    sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+    sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/RelativeZ_test.cpp b/services/surfaceflinger/tests/RelativeZ_test.cpp
new file mode 100644
index 0000000..3e0b3c6
--- /dev/null
+++ b/services/surfaceflinger/tests/RelativeZ_test.cpp
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+        ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class RelativeZTest : public LayerTransactionTest {
+protected:
+    virtual void SetUp() {
+        LayerTransactionTest::SetUp();
+        ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+        const auto display = SurfaceComposerClient::getInternalDisplayToken();
+        ASSERT_FALSE(display == nullptr);
+
+        // Back layer
+        mBackgroundLayer = createColorLayer("Background layer", Color::RED);
+
+        // Front layer
+        mForegroundLayer = createColorLayer("Foreground layer", Color::GREEN);
+
+        asTransaction([&](Transaction& t) {
+            t.setDisplayLayerStack(display, 0);
+            t.setLayer(mBackgroundLayer, INT32_MAX - 2).show(mBackgroundLayer);
+            t.setLayer(mForegroundLayer, INT32_MAX - 1).show(mForegroundLayer);
+        });
+    }
+
+    virtual void TearDown() {
+        LayerTransactionTest::TearDown();
+        mBackgroundLayer = 0;
+        mForegroundLayer = 0;
+    }
+
+    sp<SurfaceControl> mBackgroundLayer;
+    sp<SurfaceControl> mForegroundLayer;
+};
+
+// When a layer is reparented offscreen, remove relative z order if the relative parent
+// is still onscreen so that the layer is not drawn.
+TEST_F(RelativeZTest, LayerRemoved) {
+    std::unique_ptr<ScreenCapture> sc;
+
+    // Background layer (RED)
+    //   Child layer (WHITE) (relative to foregroud layer)
+    // Foregroud layer (GREEN)
+    sp<SurfaceControl> childLayer =
+            createColorLayer("Child layer", Color::BLUE, mBackgroundLayer.get());
+
+    Transaction{}
+            .setRelativeLayer(childLayer, mForegroundLayer->getHandle(), 1)
+            .show(childLayer)
+            .apply();
+
+    {
+        // The childLayer should be in front of the FG control.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(1, 1, Color::BLUE.r, Color::BLUE.g, Color::BLUE.b);
+    }
+
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    Transaction{}.reparent(childLayer, nullptr).apply();
+
+    // Background layer (RED)
+    //   Child layer (WHITE)
+    // Foregroud layer (GREEN)
+    Transaction{}.reparent(childLayer, mBackgroundLayer->getHandle()).apply();
+
+    {
+        // The relative z info for child layer should be reset, leaving FG control on top.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+    }
+}
+
+// When a layer is reparented offscreen, preseve relative z order if the relative parent
+// is also offscreen. Regression test b/132613412
+TEST_F(RelativeZTest, LayerRemovedOffscreenRelativeParent) {
+    std::unique_ptr<ScreenCapture> sc;
+
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    //   child level 1 (WHITE)
+    //     child level 2a (BLUE)
+    //       child level 3 (GREEN) (relative to child level 2b)
+    //     child level 2b (BLACK)
+    sp<SurfaceControl> childLevel1 =
+            createColorLayer("child level 1", Color::WHITE, mForegroundLayer.get());
+    sp<SurfaceControl> childLevel2a =
+            createColorLayer("child level 2a", Color::BLUE, childLevel1.get());
+    sp<SurfaceControl> childLevel2b =
+            createColorLayer("child level 2b", Color::BLACK, childLevel1.get());
+    sp<SurfaceControl> childLevel3 =
+            createColorLayer("child level 3", Color::GREEN, childLevel2a.get());
+
+    Transaction{}
+            .setRelativeLayer(childLevel3, childLevel2b->getHandle(), 1)
+            .show(childLevel2a)
+            .show(childLevel2b)
+            .show(childLevel3)
+            .apply();
+
+    {
+        // The childLevel3 should be in front of childLevel2b.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+    }
+
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    Transaction{}.reparent(childLevel1, nullptr).apply();
+
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    //   child level 1 (WHITE)
+    //     child level 2 back (BLUE)
+    //       child level 3 (GREEN) (relative to child level 2b)
+    //     child level 2 front (BLACK)
+    Transaction{}.reparent(childLevel1, mForegroundLayer->getHandle()).apply();
+
+    {
+        // Nothing should change at this point since relative z info was preserved.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+    }
+}
+
+TEST_F(RelativeZTest, LayerAndRelativeRemoved) {
+    std::unique_ptr<ScreenCapture> sc;
+
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    //   Child layer (BLUE) (relative to relativeToLayer layer)
+    //   Relative layer (WHITE)
+    sp<SurfaceControl> childLayer =
+            createColorLayer("Child layer", Color::BLUE, mForegroundLayer.get());
+    sp<SurfaceControl> relativeToLayer =
+            createColorLayer("Relative layer", Color::WHITE, mForegroundLayer.get());
+
+    Transaction{}
+            .setRelativeLayer(childLayer, relativeToLayer->getHandle(), 1)
+            .show(childLayer)
+            .show(relativeToLayer)
+            .apply();
+
+    {
+        // The childLayer should be in front of relativeToLayer.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(1, 1, Color::BLUE.r, Color::BLUE.g, Color::BLUE.b);
+    }
+
+    // Remove layer that childLayer is relative to
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    //   Child layer (BLUE) (relative to relativeToLayer layer)
+    Transaction{}.reparent(relativeToLayer, nullptr).apply();
+    relativeToLayer = 0;
+
+    {
+        // The child layer is relative to an deleted layer so it won't be drawn.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+    }
+
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    Transaction{}.reparent(childLayer, nullptr).apply();
+
+    {
+        // The child layer is offscreen, so it won't be drawn.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+    }
+
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    //   Child layer (BLUE)
+    Transaction{}.reparent(childLayer, mForegroundLayer->getHandle()).apply();
+
+    {
+        // The relative z info for child layer should be reset, leaving the child layer on top.
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(1, 1, Color::BLUE.r, Color::BLUE.g, Color::BLUE.b);
+    }
+}
+
+// Preserve the relative z order when a layer is reparented to a layer that's already offscreen
+TEST_F(RelativeZTest, LayerWithRelativeReparentedToOffscreen) {
+    std::unique_ptr<ScreenCapture> sc;
+
+    Color testLayerColor = {255, 100, 0, 255};
+
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    //   child level 1a (testLayerColor) (relative to child level 2b)
+    //   child level 1b (WHITE)
+    //     child level 2a (BLUE)
+    //     child level 2b (BLACK)
+    sp<SurfaceControl> childLevel1a =
+            createColorLayer("child level 1a", testLayerColor, mForegroundLayer.get());
+    sp<SurfaceControl> childLevel1b =
+            createColorLayer("child level 1b", Color::WHITE, mForegroundLayer.get());
+    sp<SurfaceControl> childLevel2a =
+            createColorLayer("child level 2a", Color::BLUE, childLevel1b.get());
+    sp<SurfaceControl> childLevel2b =
+            createColorLayer("child level 2b", Color::BLACK, childLevel1b.get());
+
+    Transaction{}
+            .setRelativeLayer(childLevel1a, childLevel2b->getHandle(), 1)
+            .show(childLevel1a)
+            .show(childLevel1b)
+            .show(childLevel2a)
+            .show(childLevel2b)
+            .apply();
+
+    {
+        // The childLevel1a should be in front of childLevel2b.
+        ScreenCapture::captureScreen(&sc);
+        sc->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), testLayerColor);
+    }
+
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    //   child level 1a (testLayerColor) (relative to child level 2b)
+    Transaction{}.reparent(childLevel1b, nullptr).apply();
+
+    // // Background layer (RED)
+    // // Foregroud layer (GREEN)
+    Transaction{}.reparent(childLevel1a, childLevel2a->getHandle()).apply();
+
+    {
+        // The childLevel1a and childLevel1b are no longer on screen
+        ScreenCapture::captureScreen(&sc);
+        sc->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::GREEN);
+    }
+
+    // Background layer (RED)
+    // Foregroud layer (GREEN)
+    //   child level 1b (WHITE)
+    //     child level 2a (BLUE)
+    //       child level 1a (testLayerColor) (relative to child level 2b)
+    //     child level 2b (BLACK)
+    Transaction{}.reparent(childLevel1b, mForegroundLayer->getHandle()).apply();
+
+    {
+        // Nothing should change at this point since relative z info was preserved.
+        ScreenCapture::captureScreen(&sc);
+        sc->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), testLayerColor);
+    }
+}
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/SetFrameRate_test.cpp b/services/surfaceflinger/tests/SetFrameRate_test.cpp
new file mode 100644
index 0000000..02ba9e2
--- /dev/null
+++ b/services/surfaceflinger/tests/SetFrameRate_test.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <system/window.h>
+
+#include <thread>
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class SetFrameRateTest : public LayerTransactionTest {
+protected:
+    void TearDown() {
+        mLayer = nullptr;
+        LayerTransactionTest::TearDown();
+    }
+
+    void CreateLayer(uint32_t layerType) {
+        ASSERT_EQ(nullptr, mLayer.get());
+        mLayerType = layerType;
+        ASSERT_NO_FATAL_FAILURE(mLayer = createLayer("TestLayer", mLayerWidth, mLayerHeight,
+                                                     /*flags=*/mLayerType));
+        ASSERT_NE(nullptr, mLayer.get());
+    }
+
+    void PostBuffers(const Color& color) {
+        auto startTime = systemTime();
+        while (systemTime() - startTime < s2ns(1)) {
+            ASSERT_NO_FATAL_FAILURE(
+                    fillLayerColor(mLayerType, mLayer, color, mLayerWidth, mLayerHeight));
+            std::this_thread::sleep_for(100ms);
+        }
+    }
+
+    const int mLayerWidth = 32;
+    const int mLayerHeight = 32;
+    sp<SurfaceControl> mLayer;
+    uint32_t mLayerType;
+};
+
+TEST_F(SetFrameRateTest, BufferQueueLayerSetFrameRate) {
+    CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferQueue);
+    native_window_set_frame_rate(mLayer->getSurface().get(), 100.f,
+                                 ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT);
+    ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
+    Transaction()
+            .setFrameRate(mLayer, 200.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT)
+            .apply();
+    ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
+    native_window_set_frame_rate(mLayer->getSurface().get(), 300.f,
+                                 ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT);
+    ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::RED));
+}
+
+TEST_F(SetFrameRateTest, BufferStateLayerSetFrameRate) {
+    CreateLayer(ISurfaceComposerClient::eFXSurfaceBufferState);
+    Transaction()
+            .setFrameRate(mLayer, 400.f, ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT)
+            .apply();
+    ASSERT_NO_FATAL_FAILURE(PostBuffers(Color::GREEN));
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/SetGeometry_test.cpp b/services/surfaceflinger/tests/SetGeometry_test.cpp
new file mode 100644
index 0000000..5fe2513
--- /dev/null
+++ b/services/surfaceflinger/tests/SetGeometry_test.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class SetGeometryTest : public LayerTransactionTest {
+protected:
+    void SetUp() {
+        LayerTransactionTest::SetUp();
+        ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+        mLayer = createLayer("Layer", mLayerWidth, mLayerHeight);
+        fillBufferQueueLayerColor(mLayer, Color::RED, mLayerWidth, mLayerHeight);
+        asTransaction([&](Transaction& t) { t.setLayer(mLayer, INT32_MAX - 1).show(mLayer); });
+
+        {
+            SCOPED_TRACE("init");
+            ScreenCapture::captureScreen(&sc);
+            sc->expectColor(Rect(0, 0, mLayerWidth, mLayerHeight), Color::RED);
+            sc->expectBorder(Rect(0, 0, mLayerWidth, mLayerHeight), Color::BLACK);
+        }
+    }
+
+    void TearDown() {
+        LayerTransactionTest::TearDown();
+        sc = 0;
+        mLayer = 0;
+    }
+
+    std::unique_ptr<ScreenCapture> sc;
+    sp<SurfaceControl> mLayer;
+    const int mLayerWidth = 100;
+    const int mLayerHeight = 200;
+};
+
+TEST_F(SetGeometryTest, SourceAtZeroNoScale) {
+    Rect source = Rect(0, 0, 30, 30);
+    Rect dest = Rect(60, 60, 90, 90);
+    Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+    {
+        SCOPED_TRACE("geometry applied");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectColor(dest, Color::RED);
+        sc->expectBorder(dest, Color::BLACK);
+    }
+}
+
+TEST_F(SetGeometryTest, SourceNotAtZero) {
+    Rect source = Rect(40, 40, 70, 70);
+    Rect dest = Rect(60, 60, 90, 90);
+    Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+    {
+        SCOPED_TRACE("geometry applied");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectColor(dest, Color::RED);
+        sc->expectBorder(dest, Color::BLACK);
+    }
+}
+
+TEST_F(SetGeometryTest, Scale) {
+    Rect source = Rect(0, 0, 100, 200);
+    Rect dest = Rect(0, 0, 200, 400);
+    Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+    {
+        SCOPED_TRACE("Scaled by 2");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectColor(dest, Color::RED);
+        sc->expectBorder(dest, Color::BLACK);
+    }
+
+    dest = Rect(0, 0, 50, 100);
+    Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+    {
+        SCOPED_TRACE("Scaled by .5");
+        ScreenCapture::captureScreen(&sc);
+        sc->expectColor(dest, Color::RED);
+        sc->expectBorder(dest, Color::BLACK);
+    }
+}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/Stress_test.cpp b/services/surfaceflinger/tests/Stress_test.cpp
index ee857b0..e9b6ba0 100644
--- a/services/surfaceflinger/tests/Stress_test.cpp
+++ b/services/surfaceflinger/tests/Stress_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <gtest/gtest.h>
 
 #include <gui/SurfaceComposerClient.h>
@@ -107,3 +111,6 @@
 }
 
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 6b4634a..cf7d570 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
 {
         "presubmit": {
-            "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*:MultiDisplayLayerBoundsTest.*:InvalidHandleTest.*:VirtualDisplayTest.*:RelativeZTest.*"
+            "filter": ""
         }
 }
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 5cc946a..8d97f27 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -14,20 +14,19 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <frameworks/native/cmds/surfacereplayer/proto/src/trace.pb.h>
 #include <google/protobuf/io/zero_copy_stream_impl.h>
-
 #include <gtest/gtest.h>
-
-#include <android/native_window.h>
-
 #include <gui/ISurfaceComposer.h>
 #include <gui/LayerState.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
-
 #include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
 
 #include <fstream>
 #include <random>
@@ -36,6 +35,9 @@
 namespace android {
 
 using Transaction = SurfaceComposerClient::Transaction;
+using SurfaceChange = surfaceflinger::SurfaceChange;
+using Trace = surfaceflinger::Trace;
+using Increment = surfaceflinger::Increment;
 
 constexpr int32_t SCALING_UPDATE = 1;
 constexpr uint32_t BUFFER_UPDATES = 18;
@@ -43,18 +45,23 @@
 constexpr uint32_t SIZE_UPDATE = 134;
 constexpr uint32_t STACK_UPDATE = 1;
 constexpr uint64_t DEFERRED_UPDATE = 0;
+constexpr int32_t RELATIVE_Z = 42;
 constexpr float ALPHA_UPDATE = 0.29f;
 constexpr float CORNER_RADIUS_UPDATE = 0.2f;
+constexpr int BACKGROUND_BLUR_RADIUS_UPDATE = 24;
 constexpr float POSITION_UPDATE = 121;
 const Rect CROP_UPDATE(16, 16, 32, 32);
+const float SHADOW_RADIUS_UPDATE = 35.0f;
 
 const String8 DISPLAY_NAME("SurfaceInterceptor Display Test");
-constexpr auto TEST_SURFACE_NAME = "BG Interceptor Test Surface";
-constexpr auto UNIQUE_TEST_SURFACE_NAME = "BG Interceptor Test Surface#0";
+constexpr auto TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface";
+constexpr auto TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface";
+constexpr auto UNIQUE_TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface#0";
+constexpr auto UNIQUE_TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface#0";
 constexpr auto LAYER_NAME = "Layer Create and Delete Test";
 constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0";
 
-constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
+constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
 
 // Fill an RGBA_8888 formatted surface with a single color.
 static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b) {
@@ -136,12 +143,16 @@
     void TearDown() override {
         mComposerClient->dispose();
         mBGSurfaceControl.clear();
+        mFGSurfaceControl.clear();
         mComposerClient.clear();
+        system("setenforce 1");
     }
 
     sp<SurfaceComposerClient> mComposerClient;
     sp<SurfaceControl> mBGSurfaceControl;
+    sp<SurfaceControl> mFGSurfaceControl;
     int32_t mBGLayerId;
+    int32_t mFGLayerId;
 
 public:
     using TestTransactionAction = void (SurfaceInterceptorTest::*)(Transaction&);
@@ -169,6 +180,8 @@
     bool layerUpdateFound(const SurfaceChange& change, bool foundLayer);
     bool cropUpdateFound(const SurfaceChange& change, bool foundCrop);
     bool cornerRadiusUpdateFound(const SurfaceChange& change, bool foundCornerRadius);
+    bool backgroundBlurRadiusUpdateFound(const SurfaceChange& change,
+                                         bool foundBackgroundBlurRadius);
     bool matrixUpdateFound(const SurfaceChange& change, bool foundMatrix);
     bool scalingModeUpdateFound(const SurfaceChange& change, bool foundScalingMode);
     bool transparentRegionHintUpdateFound(const SurfaceChange& change, bool foundTransparentRegion);
@@ -177,6 +190,11 @@
     bool opaqueFlagUpdateFound(const SurfaceChange& change, bool foundOpaqueFlag);
     bool secureFlagUpdateFound(const SurfaceChange& change, bool foundSecureFlag);
     bool deferredTransactionUpdateFound(const SurfaceChange& change, bool foundDeferred);
+    bool reparentUpdateFound(const SurfaceChange& change, bool found);
+    bool relativeParentUpdateFound(const SurfaceChange& change, bool found);
+    bool detachChildrenUpdateFound(const SurfaceChange& change, bool found);
+    bool reparentChildrenUpdateFound(const SurfaceChange& change, bool found);
+    bool shadowRadiusUpdateFound(const SurfaceChange& change, bool found);
     bool surfaceUpdateFound(const Trace& trace, SurfaceChange::SurfaceChangeCase changeCase);
 
     // Find all of the updates in the single trace
@@ -201,6 +219,7 @@
     void layerUpdate(Transaction&);
     void cropUpdate(Transaction&);
     void cornerRadiusUpdate(Transaction&);
+    void backgroundBlurRadiusUpdate(Transaction&);
     void matrixUpdate(Transaction&);
     void overrideScalingModeUpdate(Transaction&);
     void transparentRegionHintUpdate(Transaction&);
@@ -209,6 +228,11 @@
     void opaqueFlagUpdate(Transaction&);
     void secureFlagUpdate(Transaction&);
     void deferredTransactionUpdate(Transaction&);
+    void reparentUpdate(Transaction&);
+    void relativeParentUpdate(Transaction&);
+    void detachChildrenUpdate(Transaction&);
+    void reparentChildrenUpdate(Transaction&);
+    void shadowRadiusUpdate(Transaction&);
     void surfaceCreation(Transaction&);
     void displayCreation(Transaction&);
     void displayDeletion(Transaction&);
@@ -243,28 +267,37 @@
     const auto display = SurfaceComposerClient::getInternalDisplayToken();
     ASSERT_FALSE(display == nullptr);
 
-    DisplayInfo info;
-    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
-
-    ssize_t displayWidth = info.w;
-    ssize_t displayHeight = info.h;
+    DisplayConfig config;
+    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+    const ui::Size& resolution = config.resolution;
 
     // Background surface
-    mBGSurfaceControl = mComposerClient->createSurface(
-            String8(TEST_SURFACE_NAME), displayWidth, displayHeight,
-            PIXEL_FORMAT_RGBA_8888, 0);
+    mBGSurfaceControl =
+            mComposerClient->createSurface(String8(TEST_BG_SURFACE_NAME), resolution.getWidth(),
+                                           resolution.getHeight(), PIXEL_FORMAT_RGBA_8888, 0);
     ASSERT_TRUE(mBGSurfaceControl != nullptr);
     ASSERT_TRUE(mBGSurfaceControl->isValid());
 
+    // Foreground surface
+    mFGSurfaceControl =
+            mComposerClient->createSurface(String8(TEST_FG_SURFACE_NAME), resolution.getWidth(),
+                                           resolution.getHeight(), PIXEL_FORMAT_RGBA_8888, 0);
+    ASSERT_TRUE(mFGSurfaceControl != nullptr);
+    ASSERT_TRUE(mFGSurfaceControl->isValid());
+
     Transaction t;
     t.setDisplayLayerStack(display, 0);
-    ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX-3)
-            .show(mBGSurfaceControl)
-            .apply());
+    ASSERT_EQ(NO_ERROR,
+              t.setLayer(mBGSurfaceControl, INT_MAX - 3)
+                      .show(mBGSurfaceControl)
+                      .setLayer(mFGSurfaceControl, INT_MAX - 3)
+                      .show(mFGSurfaceControl)
+                      .apply());
 }
 
 void SurfaceInterceptorTest::preProcessTrace(const Trace& trace) {
-    mBGLayerId = getSurfaceId(trace, UNIQUE_TEST_SURFACE_NAME);
+    mBGLayerId = getSurfaceId(trace, UNIQUE_TEST_BG_SURFACE_NAME);
+    mFGLayerId = getSurfaceId(trace, UNIQUE_TEST_FG_SURFACE_NAME);
 }
 
 void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
@@ -322,6 +355,10 @@
     t.setCornerRadius(mBGSurfaceControl, CORNER_RADIUS_UPDATE);
 }
 
+void SurfaceInterceptorTest::backgroundBlurRadiusUpdate(Transaction& t) {
+    t.setBackgroundBlurRadius(mBGSurfaceControl, BACKGROUND_BLUR_RADIUS_UPDATE);
+}
+
 void SurfaceInterceptorTest::layerUpdate(Transaction& t) {
     t.setLayer(mBGSurfaceControl, LAYER_UPDATE);
 }
@@ -364,6 +401,26 @@
                                    DEFERRED_UPDATE);
 }
 
+void SurfaceInterceptorTest::reparentUpdate(Transaction& t) {
+    t.reparent(mBGSurfaceControl, mFGSurfaceControl->getHandle());
+}
+
+void SurfaceInterceptorTest::relativeParentUpdate(Transaction& t) {
+    t.setRelativeLayer(mBGSurfaceControl, mFGSurfaceControl->getHandle(), RELATIVE_Z);
+}
+
+void SurfaceInterceptorTest::detachChildrenUpdate(Transaction& t) {
+    t.detachChildren(mBGSurfaceControl);
+}
+
+void SurfaceInterceptorTest::reparentChildrenUpdate(Transaction& t) {
+    t.reparentChildren(mBGSurfaceControl, mFGSurfaceControl->getHandle());
+}
+
+void SurfaceInterceptorTest::shadowRadiusUpdate(Transaction& t) {
+    t.setShadowRadius(mBGSurfaceControl, SHADOW_RADIUS_UPDATE);
+}
+
 void SurfaceInterceptorTest::displayCreation(Transaction&) {
     sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
     SurfaceComposerClient::destroyDisplay(testDisplay);
@@ -379,6 +436,7 @@
     runInTransaction(&SurfaceInterceptorTest::sizeUpdate);
     runInTransaction(&SurfaceInterceptorTest::alphaUpdate);
     runInTransaction(&SurfaceInterceptorTest::cornerRadiusUpdate);
+    runInTransaction(&SurfaceInterceptorTest::backgroundBlurRadiusUpdate);
     runInTransaction(&SurfaceInterceptorTest::layerUpdate);
     runInTransaction(&SurfaceInterceptorTest::cropUpdate);
     runInTransaction(&SurfaceInterceptorTest::matrixUpdate);
@@ -389,6 +447,11 @@
     runInTransaction(&SurfaceInterceptorTest::opaqueFlagUpdate);
     runInTransaction(&SurfaceInterceptorTest::secureFlagUpdate);
     runInTransaction(&SurfaceInterceptorTest::deferredTransactionUpdate);
+    runInTransaction(&SurfaceInterceptorTest::reparentUpdate);
+    runInTransaction(&SurfaceInterceptorTest::reparentChildrenUpdate);
+    runInTransaction(&SurfaceInterceptorTest::detachChildrenUpdate);
+    runInTransaction(&SurfaceInterceptorTest::relativeParentUpdate);
+    runInTransaction(&SurfaceInterceptorTest::shadowRadiusUpdate);
 }
 
 void SurfaceInterceptorTest::surfaceCreation(Transaction&) {
@@ -451,6 +514,18 @@
     return foundCornerRadius;
 }
 
+bool SurfaceInterceptorTest::backgroundBlurRadiusUpdateFound(const SurfaceChange& change,
+                                                             bool foundBackgroundBlur) {
+    bool hasBackgroundBlur(change.background_blur_radius().background_blur_radius() ==
+                           BACKGROUND_BLUR_RADIUS_UPDATE);
+    if (hasBackgroundBlur && !foundBackgroundBlur) {
+        foundBackgroundBlur = true;
+    } else if (hasBackgroundBlur && foundBackgroundBlur) {
+        []() { FAIL(); }();
+    }
+    return foundBackgroundBlur;
+}
+
 bool SurfaceInterceptorTest::layerUpdateFound(const SurfaceChange& change, bool foundLayer) {
     bool hasLayer(change.layer().layer() == LAYER_UPDATE);
     if (hasLayer && !foundLayer) {
@@ -569,6 +644,57 @@
     return foundDeferred;
 }
 
+bool SurfaceInterceptorTest::reparentUpdateFound(const SurfaceChange& change, bool found) {
+    bool hasId(change.reparent().parent_id() == mFGLayerId);
+    if (hasId && !found) {
+        found = true;
+    } else if (hasId && found) {
+        []() { FAIL(); }();
+    }
+    return found;
+}
+
+bool SurfaceInterceptorTest::relativeParentUpdateFound(const SurfaceChange& change, bool found) {
+    bool hasId(change.relative_parent().relative_parent_id() == mFGLayerId);
+    if (hasId && !found) {
+        found = true;
+    } else if (hasId && found) {
+        []() { FAIL(); }();
+    }
+    return found;
+}
+
+bool SurfaceInterceptorTest::detachChildrenUpdateFound(const SurfaceChange& change, bool found) {
+    bool detachChildren(change.detach_children().detach_children());
+    if (detachChildren && !found) {
+        found = true;
+    } else if (detachChildren && found) {
+        []() { FAIL(); }();
+    }
+    return found;
+}
+
+bool SurfaceInterceptorTest::reparentChildrenUpdateFound(const SurfaceChange& change, bool found) {
+    bool hasId(change.reparent_children().parent_id() == mFGLayerId);
+    if (hasId && !found) {
+        found = true;
+    } else if (hasId && found) {
+        []() { FAIL(); }();
+    }
+    return found;
+}
+
+bool SurfaceInterceptorTest::shadowRadiusUpdateFound(const SurfaceChange& change,
+                                                     bool foundShadowRadius) {
+    bool hasShadowRadius(change.shadow_radius().radius() == SHADOW_RADIUS_UPDATE);
+    if (hasShadowRadius && !foundShadowRadius) {
+        foundShadowRadius = true;
+    } else if (hasShadowRadius && foundShadowRadius) {
+        []() { FAIL(); }();
+    }
+    return foundShadowRadius;
+}
+
 bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace,
         SurfaceChange::SurfaceChangeCase changeCase) {
     bool foundUpdate = false;
@@ -596,6 +722,9 @@
                         case SurfaceChange::SurfaceChangeCase::kCornerRadius:
                             foundUpdate = cornerRadiusUpdateFound(change, foundUpdate);
                             break;
+                        case SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius:
+                            foundUpdate = backgroundBlurRadiusUpdateFound(change, foundUpdate);
+                            break;
                         case SurfaceChange::SurfaceChangeCase::kMatrix:
                             foundUpdate = matrixUpdateFound(change, foundUpdate);
                             break;
@@ -620,6 +749,21 @@
                         case SurfaceChange::SurfaceChangeCase::kDeferredTransaction:
                             foundUpdate = deferredTransactionUpdateFound(change, foundUpdate);
                             break;
+                        case SurfaceChange::SurfaceChangeCase::kReparent:
+                            foundUpdate = reparentUpdateFound(change, foundUpdate);
+                            break;
+                        case SurfaceChange::SurfaceChangeCase::kReparentChildren:
+                            foundUpdate = reparentChildrenUpdateFound(change, foundUpdate);
+                            break;
+                        case SurfaceChange::SurfaceChangeCase::kRelativeParent:
+                            foundUpdate = relativeParentUpdateFound(change, foundUpdate);
+                            break;
+                        case SurfaceChange::SurfaceChangeCase::kDetachChildren:
+                            foundUpdate = detachChildrenUpdateFound(change, foundUpdate);
+                            break;
+                        case SurfaceChange::SurfaceChangeCase::kShadowRadius:
+                            foundUpdate = shadowRadiusUpdateFound(change, foundUpdate);
+                            break;
                         case SurfaceChange::SurfaceChangeCase::SURFACECHANGE_NOT_SET:
                             break;
                     }
@@ -644,6 +788,10 @@
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kOpaqueFlag));
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kSecureFlag));
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kDeferredTransaction));
+    ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparent));
+    ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparentChildren));
+    ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kRelativeParent));
+    ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kDetachChildren));
 }
 
 bool SurfaceInterceptorTest::surfaceCreationFound(const Increment& increment, bool foundSurface) {
@@ -759,6 +907,11 @@
             SurfaceChange::SurfaceChangeCase::kCornerRadius);
 }
 
+TEST_F(SurfaceInterceptorTest, InterceptBackgroundBlurRadiusUpdateWorks) {
+    captureTest(&SurfaceInterceptorTest::backgroundBlurRadiusUpdate,
+                SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius);
+}
+
 TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) {
     captureTest(&SurfaceInterceptorTest::matrixUpdate, SurfaceChange::SurfaceChangeCase::kMatrix);
 }
@@ -798,6 +951,31 @@
             SurfaceChange::SurfaceChangeCase::kDeferredTransaction);
 }
 
+TEST_F(SurfaceInterceptorTest, InterceptReparentUpdateWorks) {
+    captureTest(&SurfaceInterceptorTest::reparentUpdate,
+                SurfaceChange::SurfaceChangeCase::kReparent);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptReparentChildrenUpdateWorks) {
+    captureTest(&SurfaceInterceptorTest::reparentChildrenUpdate,
+                SurfaceChange::SurfaceChangeCase::kReparentChildren);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptRelativeParentUpdateWorks) {
+    captureTest(&SurfaceInterceptorTest::relativeParentUpdate,
+                SurfaceChange::SurfaceChangeCase::kRelativeParent);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptDetachChildrenUpdateWorks) {
+    captureTest(&SurfaceInterceptorTest::detachChildrenUpdate,
+                SurfaceChange::SurfaceChangeCase::kDetachChildren);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptShadowRadiusUpdateWorks) {
+    captureTest(&SurfaceInterceptorTest::shadowRadiusUpdate,
+                SurfaceChange::SurfaceChangeCase::kShadowRadius);
+}
+
 TEST_F(SurfaceInterceptorTest, InterceptAllUpdatesWorks) {
     captureTest(&SurfaceInterceptorTest::runAllUpdates,
                 &SurfaceInterceptorTest::assertAllUpdatesFound);
@@ -861,5 +1039,7 @@
     ASSERT_TRUE(bufferUpdatesFound(capturedTrace));
     ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceCreation));
 }
-
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
new file mode 100644
index 0000000..f0af363
--- /dev/null
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 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.
+ */
+#ifndef ANDROID_TRANSACTION_TEST_HARNESSES
+#define ANDROID_TRANSACTION_TEST_HARNESSES
+
+#include <ui/DisplayState.h>
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class LayerRenderPathTestHarness {
+public:
+    LayerRenderPathTestHarness(LayerTransactionTest* delegate, RenderPath renderPath)
+          : mDelegate(delegate), mRenderPath(renderPath) {}
+
+    std::unique_ptr<ScreenCapture> getScreenCapture() {
+        switch (mRenderPath) {
+            case RenderPath::SCREENSHOT:
+                return mDelegate->screenshot();
+            case RenderPath::VIRTUAL_DISPLAY:
+
+                const auto displayToken = SurfaceComposerClient::getInternalDisplayToken();
+
+                ui::DisplayState displayState;
+                SurfaceComposerClient::getDisplayState(displayToken, &displayState);
+
+                DisplayConfig displayConfig;
+                SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
+                const ui::Size& resolution = displayConfig.resolution;
+
+                sp<IBinder> vDisplay;
+                sp<IGraphicBufferProducer> producer;
+                sp<IGraphicBufferConsumer> consumer;
+                sp<BufferItemConsumer> itemConsumer;
+                BufferQueue::createBufferQueue(&producer, &consumer);
+
+                consumer->setConsumerName(String8("Virtual disp consumer"));
+                consumer->setDefaultBufferSize(resolution.getWidth(), resolution.getHeight());
+
+                itemConsumer = new BufferItemConsumer(consumer,
+                                                      // Sample usage bits from screenrecord
+                                                      GRALLOC_USAGE_HW_VIDEO_ENCODER |
+                                                              GRALLOC_USAGE_SW_READ_OFTEN);
+
+                vDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"),
+                                                                false /*secure*/);
+
+                SurfaceComposerClient::Transaction t;
+                t.setDisplaySurface(vDisplay, producer);
+                t.setDisplayLayerStack(vDisplay, 0);
+                t.setDisplayProjection(vDisplay, displayState.orientation,
+                                       Rect(displayState.viewport), Rect(resolution));
+                t.apply();
+                SurfaceComposerClient::Transaction().apply(true);
+                BufferItem item;
+                itemConsumer->acquireBuffer(&item, 0, true);
+                auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer);
+                itemConsumer->releaseBuffer(item);
+                SurfaceComposerClient::destroyDisplay(vDisplay);
+                return sc;
+        }
+    }
+
+protected:
+    LayerTransactionTest* mDelegate;
+    RenderPath mRenderPath;
+};
+
+class LayerTypeTransactionHarness : public LayerTransactionTest {
+public:
+    LayerTypeTransactionHarness(uint32_t layerType) : mLayerType(layerType) {}
+
+    sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+                                   uint32_t flags = 0, SurfaceControl* parent = nullptr,
+                                   uint32_t* outTransformHint = nullptr,
+                                   PixelFormat format = PIXEL_FORMAT_RGBA_8888) {
+        // if the flags already have a layer type specified, return an error
+        if (flags & ISurfaceComposerClient::eFXSurfaceMask) {
+            return nullptr;
+        }
+        return LayerTransactionTest::createLayer(name, width, height, flags | mLayerType, parent,
+                                                 outTransformHint, format);
+    }
+
+    void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color, int32_t bufferWidth,
+                        int32_t bufferHeight) {
+        ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerColor(mLayerType, layer, color,
+                                                                     bufferWidth, bufferHeight));
+    }
+
+    void fillLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
+                           int32_t bufferHeight, const Color& topLeft, const Color& topRight,
+                           const Color& bottomLeft, const Color& bottomRight) {
+        ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerQuadrant(mLayerType, layer,
+                                                                        bufferWidth, bufferHeight,
+                                                                        topLeft, topRight,
+                                                                        bottomLeft, bottomRight));
+    }
+
+protected:
+    uint32_t mLayerType;
+};
+} // namespace android
+#endif
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
deleted file mode 100644
index 71016db..0000000
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ /dev/null
@@ -1,6218 +0,0 @@
-/*
- * Copyright (C) 2011 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 <algorithm>
-#include <chrono>
-#include <cinttypes>
-#include <functional>
-#include <limits>
-#include <ostream>
-#include <thread>
-
-#include <gtest/gtest.h>
-
-#include <android/native_window.h>
-
-#include <binder/ProcessState.h>
-#include <gui/BufferItemConsumer.h>
-#include <gui/IProducerListener.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/LayerState.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-#include <hardware/hwcomposer_defs.h>
-#include <private/android_filesystem_config.h>
-#include <private/gui/ComposerService.h>
-
-#include <ui/ColorSpace.h>
-#include <ui/DisplayInfo.h>
-#include <ui/Rect.h>
-#include <utils/String8.h>
-
-#include <math.h>
-#include <math/vec3.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "BufferGenerator.h"
-
-namespace android {
-
-namespace {
-
-struct Color {
-    uint8_t r;
-    uint8_t g;
-    uint8_t b;
-    uint8_t a;
-
-    static const Color RED;
-    static const Color GREEN;
-    static const Color BLUE;
-    static const Color WHITE;
-    static const Color BLACK;
-    static const Color TRANSPARENT;
-};
-
-const Color Color::RED{255, 0, 0, 255};
-const Color Color::GREEN{0, 255, 0, 255};
-const Color Color::BLUE{0, 0, 255, 255};
-const Color Color::WHITE{255, 255, 255, 255};
-const Color Color::BLACK{0, 0, 0, 255};
-const Color Color::TRANSPARENT{0, 0, 0, 0};
-
-using android::hardware::graphics::common::V1_1::BufferUsage;
-using namespace std::chrono_literals;
-
-std::ostream& operator<<(std::ostream& os, const Color& color) {
-    os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
-    return os;
-}
-
-// Fill a region with the specified color.
-void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect,
-                                  const Color& color) {
-    Rect r(0, 0, buffer.width, buffer.height);
-    if (!r.intersect(rect, &r)) {
-        return;
-    }
-
-    int32_t width = r.right - r.left;
-    int32_t height = r.bottom - r.top;
-
-    for (int32_t row = 0; row < height; row++) {
-        uint8_t* dst =
-                static_cast<uint8_t*>(buffer.bits) + (buffer.stride * (r.top + row) + r.left) * 4;
-        for (int32_t column = 0; column < width; column++) {
-            dst[0] = color.r;
-            dst[1] = color.g;
-            dst[2] = color.b;
-            dst[3] = color.a;
-            dst += 4;
-        }
-    }
-}
-
-// Fill a region with the specified color.
-void fillGraphicBufferColor(const sp<GraphicBuffer>& buffer, const Rect& rect, const Color& color) {
-    Rect r(0, 0, buffer->width, buffer->height);
-    if (!r.intersect(rect, &r)) {
-        return;
-    }
-
-    int32_t width = r.right - r.left;
-    int32_t height = r.bottom - r.top;
-
-    uint8_t* pixels;
-    buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
-                 reinterpret_cast<void**>(&pixels));
-
-    for (int32_t row = 0; row < height; row++) {
-        uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4;
-        for (int32_t column = 0; column < width; column++) {
-            dst[0] = color.r;
-            dst[1] = color.g;
-            dst[2] = color.b;
-            dst[3] = color.a;
-            dst += 4;
-        }
-    }
-    buffer->unlock();
-}
-
-// Check if a region has the specified color.
-void expectBufferColor(const sp<GraphicBuffer>& outBuffer, uint8_t* pixels, const Rect& rect,
-                       const Color& color, uint8_t tolerance) {
-    int32_t x = rect.left;
-    int32_t y = rect.top;
-    int32_t width = rect.right - rect.left;
-    int32_t height = rect.bottom - rect.top;
-
-    int32_t bufferWidth = int32_t(outBuffer->getWidth());
-    int32_t bufferHeight = int32_t(outBuffer->getHeight());
-    if (x + width > bufferWidth) {
-        x = std::min(x, bufferWidth);
-        width = bufferWidth - x;
-    }
-    if (y + height > bufferHeight) {
-        y = std::min(y, bufferHeight);
-        height = bufferHeight - y;
-    }
-
-    auto colorCompare = [tolerance](uint8_t a, uint8_t b) {
-        uint8_t tmp = a >= b ? a - b : b - a;
-        return tmp <= tolerance;
-    };
-    for (int32_t j = 0; j < height; j++) {
-        const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4;
-        for (int32_t i = 0; i < width; i++) {
-            const uint8_t expected[4] = {color.r, color.g, color.b, color.a};
-            EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare))
-                    << "pixel @ (" << x + i << ", " << y + j << "): "
-                    << "expected (" << color << "), "
-                    << "got (" << Color{src[0], src[1], src[2], src[3]} << ")";
-            src += 4;
-        }
-    }
-}
-
-} // anonymous namespace
-
-using Transaction = SurfaceComposerClient::Transaction;
-
-// Fill an RGBA_8888 formatted surface with a single color.
-static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b,
-                             bool unlock = true) {
-    ANativeWindow_Buffer outBuffer;
-    sp<Surface> s = sc->getSurface();
-    ASSERT_TRUE(s != nullptr);
-    ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
-    uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
-    for (int y = 0; y < outBuffer.height; y++) {
-        for (int x = 0; x < outBuffer.width; x++) {
-            uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
-            pixel[0] = r;
-            pixel[1] = g;
-            pixel[2] = b;
-            pixel[3] = 255;
-        }
-    }
-    if (unlock) {
-        ASSERT_EQ(NO_ERROR, s->unlockAndPost());
-    }
-}
-
-// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
-// individual pixel values for testing purposes.
-class ScreenCapture : public RefBase {
-public:
-    static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
-        captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
-    }
-
-    static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
-        const auto sf = ComposerService::getComposerService();
-        SurfaceComposerClient::Transaction().apply(true);
-
-        sp<GraphicBuffer> outBuffer;
-        ASSERT_EQ(NO_ERROR, sf->captureScreen(displayToken, &outBuffer, Rect(), 0, 0, false));
-        *sc = std::make_unique<ScreenCapture>(outBuffer);
-    }
-
-    static void captureLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
-                              Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        SurfaceComposerClient::Transaction().apply(true);
-
-        sp<GraphicBuffer> outBuffer;
-        ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale));
-        *sc = std::make_unique<ScreenCapture>(outBuffer);
-    }
-
-    static void captureChildLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
-                                   Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        SurfaceComposerClient::Transaction().apply(true);
-
-        sp<GraphicBuffer> outBuffer;
-        ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale, true));
-        *sc = std::make_unique<ScreenCapture>(outBuffer);
-    }
-
-    static void captureChildLayersExcluding(
-            std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
-            std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> excludeLayers) {
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        SurfaceComposerClient::Transaction().apply(true);
-
-        sp<GraphicBuffer> outBuffer;
-        ASSERT_EQ(NO_ERROR,
-                  sf->captureLayers(parentHandle, &outBuffer, ui::Dataspace::V0_SRGB,
-                                    ui::PixelFormat::RGBA_8888, Rect::EMPTY_RECT, excludeLayers,
-                                    1.0f, true));
-        *sc = std::make_unique<ScreenCapture>(outBuffer);
-    }
-
-    void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
-        ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
-        expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
-    }
-
-    void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
-        ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
-        const bool leftBorder = rect.left > 0;
-        const bool topBorder = rect.top > 0;
-        const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth());
-        const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight());
-
-        if (topBorder) {
-            Rect top(rect.left, rect.top - 1, rect.right, rect.top);
-            if (leftBorder) {
-                top.left -= 1;
-            }
-            if (rightBorder) {
-                top.right += 1;
-            }
-            expectColor(top, color, tolerance);
-        }
-        if (leftBorder) {
-            Rect left(rect.left - 1, rect.top, rect.left, rect.bottom);
-            expectColor(left, color, tolerance);
-        }
-        if (rightBorder) {
-            Rect right(rect.right, rect.top, rect.right + 1, rect.bottom);
-            expectColor(right, color, tolerance);
-        }
-        if (bottomBorder) {
-            Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1);
-            if (leftBorder) {
-                bottom.left -= 1;
-            }
-            if (rightBorder) {
-                bottom.right += 1;
-            }
-            expectColor(bottom, color, tolerance);
-        }
-    }
-
-    void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight,
-                        const Color& bottomLeft, const Color& bottomRight, bool filtered = false,
-                        uint8_t tolerance = 0) {
-        ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0);
-
-        const int32_t centerX = rect.left + (rect.right - rect.left) / 2;
-        const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2;
-        // avoid checking borders due to unspecified filtering behavior
-        const int32_t offsetX = filtered ? 2 : 0;
-        const int32_t offsetY = filtered ? 2 : 0;
-        expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft,
-                    tolerance);
-        expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight,
-                    tolerance);
-        expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft,
-                    tolerance);
-        expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom),
-                    bottomRight, tolerance);
-    }
-
-    void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
-        ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
-        const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
-        if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
-            String8 err(String8::format("pixel @ (%3d, %3d): "
-                                        "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
-                                        x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
-            EXPECT_EQ(String8(), err) << err.string();
-        }
-    }
-
-    void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); }
-
-    void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); }
-
-    void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
-
-    explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
-        mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
-    }
-
-    ~ScreenCapture() { mOutBuffer->unlock(); }
-
-private:
-    sp<GraphicBuffer> mOutBuffer;
-    uint8_t* mPixels = nullptr;
-};
-
-class LayerTransactionTest : public ::testing::Test {
-protected:
-    void SetUp() override {
-        mClient = new SurfaceComposerClient;
-        ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
-
-        ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
-
-        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-        ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed));
-    }
-
-    virtual void TearDown() {
-        mBlackBgSurface = 0;
-        mClient->dispose();
-        mClient = 0;
-    }
-
-    virtual sp<SurfaceControl> createLayer(const sp<SurfaceComposerClient>& client,
-                                           const char* name, uint32_t width, uint32_t height,
-                                           uint32_t flags = 0, SurfaceControl* parent = nullptr,
-                                           PixelFormat format = PIXEL_FORMAT_RGBA_8888) {
-        auto layer = createSurface(client, name, width, height, format, flags, parent);
-
-        Transaction t;
-        t.setLayerStack(layer, mDisplayLayerStack).setLayer(layer, mLayerZBase);
-
-        status_t error = t.apply();
-        if (error != NO_ERROR) {
-            ADD_FAILURE() << "failed to initialize SurfaceControl";
-            layer.clear();
-        }
-
-        return layer;
-    }
-
-    virtual sp<SurfaceControl> createSurface(const sp<SurfaceComposerClient>& client,
-                                             const char* name, uint32_t width, uint32_t height,
-                                             PixelFormat format, uint32_t flags,
-                                             SurfaceControl* parent = nullptr) {
-        auto layer = client->createSurface(String8(name), width, height, format, flags, parent);
-        EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
-        return layer;
-    }
-
-    virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
-                                           uint32_t flags = 0, SurfaceControl* parent = nullptr,
-                                           PixelFormat format = PIXEL_FORMAT_RGBA_8888) {
-        return createLayer(mClient, name, width, height, flags, parent, format);
-    }
-
-    sp<SurfaceControl> createColorLayer(const char* name, const Color& color,
-                                        SurfaceControl* parent = nullptr) {
-        auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */,
-                                        PIXEL_FORMAT_RGBA_8888,
-                                        ISurfaceComposerClient::eFXSurfaceColor, parent);
-        asTransaction([&](Transaction& t) {
-            t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f});
-            t.setAlpha(colorLayer, color.a / 255.0f);
-        });
-        return colorLayer;
-    }
-
-    ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
-        // wait for previous transactions (such as setSize) to complete
-        Transaction().apply(true);
-
-        ANativeWindow_Buffer buffer = {};
-        EXPECT_EQ(NO_ERROR, layer->getSurface()->lock(&buffer, nullptr));
-
-        return buffer;
-    }
-
-    void postBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
-        ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost());
-
-        // wait for the newly posted buffer to be latched
-        waitForLayerBuffers();
-    }
-
-    virtual void fillBufferQueueLayerColor(const sp<SurfaceControl>& layer, const Color& color,
-                                           int32_t bufferWidth, int32_t bufferHeight) {
-        ANativeWindow_Buffer buffer;
-        ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
-        fillANativeWindowBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color);
-        postBufferQueueLayerBuffer(layer);
-    }
-
-    virtual void fillBufferStateLayerColor(const sp<SurfaceControl>& layer, const Color& color,
-                                           int32_t bufferWidth, int32_t bufferHeight) {
-        sp<GraphicBuffer> buffer =
-                new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
-                                  BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                          BufferUsage::COMPOSER_OVERLAY,
-                                  "test");
-        fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color);
-        Transaction().setBuffer(layer, buffer).apply();
-    }
-
-    void fillLayerColor(uint32_t mLayerType, const sp<SurfaceControl>& layer, const Color& color,
-                        int32_t bufferWidth, int32_t bufferHeight) {
-        switch (mLayerType) {
-            case ISurfaceComposerClient::eFXSurfaceBufferQueue:
-                fillBufferQueueLayerColor(layer, color, bufferWidth, bufferHeight);
-                break;
-            case ISurfaceComposerClient::eFXSurfaceBufferState:
-                fillBufferStateLayerColor(layer, color, bufferWidth, bufferHeight);
-                break;
-            default:
-                ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType;
-        }
-    }
-
-    void fillLayerQuadrant(uint32_t mLayerType, const sp<SurfaceControl>& layer,
-                           int32_t bufferWidth, int32_t bufferHeight, const Color& topLeft,
-                           const Color& topRight, const Color& bottomLeft,
-                           const Color& bottomRight) {
-        switch (mLayerType) {
-            case ISurfaceComposerClient::eFXSurfaceBufferQueue:
-                fillBufferQueueLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight,
-                                             bottomLeft, bottomRight);
-                break;
-            case ISurfaceComposerClient::eFXSurfaceBufferState:
-                fillBufferStateLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight,
-                                             bottomLeft, bottomRight);
-                break;
-            default:
-                ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType;
-        }
-    }
-
-    virtual void fillBufferQueueLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
-                                              int32_t bufferHeight, const Color& topLeft,
-                                              const Color& topRight, const Color& bottomLeft,
-                                              const Color& bottomRight) {
-        ANativeWindow_Buffer buffer;
-        ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
-        ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
-
-        const int32_t halfW = bufferWidth / 2;
-        const int32_t halfH = bufferHeight / 2;
-        fillANativeWindowBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
-        fillANativeWindowBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), topRight);
-        fillANativeWindowBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), bottomLeft);
-        fillANativeWindowBufferColor(buffer, Rect(halfW, halfH, bufferWidth, bufferHeight),
-                                     bottomRight);
-
-        postBufferQueueLayerBuffer(layer);
-    }
-
-    virtual void fillBufferStateLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
-                                              int32_t bufferHeight, const Color& topLeft,
-                                              const Color& topRight, const Color& bottomLeft,
-                                              const Color& bottomRight) {
-        sp<GraphicBuffer> buffer =
-                new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
-                                  BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                          BufferUsage::COMPOSER_OVERLAY,
-                                  "test");
-
-        ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
-
-        const int32_t halfW = bufferWidth / 2;
-        const int32_t halfH = bufferHeight / 2;
-        fillGraphicBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
-        fillGraphicBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), topRight);
-        fillGraphicBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), bottomLeft);
-        fillGraphicBufferColor(buffer, Rect(halfW, halfH, bufferWidth, bufferHeight), bottomRight);
-
-        Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply();
-    }
-
-    std::unique_ptr<ScreenCapture> screenshot() {
-        std::unique_ptr<ScreenCapture> screenshot;
-        ScreenCapture::captureScreen(&screenshot);
-        return screenshot;
-    }
-
-    void asTransaction(const std::function<void(Transaction&)>& exec) {
-        Transaction t;
-        exec(t);
-        t.apply(true);
-    }
-
-    static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
-        static BufferGenerator bufferGenerator;
-        return bufferGenerator.get(outBuffer, outFence);
-    }
-
-    sp<SurfaceComposerClient> mClient;
-
-    sp<IBinder> mDisplay;
-    uint32_t mDisplayWidth;
-    uint32_t mDisplayHeight;
-    uint32_t mDisplayLayerStack;
-    Rect mDisplayRect = Rect::INVALID_RECT;
-
-    // leave room for ~256 layers
-    const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256;
-
-    sp<SurfaceControl> mBlackBgSurface;
-    bool mColorManagementUsed;
-
-private:
-    void SetUpDisplay() {
-        mDisplay = mClient->getInternalDisplayToken();
-        ASSERT_FALSE(mDisplay == nullptr) << "failed to get display";
-
-        // get display width/height
-        DisplayInfo info;
-        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
-        mDisplayWidth = info.w;
-        mDisplayHeight = info.h;
-        mDisplayRect =
-                Rect(static_cast<int32_t>(mDisplayWidth), static_cast<int32_t>(mDisplayHeight));
-
-        // After a new buffer is queued, SurfaceFlinger is notified and will
-        // latch the new buffer on next vsync.  Let's heuristically wait for 3
-        // vsyncs.
-        mBufferPostDelay = int32_t(1e6 / info.fps) * 3;
-
-        mDisplayLayerStack = 0;
-
-        mBlackBgSurface =
-                createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */,
-                              PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
-
-        // set layer stack (b/68888219)
-        Transaction t;
-        t.setDisplayLayerStack(mDisplay, mDisplayLayerStack);
-        t.setCrop_legacy(mBlackBgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight));
-        t.setLayerStack(mBlackBgSurface, mDisplayLayerStack);
-        t.setColor(mBlackBgSurface, half3{0, 0, 0});
-        t.setLayer(mBlackBgSurface, mLayerZBase);
-        t.apply();
-    }
-
-    void waitForLayerBuffers() {
-        // Request an empty transaction to get applied synchronously to ensure the buffer is
-        // latched.
-        Transaction().apply(true);
-        usleep(mBufferPostDelay);
-    }
-
-    int32_t mBufferPostDelay;
-
-    friend class LayerRenderPathTestHarness;
-};
-enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY };
-
-class LayerRenderPathTestHarness {
-public:
-    LayerRenderPathTestHarness(LayerTransactionTest* delegate, RenderPath renderPath)
-          : mDelegate(delegate), mRenderPath(renderPath) {}
-
-    std::unique_ptr<ScreenCapture> getScreenCapture() {
-        switch (mRenderPath) {
-            case RenderPath::SCREENSHOT:
-                return mDelegate->screenshot();
-            case RenderPath::VIRTUAL_DISPLAY:
-
-                const auto mainDisplay = SurfaceComposerClient::getInternalDisplayToken();
-                DisplayInfo mainDisplayInfo;
-                SurfaceComposerClient::getDisplayInfo(mainDisplay, &mainDisplayInfo);
-
-                sp<IBinder> vDisplay;
-                sp<IGraphicBufferProducer> producer;
-                sp<IGraphicBufferConsumer> consumer;
-                sp<BufferItemConsumer> itemConsumer;
-                BufferQueue::createBufferQueue(&producer, &consumer);
-
-                consumer->setConsumerName(String8("Virtual disp consumer"));
-                consumer->setDefaultBufferSize(mainDisplayInfo.w, mainDisplayInfo.h);
-
-                itemConsumer = new BufferItemConsumer(consumer,
-                                                      // Sample usage bits from screenrecord
-                                                      GRALLOC_USAGE_HW_VIDEO_ENCODER |
-                                                              GRALLOC_USAGE_SW_READ_OFTEN);
-
-                vDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"),
-                                                                false /*secure*/);
-
-                SurfaceComposerClient::Transaction t;
-                t.setDisplaySurface(vDisplay, producer);
-                t.setDisplayLayerStack(vDisplay, 0);
-                t.setDisplayProjection(vDisplay, mainDisplayInfo.orientation,
-                                       Rect(mainDisplayInfo.viewportW, mainDisplayInfo.viewportH),
-                                       Rect(mainDisplayInfo.w, mainDisplayInfo.h));
-                t.apply();
-                SurfaceComposerClient::Transaction().apply(true);
-                BufferItem item;
-                itemConsumer->acquireBuffer(&item, 0, true);
-                auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer);
-                itemConsumer->releaseBuffer(item);
-                SurfaceComposerClient::destroyDisplay(vDisplay);
-                return sc;
-        }
-    }
-
-protected:
-    LayerTransactionTest* mDelegate;
-    RenderPath mRenderPath;
-};
-
-class LayerTypeTransactionHarness : public LayerTransactionTest {
-public:
-    LayerTypeTransactionHarness(uint32_t layerType) : mLayerType(layerType) {}
-
-    sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
-                                   uint32_t flags = 0, SurfaceControl* parent = nullptr,
-                                   PixelFormat format = PIXEL_FORMAT_RGBA_8888) {
-        // if the flags already have a layer type specified, return an error
-        if (flags & ISurfaceComposerClient::eFXSurfaceMask) {
-            return nullptr;
-        }
-        return LayerTransactionTest::createLayer(name, width, height, flags | mLayerType, parent,
-                                                 format);
-    }
-
-    void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color, int32_t bufferWidth,
-                        int32_t bufferHeight) {
-        ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerColor(mLayerType, layer, color,
-                                                                     bufferWidth, bufferHeight));
-    }
-
-    void fillLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
-                           int32_t bufferHeight, const Color& topLeft, const Color& topRight,
-                           const Color& bottomLeft, const Color& bottomRight) {
-        ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerQuadrant(mLayerType, layer,
-                                                                        bufferWidth, bufferHeight,
-                                                                        topLeft, topRight,
-                                                                        bottomLeft, bottomRight));
-    }
-
-protected:
-    uint32_t mLayerType;
-};
-
-class LayerTypeTransactionTest : public LayerTypeTransactionHarness,
-                                 public ::testing::WithParamInterface<uint32_t> {
-public:
-    LayerTypeTransactionTest() : LayerTypeTransactionHarness(GetParam()) {}
-};
-
-class LayerTypeAndRenderTypeTransactionTest
-      : public LayerTypeTransactionHarness,
-        public ::testing::WithParamInterface<std::tuple<uint32_t, RenderPath>> {
-public:
-    LayerTypeAndRenderTypeTransactionTest()
-          : LayerTypeTransactionHarness(std::get<0>(GetParam())),
-            mRenderPathHarness(LayerRenderPathTestHarness(this, std::get<1>(GetParam()))) {}
-
-    std::unique_ptr<ScreenCapture> getScreenCapture() {
-        return mRenderPathHarness.getScreenCapture();
-    }
-
-protected:
-    LayerRenderPathTestHarness mRenderPathHarness;
-};
-
-// Environment for starting up binder threads. This is required for testing
-// virtual displays, as BufferQueue parameters may be queried over binder.
-class BinderEnvironment : public ::testing::Environment {
-public:
-    void SetUp() override { ProcessState::self()->startThreadPool(); }
-};
-
-::testing::Environment* const binderEnv =
-        ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
-
-class LayerRenderTypeTransactionTest : public LayerTransactionTest,
-                                       public ::testing::WithParamInterface<RenderPath> {
-public:
-    LayerRenderTypeTransactionTest() : mHarness(LayerRenderPathTestHarness(this, GetParam())) {}
-
-    std::unique_ptr<ScreenCapture> getScreenCapture() { return mHarness.getScreenCapture(); }
-    void setRelativeZBasicHelper(uint32_t layerType);
-    void setRelativeZGroupHelper(uint32_t layerType);
-    void setAlphaBasicHelper(uint32_t layerType);
-    void setBackgroundColorHelper(uint32_t layerType, bool priorColor, bool bufferFill, float alpha,
-                                  Color finalColor);
-
-protected:
-    LayerRenderPathTestHarness mHarness;
-};
-
-INSTANTIATE_TEST_CASE_P(
-        LayerTypeAndRenderTypeTransactionTests, LayerTypeAndRenderTypeTransactionTest,
-        ::testing::Combine(
-                ::testing::Values(
-                        static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
-                        static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)),
-                ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT)));
-
-INSTANTIATE_TEST_CASE_P(LayerRenderTypeTransactionTests, LayerRenderTypeTransactionTest,
-                        ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT));
-
-INSTANTIATE_TEST_CASE_P(
-        LayerTypeTransactionTests, LayerTypeTransactionTest,
-        ::testing::Values(static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
-                          static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)));
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionBasic_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    {
-        SCOPED_TRACE("default position");
-        const Rect rect(0, 0, 32, 32);
-        auto shot = getScreenCapture();
-        shot->expectColor(rect, Color::RED);
-        shot->expectBorder(rect, Color::BLACK);
-    }
-
-    Transaction().setPosition(layer, 5, 10).apply();
-    {
-        SCOPED_TRACE("new position");
-        const Rect rect(5, 10, 37, 42);
-        auto shot = getScreenCapture();
-        shot->expectColor(rect, Color::RED);
-        shot->expectBorder(rect, Color::BLACK);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionRounding_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    // GLES requires only 4 bits of subpixel precision during rasterization
-    // XXX GLES composition does not match HWC composition due to precision
-    // loss (b/69315223)
-    const float epsilon = 1.0f / 16.0f;
-    Transaction().setPosition(layer, 0.5f - epsilon, 0.5f - epsilon).apply();
-    {
-        SCOPED_TRACE("rounding down");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    }
-
-    Transaction().setPosition(layer, 0.5f + epsilon, 0.5f + epsilon).apply();
-    {
-        SCOPED_TRACE("rounding up");
-        getScreenCapture()->expectColor(Rect(1, 1, 33, 33), Color::RED);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionOutOfBounds_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    Transaction().setPosition(layer, -32, -32).apply();
-    {
-        SCOPED_TRACE("negative coordinates");
-        getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
-    }
-
-    Transaction().setPosition(layer, mDisplayWidth, mDisplayHeight).apply();
-    {
-        SCOPED_TRACE("positive coordinates");
-        getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionPartiallyOutOfBounds_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    // partially out of bounds
-    Transaction().setPosition(layer, -30, -30).apply();
-    {
-        SCOPED_TRACE("negative coordinates");
-        getScreenCapture()->expectColor(Rect(0, 0, 2, 2), Color::RED);
-    }
-
-    Transaction().setPosition(layer, mDisplayWidth - 2, mDisplayHeight - 2).apply();
-    {
-        SCOPED_TRACE("positive coordinates");
-        getScreenCapture()->expectColor(Rect(mDisplayWidth - 2, mDisplayHeight - 2, mDisplayWidth,
-                                             mDisplayHeight),
-                                        Color::RED);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionWithResize_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    // setPosition is applied immediately by default, with or without resize
-    // pending
-    Transaction().setPosition(layer, 5, 10).setSize(layer, 64, 64).apply();
-    {
-        SCOPED_TRACE("resize pending");
-        auto shot = getScreenCapture();
-        const Rect rect(5, 10, 37, 42);
-        shot->expectColor(rect, Color::RED);
-        shot->expectBorder(rect, Color::BLACK);
-    }
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
-    {
-        SCOPED_TRACE("resize applied");
-        getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResize_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    // request setPosition to be applied with the next resize
-    Transaction().setPosition(layer, 5, 10).setGeometryAppliesWithResize(layer).apply();
-    {
-        SCOPED_TRACE("new position pending");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    }
-
-    Transaction().setPosition(layer, 15, 20).apply();
-    {
-        SCOPED_TRACE("pending new position modified");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    }
-
-    Transaction().setSize(layer, 64, 64).apply();
-    {
-        SCOPED_TRACE("resize pending");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    }
-
-    // finally resize and latch the buffer
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
-    {
-        SCOPED_TRACE("new position applied");
-        getScreenCapture()->expectColor(Rect(15, 20, 79, 84), Color::RED);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResizeScaleToWindow_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    // setPosition is not immediate even with SCALE_TO_WINDOW override
-    Transaction()
-            .setPosition(layer, 5, 10)
-            .setSize(layer, 64, 64)
-            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
-            .setGeometryAppliesWithResize(layer)
-            .apply();
-    {
-        SCOPED_TRACE("new position pending");
-        getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED);
-    }
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
-    {
-        SCOPED_TRACE("new position applied");
-        getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    Transaction().setSize(layer, 64, 64).apply();
-    {
-        SCOPED_TRACE("resize pending");
-        auto shot = getScreenCapture();
-        const Rect rect(0, 0, 32, 32);
-        shot->expectColor(rect, Color::RED);
-        shot->expectBorder(rect, Color::BLACK);
-    }
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
-    {
-        SCOPED_TRACE("resize applied");
-        auto shot = getScreenCapture();
-        const Rect rect(0, 0, 64, 64);
-        shot->expectColor(rect, Color::RED);
-        shot->expectBorder(rect, Color::BLACK);
-    }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetSizeInvalid) {
-    // cannot test robustness against invalid sizes (zero or really huge)
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetSizeWithScaleToWindow_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    // setSize is immediate with SCALE_TO_WINDOW, unlike setPosition
-    Transaction()
-            .setSize(layer, 64, 64)
-            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
-            .apply();
-    getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED);
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZBasic) {
-    sp<SurfaceControl> layerR;
-    sp<SurfaceControl> layerG;
-    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
-
-    Transaction().setLayer(layerR, mLayerZBase + 1).apply();
-    {
-        SCOPED_TRACE("layerR");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    }
-
-    Transaction().setLayer(layerG, mLayerZBase + 2).apply();
-    {
-        SCOPED_TRACE("layerG");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
-    }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZNegative) {
-    sp<SurfaceControl> parent =
-            LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
-                                              ISurfaceComposerClient::eFXSurfaceContainer);
-    Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
-    sp<SurfaceControl> layerR;
-    sp<SurfaceControl> layerG;
-    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
-
-    Transaction()
-            .reparent(layerR, parent->getHandle())
-            .reparent(layerG, parent->getHandle())
-            .apply();
-    Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply();
-    {
-        SCOPED_TRACE("layerR");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    }
-
-    Transaction().setLayer(layerR, -3).apply();
-    {
-        SCOPED_TRACE("layerG");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
-    }
-}
-
-void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) {
-    sp<SurfaceControl> layerR;
-    sp<SurfaceControl> layerG;
-    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32, layerType));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32, layerType));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32));
-
-    switch (layerType) {
-        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
-            Transaction()
-                    .setPosition(layerG, 16, 16)
-                    .setRelativeLayer(layerG, layerR->getHandle(), 1)
-                    .apply();
-            break;
-        case ISurfaceComposerClient::eFXSurfaceBufferState:
-            Transaction()
-                    .setFrame(layerR, Rect(0, 0, 32, 32))
-                    .setFrame(layerG, Rect(16, 16, 48, 48))
-                    .setRelativeLayer(layerG, layerR->getHandle(), 1)
-                    .apply();
-            break;
-        default:
-            ASSERT_FALSE(true) << "Unsupported layer type";
-    }
-    {
-        SCOPED_TRACE("layerG above");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
-        shot->expectColor(Rect(16, 16, 48, 48), Color::GREEN);
-    }
-
-    Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).apply();
-    {
-        SCOPED_TRACE("layerG below");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
-        shot->expectColor(Rect(32, 32, 48, 48), Color::GREEN);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferQueue) {
-    ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferState) {
-    ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
-}
-
-TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) {
-    sp<SurfaceControl> parent =
-            LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
-                                              ISurfaceComposerClient::eFXSurfaceContainer);
-    Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
-    sp<SurfaceControl> layerR;
-    sp<SurfaceControl> layerG;
-    sp<SurfaceControl> layerB;
-    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE, 32, 32));
-
-    Transaction()
-            .reparent(layerB, parent->getHandle())
-            .apply();
-
-    // layerR = mLayerZBase, layerG = layerR - 1, layerB = -2
-    Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).setLayer(layerB, -2).apply();
-
-    std::unique_ptr<ScreenCapture> screenshot;
-    // only layerB is in this range
-    sp<IBinder> parentHandle = parent->getHandle();
-    ScreenCapture::captureLayers(&screenshot, parentHandle, Rect(0, 0, 32, 32));
-    screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
-}
-
-TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) {
-    sp<SurfaceControl> parent =
-            LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
-                                              ISurfaceComposerClient::eFXSurfaceColor);
-
-    sp<SurfaceControl> childLayer;
-    ASSERT_NO_FATAL_FAILURE(
-            childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
-                                                           0 /* buffer height */,
-                                                           ISurfaceComposerClient::eFXSurfaceColor,
-                                                           parent.get()));
-    Transaction()
-            .setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
-            .setColor(parent, half3{0.0f, 0.0f, 0.0f})
-            .show(childLayer)
-            .show(parent)
-            .setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight))
-            .setCrop_legacy(childLayer, Rect(0, 0, 20, 30))
-            .apply();
-
-    Transaction()
-            .setRelativeLayer(childLayer, parent->getHandle(), -1)
-            .setLayer(childLayer, 1)
-            .apply();
-
-    {
-        SCOPED_TRACE("setLayer above");
-        // Set layer should get applied and place the child above.
-        std::unique_ptr<ScreenCapture> screenshot;
-        ScreenCapture::captureScreen(&screenshot);
-        screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED);
-    }
-
-    Transaction()
-            .setLayer(childLayer, 1)
-            .setRelativeLayer(childLayer, parent->getHandle(), -1)
-            .apply();
-
-    {
-        SCOPED_TRACE("setRelative below");
-        // Set relative layer should get applied and place the child below.
-        std::unique_ptr<ScreenCapture> screenshot;
-        ScreenCapture::captureScreen(&screenshot);
-        screenshot->expectColor(Rect(0, 0, 20, 30), Color::BLACK);
-    }
-}
-
-TEST_P(LayerTypeTransactionTest, HideRelativeParentHidesLayer) {
-    sp<SurfaceControl> parent =
-            LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
-                                              ISurfaceComposerClient::eFXSurfaceColor);
-    sp<SurfaceControl> relativeParent =
-            LayerTransactionTest::createLayer("RelativeParent", 0 /* buffer width */,
-                    0 /* buffer height */, ISurfaceComposerClient::eFXSurfaceColor);
-
-    sp<SurfaceControl> childLayer;
-    ASSERT_NO_FATAL_FAILURE(
-            childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
-                                                           0 /* buffer height */,
-                                                           ISurfaceComposerClient::eFXSurfaceColor,
-                                                           parent.get()));
-    Transaction()
-            .setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
-            .setColor(parent, half3{0.0f, 0.0f, 0.0f})
-            .setColor(relativeParent, half3{0.0f, 1.0f, 0.0f})
-            .show(childLayer)
-            .show(parent)
-            .show(relativeParent)
-            .setLayer(parent, mLayerZBase - 1)
-            .setLayer(relativeParent, mLayerZBase)
-            .apply();
-
-    Transaction()
-            .setRelativeLayer(childLayer, relativeParent->getHandle(), 1)
-            .apply();
-
-    {
-        SCOPED_TRACE("setLayer above");
-        // Set layer should get applied and place the child above.
-        std::unique_ptr<ScreenCapture> screenshot;
-        ScreenCapture::captureScreen(&screenshot);
-        screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED);
-    }
-
-    Transaction()
-        .hide(relativeParent)
-        .apply();
-
-    {
-        SCOPED_TRACE("hide relative parent");
-        // The relative should no longer be visible.
-        std::unique_ptr<ScreenCapture> screenshot;
-        ScreenCapture::captureScreen(&screenshot);
-        screenshot->expectColor(Rect(0, 0, 20, 30), Color::BLACK);
-    }
-}
-
-void LayerRenderTypeTransactionTest::setRelativeZGroupHelper(uint32_t layerType) {
-    sp<SurfaceControl> layerR;
-    sp<SurfaceControl> layerG;
-    sp<SurfaceControl> layerB;
-    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test", 32, 32, layerType));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test", 32, 32, layerType));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test", 32, 32, layerType));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerB, Color::BLUE, 32, 32));
-
-    // layerR = 0, layerG = layerR + 3, layerB = 2
-    switch (layerType) {
-        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
-            Transaction()
-                    .setPosition(layerG, 8, 8)
-                    .setRelativeLayer(layerG, layerR->getHandle(), 3)
-                    .setPosition(layerB, 16, 16)
-                    .setLayer(layerB, mLayerZBase + 2)
-                    .apply();
-            break;
-        case ISurfaceComposerClient::eFXSurfaceBufferState:
-            Transaction()
-                    .setFrame(layerR, Rect(0, 0, 32, 32))
-                    .setFrame(layerG, Rect(8, 8, 40, 40))
-                    .setRelativeLayer(layerG, layerR->getHandle(), 3)
-                    .setFrame(layerB, Rect(16, 16, 48, 48))
-                    .setLayer(layerB, mLayerZBase + 2)
-                    .apply();
-            break;
-        default:
-            ASSERT_FALSE(true) << "Unsupported layer type";
-    }
-
-    {
-        SCOPED_TRACE("(layerR < layerG) < layerB");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
-        shot->expectColor(Rect(8, 8, 16, 16), Color::GREEN);
-        shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
-    }
-
-    // layerR = 4, layerG = layerR + 3, layerB = 2
-    Transaction().setLayer(layerR, mLayerZBase + 4).apply();
-    {
-        SCOPED_TRACE("layerB < (layerR < layerG)");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
-        shot->expectColor(Rect(8, 8, 40, 40), Color::GREEN);
-        shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
-    }
-
-    // layerR = 4, layerG = layerR - 3, layerB = 2
-    Transaction().setRelativeLayer(layerG, layerR->getHandle(), -3).apply();
-    {
-        SCOPED_TRACE("layerB < (layerG < layerR)");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
-        shot->expectColor(Rect(32, 32, 40, 40), Color::GREEN);
-        shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
-    }
-
-    // restore to absolute z
-    // layerR = 4, layerG = 0, layerB = 2
-    Transaction().setLayer(layerG, mLayerZBase).apply();
-    {
-        SCOPED_TRACE("layerG < layerB < layerR");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
-        shot->expectColor(Rect(32, 32, 48, 48), Color::BLUE);
-    }
-
-    // layerR should not affect layerG anymore
-    // layerR = 1, layerG = 0, layerB = 2
-    Transaction().setLayer(layerR, mLayerZBase + 1).apply();
-    {
-        SCOPED_TRACE("layerG < layerR < layerB");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
-        shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferQueue) {
-    ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferState) {
-    ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetRelativeZBug64572777) {
-    sp<SurfaceControl> layerR;
-    sp<SurfaceControl> layerG;
-
-    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
-
-    Transaction()
-            .setPosition(layerG, 16, 16)
-            .setRelativeLayer(layerG, layerR->getHandle(), 1)
-            .apply();
-
-    layerG.clear();
-    // layerG should have been removed
-    getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsHidden) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
-
-    Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply();
-    {
-        SCOPED_TRACE("layer hidden");
-        getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
-    }
-
-    Transaction().setFlags(layer, 0, layer_state_t::eLayerHidden).apply();
-    {
-        SCOPED_TRACE("layer shown");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsOpaque) {
-    const Color translucentRed = {100, 0, 0, 100};
-    sp<SurfaceControl> layerR;
-    sp<SurfaceControl> layerG;
-    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, translucentRed, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
-
-    Transaction()
-            .setLayer(layerR, mLayerZBase + 1)
-            .setFlags(layerR, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque)
-            .apply();
-    {
-        SCOPED_TRACE("layerR opaque");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, 0, 0, 255});
-    }
-
-    Transaction().setFlags(layerR, 0, layer_state_t::eLayerOpaque).apply();
-    {
-        SCOPED_TRACE("layerR translucent");
-        const uint8_t g = uint8_t(255 - translucentRed.a);
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, g, 0, 255});
-    }
-}
-
-TEST_P(LayerTypeTransactionTest, SetFlagsSecure) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
-
-    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
-    sp<GraphicBuffer> outBuffer;
-    Transaction()
-            .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
-            .apply(true);
-    ASSERT_EQ(PERMISSION_DENIED,
-              composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
-
-    Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true);
-    ASSERT_EQ(NO_ERROR,
-              composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
-}
-
-/** RAII Wrapper around get/seteuid */
-class UIDFaker {
-    uid_t oldId;
-public:
-    UIDFaker(uid_t uid) {
-        oldId = geteuid();
-        seteuid(uid);
-    }
-    ~UIDFaker() {
-        seteuid(oldId);
-    }
-};
-
-TEST_F(LayerTransactionTest, SetFlagsSecureEUidSystem) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    sp<ISurfaceComposer> composer = ComposerService::getComposerService();
-    sp<GraphicBuffer> outBuffer;
-    Transaction()
-            .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
-            .apply(true);
-    ASSERT_EQ(PERMISSION_DENIED,
-              composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
-
-    UIDFaker f(AID_SYSTEM);
-
-    // By default the system can capture screenshots with secure layers but they
-    // will be blacked out
-    ASSERT_EQ(NO_ERROR,
-              composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
-
-    {
-        SCOPED_TRACE("as system");
-        auto shot = screenshot();
-        shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
-    }
-
-    // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able
-    // to receive them...we are expected to take care with the results.
-    bool outCapturedSecureLayers;
-    ASSERT_EQ(NO_ERROR,
-              composer->captureScreen(mDisplay, &outBuffer, outCapturedSecureLayers,
-                                      ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), 0,
-                                      0, false, ISurfaceComposer::eRotateNone, true));
-    ASSERT_EQ(true, outCapturedSecureLayers);
-    ScreenCapture sc(outBuffer);
-    sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferQueue) {
-    const Rect top(0, 0, 32, 16);
-    const Rect bottom(0, 16, 32, 32);
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-
-    ANativeWindow_Buffer buffer;
-    ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
-    ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, top, Color::TRANSPARENT));
-    ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, bottom, Color::RED));
-    // setTransparentRegionHint always applies to the following buffer
-    Transaction().setTransparentRegionHint(layer, Region(top)).apply();
-    ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
-    {
-        SCOPED_TRACE("top transparent");
-        auto shot = getScreenCapture();
-        shot->expectColor(top, Color::BLACK);
-        shot->expectColor(bottom, Color::RED);
-    }
-
-    Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
-    {
-        SCOPED_TRACE("transparent region hint pending");
-        auto shot = getScreenCapture();
-        shot->expectColor(top, Color::BLACK);
-        shot->expectColor(bottom, Color::RED);
-    }
-
-    ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
-    ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, top, Color::RED));
-    ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, bottom, Color::TRANSPARENT));
-    ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
-    {
-        SCOPED_TRACE("bottom transparent");
-        auto shot = getScreenCapture();
-        shot->expectColor(top, Color::RED);
-        shot->expectColor(bottom, Color::BLACK);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState) {
-    const Rect top(0, 0, 32, 16);
-    const Rect bottom(0, 16, 32, 32);
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY,
-                              "test");
-
-    ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, top, Color::TRANSPARENT));
-    ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, bottom, Color::RED));
-    Transaction()
-            .setTransparentRegionHint(layer, Region(top))
-            .setBuffer(layer, buffer)
-            .setFrame(layer, Rect(0, 0, 32, 32))
-            .apply();
-    {
-        SCOPED_TRACE("top transparent");
-        auto shot = getScreenCapture();
-        shot->expectColor(top, Color::BLACK);
-        shot->expectColor(bottom, Color::RED);
-    }
-
-    Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
-    {
-        SCOPED_TRACE("transparent region hint intermediate");
-        auto shot = getScreenCapture();
-        shot->expectColor(top, Color::BLACK);
-        shot->expectColor(bottom, Color::BLACK);
-    }
-
-    buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                               BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                       BufferUsage::COMPOSER_OVERLAY,
-                               "test");
-
-    ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, top, Color::RED));
-    ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, bottom, Color::TRANSPARENT));
-    Transaction().setBuffer(layer, buffer).apply();
-    {
-        SCOPED_TRACE("bottom transparent");
-        auto shot = getScreenCapture();
-        shot->expectColor(top, Color::RED);
-        shot->expectColor(bottom, Color::BLACK);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferQueue) {
-    sp<SurfaceControl> layerTransparent;
-    sp<SurfaceControl> layerR;
-    ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-
-    // check that transparent region hint is bound by the layer size
-    Transaction()
-            .setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
-            .setPosition(layerR, 16, 16)
-            .setLayer(layerR, mLayerZBase + 1)
-            .apply();
-    ASSERT_NO_FATAL_FAILURE(
-            fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layerR, Color::RED, 32, 32));
-    getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferState) {
-    sp<SurfaceControl> layerTransparent;
-    sp<SurfaceControl> layerR;
-    ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(
-            layerR = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    // check that transparent region hint is bound by the layer size
-    Transaction()
-            .setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
-            .setFrame(layerR, Rect(16, 16, 48, 48))
-            .setLayer(layerR, mLayerZBase + 1)
-            .apply();
-    ASSERT_NO_FATAL_FAILURE(
-            fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layerR, Color::RED, 32, 32));
-    getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
-}
-
-void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) {
-    sp<SurfaceControl> layer1;
-    sp<SurfaceControl> layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32, layerType));
-    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer("test 2", 32, 32, layerType));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer1, {64, 0, 0, 255}, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer2, {0, 64, 0, 255}, 32, 32));
-
-    switch (layerType) {
-        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
-            Transaction()
-                    .setAlpha(layer1, 0.25f)
-                    .setAlpha(layer2, 0.75f)
-                    .setPosition(layer2, 16, 0)
-                    .setLayer(layer2, mLayerZBase + 1)
-                    .apply();
-            break;
-        case ISurfaceComposerClient::eFXSurfaceBufferState:
-            Transaction()
-                    .setAlpha(layer1, 0.25f)
-                    .setAlpha(layer2, 0.75f)
-                    .setFrame(layer1, Rect(0, 0, 32, 32))
-                    .setFrame(layer2, Rect(16, 0, 48, 32))
-                    .setLayer(layer2, mLayerZBase + 1)
-                    .apply();
-            break;
-        default:
-            ASSERT_FALSE(true) << "Unsupported layer type";
-    }
-    {
-        auto shot = getScreenCapture();
-        uint8_t r = 16; // 64 * 0.25f
-        uint8_t g = 48; // 64 * 0.75f
-        shot->expectColor(Rect(0, 0, 16, 32), {r, 0, 0, 255});
-        shot->expectColor(Rect(32, 0, 48, 32), {0, g, 0, 255});
-
-        r /= 4; // r * (1.0f - 0.75f)
-        shot->expectColor(Rect(16, 0, 32, 32), {r, g, 0, 255});
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferQueue) {
-    ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferState) {
-    ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetAlphaClamped) {
-    const Color color = {64, 0, 0, 255};
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, color, 32, 32));
-
-    Transaction().setAlpha(layer, 2.0f).apply();
-    {
-        SCOPED_TRACE("clamped to 1.0f");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), color);
-    }
-
-    Transaction().setAlpha(layer, -1.0f).apply();
-    {
-        SCOPED_TRACE("clamped to 0.0f");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
-    }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) {
-    sp<SurfaceControl> layer;
-    const uint8_t size = 64;
-    const uint8_t testArea = 4;
-    const float cornerRadius = 20.0f;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size));
-
-    Transaction()
-            .setCornerRadius(layer, cornerRadius)
-            .apply();
-    {
-        const uint8_t bottom = size - 1;
-        const uint8_t right = size - 1;
-        auto shot = getScreenCapture();
-        // Transparent corners
-        shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK);
-        shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::BLACK);
-        shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
-        shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::BLACK);
-    }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) {
-    sp<SurfaceControl> parent;
-    sp<SurfaceControl> child;
-    const uint8_t size = 64;
-    const uint8_t testArea = 4;
-    const float cornerRadius = 20.0f;
-    ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, size, size));
-    ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2));
-
-    Transaction()
-            .setCornerRadius(parent, cornerRadius)
-            .reparent(child, parent->getHandle())
-            .setPosition(child, 0, size / 2)
-            .apply();
-    {
-        const uint8_t bottom = size - 1;
-        const uint8_t right = size - 1;
-        auto shot = getScreenCapture();
-        // Top edge of child should not have rounded corners because it's translated in the parent
-        shot->expectColor(Rect(0, size / 2, right, static_cast<int>(bottom - cornerRadius)),
-            Color::GREEN);
-        // But bottom edges should have been clipped according to parent bounds
-        shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
-        shot->expectColor(Rect(right - testArea, bottom - testArea, right, bottom), Color::BLACK);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorBasic) {
-    sp<SurfaceControl> bufferLayer;
-    sp<SurfaceControl> colorLayer;
-    ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(colorLayer =
-                                    createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
-                                                ISurfaceComposerClient::eFXSurfaceColor));
-
-    Transaction()
-            .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
-            .setLayer(colorLayer, mLayerZBase + 1)
-            .apply();
-
-    {
-        SCOPED_TRACE("default color");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
-    }
-
-    const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
-    const Color expected = {15, 51, 85, 255};
-    // this is handwavy, but the precison loss scaled by 255 (8-bit per
-    // channel) should be less than one
-    const uint8_t tolerance = 1;
-    Transaction().setColor(colorLayer, color).apply();
-    {
-        SCOPED_TRACE("new color");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
-    }
-}
-
-// RED: Color layer base color and BufferQueueLayer/BufferStateLayer fill
-// BLUE: prior background color
-// GREEN: final background color
-// BLACK: no color or fill
-void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType, bool priorColor,
-                                                              bool bufferFill, float alpha,
-                                                              Color finalColor) {
-    sp<SurfaceControl> layer;
-    int32_t width = 500;
-    int32_t height = 500;
-
-    Color fillColor = Color::RED;
-    Color priorBgColor = Color::BLUE;
-    Color expectedColor = Color::BLACK;
-    switch (layerType) {
-        case ISurfaceComposerClient::eFXSurfaceColor:
-            ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType));
-            Transaction()
-                    .setCrop_legacy(layer, Rect(0, 0, width, height))
-                    .setColor(layer, half3(1.0f, 0, 0))
-                    .apply();
-            expectedColor = fillColor;
-            break;
-        case ISurfaceComposerClient::eFXSurfaceBufferQueue:
-            ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
-            if (bufferFill) {
-                ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, fillColor, width, height));
-                expectedColor = fillColor;
-            }
-            Transaction().setCrop_legacy(layer, Rect(0, 0, width, height)).apply();
-            break;
-        case ISurfaceComposerClient::eFXSurfaceBufferState:
-            ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height, layerType));
-            if (bufferFill) {
-                ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height));
-                expectedColor = fillColor;
-            }
-            Transaction().setFrame(layer, Rect(0, 0, width, height)).apply();
-            break;
-        default:
-            GTEST_FAIL() << "Unknown layer type in setBackgroundColorHelper";
-            return;
-    }
-
-    if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceColor) {
-        Transaction()
-                .setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN)
-                .apply();
-        if (!bufferFill) {
-            expectedColor = priorBgColor;
-        }
-    }
-
-    {
-        SCOPED_TRACE("default before setting background color layer");
-        screenshot()->expectColor(Rect(0, 0, width, height), expectedColor);
-    }
-    Transaction()
-            .setBackgroundColor(layer, half3(0, 1.0f, 0), alpha, ui::Dataspace::UNKNOWN)
-            .apply();
-
-    {
-        auto shot = screenshot();
-        shot->expectColor(Rect(0, 0, width, height), finalColor);
-        shot->expectBorder(Rect(0, 0, width, height), Color::BLACK);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) {
-    bool priorColor = false;
-    bool bufferFill = false;
-    float alpha = 1.0f;
-    Color finalColor = Color::RED;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceColor,
-                                                     priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
-       SetBackgroundColor_BufferQueue_BufferFill_NoPriorColor_Basic) {
-    bool priorColor = false;
-    bool bufferFill = true;
-    float alpha = 1.0f;
-    Color finalColor = Color::RED;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
-                                                     priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
-       SetBackgroundColor_BufferQueue_NoBufferFill_NoPriorColor_Basic) {
-    bool priorColor = false;
-    bool bufferFill = false;
-    float alpha = 1.0f;
-    Color finalColor = Color::GREEN;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
-                                                     priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferQueue_BufferFill_PriorColor_Basic) {
-    bool priorColor = true;
-    bool bufferFill = true;
-    float alpha = 1.0f;
-    Color finalColor = Color::RED;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
-                                                     priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
-       SetBackgroundColor_BufferQueue_NoBufferFill_PriorColor_Basic) {
-    bool priorColor = true;
-    bool bufferFill = false;
-    float alpha = 1.0f;
-    Color finalColor = Color::GREEN;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
-                                                     priorColor, bufferFill, alpha, finalColor));
-}
-TEST_P(LayerRenderTypeTransactionTest,
-       SetBackgroundColor_BufferQueue_NoPriorColor_ZeroAlpha_NoEffect) {
-    bool priorColor = false;
-    bool bufferFill = false;
-    float alpha = 0;
-    Color finalColor = Color::BLACK;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
-                                                     priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
-       SetBackgroundColor_BufferQueue_PriorColor_ZeroAlpha_DeleteBackground) {
-    bool priorColor = true;
-    bool bufferFill = false;
-    float alpha = 0;
-    Color finalColor = Color::BLACK;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
-                                                     priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
-       SetBackgroundColor_BufferState_BufferFill_NoPriorColor_Basic) {
-    bool priorColor = false;
-    bool bufferFill = true;
-    float alpha = 1.0f;
-    Color finalColor = Color::RED;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
-                                                     priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
-       SetBackgroundColor_BufferState_NoBufferFill_NoPriorColor_Basic) {
-    bool priorColor = false;
-    bool bufferFill = false;
-    float alpha = 1.0f;
-    Color finalColor = Color::GREEN;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
-                                                     priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
-       SetBackgroundColor_BufferState_NoBufferFill_PriorColor_Basic) {
-    bool priorColor = true;
-    bool bufferFill = false;
-    float alpha = 1.0f;
-    Color finalColor = Color::GREEN;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
-                                                     priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
-       SetBackgroundColor_BufferState_NoPriorColor_ZeroAlpha_NoEffect) {
-    bool priorColor = false;
-    bool bufferFill = false;
-    float alpha = 0;
-    Color finalColor = Color::BLACK;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
-                                                     priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
-       SetBackgroundColor_BufferState_PriorColor_ZeroAlpha_DeleteBackground) {
-    bool priorColor = true;
-    bool bufferFill = false;
-    float alpha = 0;
-    Color finalColor = Color::BLACK;
-    ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
-                                                     priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) {
-    sp<SurfaceControl> colorLayer;
-    ASSERT_NO_FATAL_FAILURE(colorLayer =
-                                    createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
-                                                ISurfaceComposerClient::eFXSurfaceColor));
-    Transaction()
-            .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
-            .setColor(colorLayer, half3(2.0f, -1.0f, 0.0f))
-            .apply();
-
-    getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) {
-    sp<SurfaceControl> bufferLayer;
-    sp<SurfaceControl> colorLayer;
-    ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(colorLayer =
-                                    createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
-                                                ISurfaceComposerClient::eFXSurfaceColor));
-    Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
-
-    const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
-    const float alpha = 0.25f;
-    const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
-    // this is handwavy, but the precison loss scaled by 255 (8-bit per
-    // channel) should be less than one
-    const uint8_t tolerance = 1;
-    Transaction()
-            .setColor(colorLayer, color)
-            .setAlpha(colorLayer, alpha)
-            .setLayer(colorLayer, mLayerZBase + 1)
-            .apply();
-    getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
-                                    tolerance);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorWithParentAlpha_Bug74220420) {
-    sp<SurfaceControl> bufferLayer;
-    sp<SurfaceControl> parentLayer;
-    sp<SurfaceControl> colorLayer;
-    ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parentWithAlpha", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
-    ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */,
-                                                     0 /* buffer height */,
-                                                     ISurfaceComposerClient::eFXSurfaceColor));
-    Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
-    const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
-    const float alpha = 0.25f;
-    const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
-    // this is handwavy, but the precision loss scaled by 255 (8-bit per
-    // channel) should be less than one
-    const uint8_t tolerance = 1;
-    Transaction()
-            .reparent(colorLayer, parentLayer->getHandle())
-            .setColor(colorLayer, color)
-            .setAlpha(parentLayer, alpha)
-            .setLayer(parentLayer, mLayerZBase + 1)
-            .apply();
-    getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
-                                    tolerance);
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) {
-    sp<SurfaceControl> bufferLayer;
-    ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED, 32, 32));
-
-    // color is ignored
-    Transaction().setColor(bufferLayer, half3(0.0f, 1.0f, 0.0f)).apply();
-    getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetLayerStackBasic) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
-
-    Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
-    {
-        SCOPED_TRACE("non-existing layer stack");
-        getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
-    }
-
-    Transaction().setLayerStack(layer, mDisplayLayerStack).apply();
-    {
-        SCOPED_TRACE("original layer stack");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBufferFormat) {
-    int32_t width = 100;
-    int32_t height = 100;
-    Rect crop = Rect(0, 0, width, height);
-
-    sp<SurfaceControl> behindLayer = createColorLayer("Behind layer", Color::RED);
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", width, height, 0, nullptr, PIXEL_FORMAT_RGBX_8888));
-
-    Transaction()
-            .setLayer(layer, INT32_MAX - 1)
-            .show(layer)
-            .setLayerStack(behindLayer, mDisplayLayerStack)
-            .setCrop_legacy(behindLayer, crop)
-            .setLayer(behindLayer, INT32_MAX - 2)
-            .show(behindLayer)
-            .apply();
-
-    sp<Surface> surface = layer->getSurface();
-
-    sp<GraphicBuffer> buffer =
-            new GraphicBuffer(width, height, PIXEL_FORMAT_RGBX_8888, 1,
-                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY,
-                              "test");
-    ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT));
-
-    if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
-        Surface::attachAndQueueBufferWithDataspace(surface.get(), buffer, ui::Dataspace::V0_SRGB);
-    } else {
-        Transaction().setBuffer(layer, buffer).apply();
-    }
-
-    {
-        SCOPED_TRACE("Buffer Opaque Format");
-        auto shot = screenshot();
-        shot->expectColor(crop, Color::BLACK);
-    }
-
-    buffer = new GraphicBuffer(width, height, PIXEL_FORMAT_RGBA_8888, 1,
-                               BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                       BufferUsage::COMPOSER_OVERLAY,
-                               "test");
-    ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, crop, Color::TRANSPARENT));
-
-    if (mLayerType == ISurfaceComposerClient::eFXSurfaceBufferQueue) {
-        Surface::attachAndQueueBufferWithDataspace(surface.get(), buffer, ui::Dataspace::V0_SRGB);
-    } else {
-        Transaction().setBuffer(layer, buffer).apply();
-    }
-
-    {
-        SCOPED_TRACE("Buffer Transparent Format");
-        auto shot = screenshot();
-        shot->expectColor(crop, Color::RED);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
-                                                         Color::BLUE, Color::WHITE));
-
-    Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 0, 0).apply();
-    {
-        SCOPED_TRACE("IDENTITY");
-        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
-                                           Color::BLUE, Color::WHITE);
-    }
-
-    Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 32, 0).apply();
-    {
-        SCOPED_TRACE("FLIP_H");
-        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED,
-                                           Color::WHITE, Color::BLUE);
-    }
-
-    Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).setPosition(layer, 0, 32).apply();
-    {
-        SCOPED_TRACE("FLIP_V");
-        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE,
-                                           Color::RED, Color::GREEN);
-    }
-
-    Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).setPosition(layer, 32, 0).apply();
-    {
-        SCOPED_TRACE("ROT_90");
-        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED,
-                                           Color::WHITE, Color::GREEN);
-    }
-
-    Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setPosition(layer, 0, 0).apply();
-    {
-        SCOPED_TRACE("SCALE");
-        getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 64), Color::RED, Color::GREEN,
-                                           Color::BLUE, Color::WHITE, true /* filtered */);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
-                                                         Color::BLUE, Color::WHITE));
-
-    Transaction()
-            .setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f)
-            .setFrame(layer, Rect(0, 0, 32, 32))
-            .apply();
-    {
-        SCOPED_TRACE("IDENTITY");
-        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
-                                           Color::BLUE, Color::WHITE);
-    }
-
-    Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply();
-    {
-        SCOPED_TRACE("FLIP_H");
-        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
-                                           Color::BLUE, Color::WHITE);
-    }
-
-    Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply();
-    {
-        SCOPED_TRACE("FLIP_V");
-        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
-                                           Color::BLUE, Color::WHITE);
-    }
-
-    Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply();
-    {
-        SCOPED_TRACE("ROT_90");
-        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
-                                           Color::BLUE, Color::WHITE);
-    }
-
-    Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply();
-    {
-        SCOPED_TRACE("SCALE");
-        getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
-                                           Color::BLUE, Color::WHITE);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixRot45_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
-                                                         Color::BLUE, Color::WHITE));
-
-    const float rot = M_SQRT1_2; // 45 degrees
-    const float trans = M_SQRT2 * 16.0f;
-    Transaction().setMatrix(layer, rot, rot, -rot, rot).setPosition(layer, trans, 0).apply();
-
-    auto shot = getScreenCapture();
-    // check a 8x8 region inside each color
-    auto get8x8Rect = [](int32_t centerX, int32_t centerY) {
-        const int32_t halfL = 4;
-        return Rect(centerX - halfL, centerY - halfL, centerX + halfL, centerY + halfL);
-    };
-    const int32_t unit = int32_t(trans / 2);
-    shot->expectColor(get8x8Rect(2 * unit, 1 * unit), Color::RED);
-    shot->expectColor(get8x8Rect(3 * unit, 2 * unit), Color::GREEN);
-    shot->expectColor(get8x8Rect(1 * unit, 2 * unit), Color::BLUE);
-    shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithResize_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    // setMatrix is applied after any pending resize, unlike setPosition
-    Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply();
-    {
-        SCOPED_TRACE("resize pending");
-        auto shot = getScreenCapture();
-        const Rect rect(0, 0, 32, 32);
-        shot->expectColor(rect, Color::RED);
-        shot->expectBorder(rect, Color::BLACK);
-    }
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
-    {
-        SCOPED_TRACE("resize applied");
-        const Rect rect(0, 0, 128, 128);
-        getScreenCapture()->expectColor(rect, Color::RED);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithScaleToWindow_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    // setMatrix is immediate with SCALE_TO_WINDOW, unlike setPosition
-    Transaction()
-            .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
-            .setSize(layer, 64, 64)
-            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
-            .apply();
-    getScreenCapture()->expectColor(Rect(0, 0, 128, 128), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetOverrideScalingModeBasic_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
-                                                         Color::BLUE, Color::WHITE));
-
-    // XXX SCALE_CROP is not respected; calling setSize and
-    // setOverrideScalingMode in separate transactions does not work
-    // (b/69315456)
-    Transaction()
-            .setSize(layer, 64, 16)
-            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
-            .apply();
-    {
-        SCOPED_TRACE("SCALE_TO_WINDOW");
-        getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN,
-                                           Color::BLUE, Color::WHITE, true /* filtered */);
-    }
-}
-
-TEST_P(LayerTypeTransactionTest, RefreshRateIsInitialized) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-
-    sp<IBinder> handle = layer->getHandle();
-    ASSERT_TRUE(handle != nullptr);
-
-    FrameStats frameStats;
-    mClient->getLayerFrameStats(handle, &frameStats);
-
-    ASSERT_GT(frameStats.refreshPeriodNano, static_cast<nsecs_t>(0));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-    const Rect crop(8, 8, 24, 24);
-
-    Transaction().setCrop_legacy(layer, crop).apply();
-    auto shot = getScreenCapture();
-    shot->expectColor(crop, Color::RED);
-    shot->expectBorder(crop, Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-    const Rect crop(8, 8, 24, 24);
-
-    Transaction().setCrop(layer, crop).apply();
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
-    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    {
-        SCOPED_TRACE("empty rect");
-        Transaction().setCrop_legacy(layer, Rect(8, 8, 8, 8)).apply();
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    }
-
-    {
-        SCOPED_TRACE("negative rect");
-        Transaction().setCrop_legacy(layer, Rect(8, 8, 0, 0)).apply();
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
-    {
-        SCOPED_TRACE("empty rect");
-        Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply();
-        getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
-    }
-
-    {
-        SCOPED_TRACE("negative rect");
-        Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply();
-        getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    Transaction().setCrop_legacy(layer, Rect(-128, -64, 128, 64)).apply();
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
-    sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 64, PIXEL_FORMAT_RGBA_8888, 1,
-                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY,
-                              "test");
-    fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE);
-    fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED);
-
-    Transaction().setFrame(layer, Rect(0, 0, 64, 64)).apply();
-
-    Transaction().setBuffer(layer, buffer).apply();
-
-    // Partially out of bounds in the negative (upper left) direction
-    Transaction().setCrop(layer, Rect(-128, -128, 32, 16)).apply();
-    {
-        SCOPED_TRACE("out of bounds, negative (upper left) direction");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 64, 64), Color::BLUE);
-        shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
-    }
-
-    // Partially out of bounds in the positive (lower right) direction
-    Transaction().setCrop(layer, Rect(0, 16, 128, 128)).apply();
-    {
-        SCOPED_TRACE("out of bounds, positive (lower right) direction");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
-        shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
-    }
-
-    // Fully out of buffer space bounds
-    Transaction().setCrop(layer, Rect(-128, -128, -1, -1)).apply();
-    {
-        SCOPED_TRACE("Fully out of bounds");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 64, 16), Color::BLUE);
-        shot->expectColor(Rect(0, 16, 64, 64), Color::RED);
-        shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    const Point position(32, 32);
-    const Rect crop(8, 8, 24, 24);
-    Transaction().setPosition(layer, position.x, position.y).setCrop_legacy(layer, crop).apply();
-    auto shot = getScreenCapture();
-    shot->expectColor(crop + position, Color::RED);
-    shot->expectBorder(crop + position, Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
-    const Rect frame(32, 32, 64, 64);
-    const Rect crop(8, 8, 24, 24);
-    Transaction().setFrame(layer, frame).setCrop(layer, crop).apply();
-    auto shot = getScreenCapture();
-    shot->expectColor(frame, Color::RED);
-    shot->expectBorder(frame, Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    // crop_legacy is affected by matrix
-    Transaction()
-            .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
-            .setCrop_legacy(layer, Rect(8, 8, 24, 24))
-            .apply();
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
-    shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithResize_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    // setCrop_legacy is applied immediately by default, with or without resize pending
-    Transaction().setCrop_legacy(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
-    {
-        SCOPED_TRACE("resize pending");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
-        shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
-    }
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
-    {
-        SCOPED_TRACE("resize applied");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
-        shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResize_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    // request setCrop_legacy to be applied with the next resize
-    Transaction()
-            .setCrop_legacy(layer, Rect(8, 8, 24, 24))
-            .setGeometryAppliesWithResize(layer)
-            .apply();
-    {
-        SCOPED_TRACE("waiting for next resize");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    }
-
-    Transaction().setCrop_legacy(layer, Rect(4, 4, 12, 12)).apply();
-    {
-        SCOPED_TRACE("pending crop modified");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    }
-
-    Transaction().setSize(layer, 16, 16).apply();
-    {
-        SCOPED_TRACE("resize pending");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-    }
-
-    // finally resize
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
-    {
-        SCOPED_TRACE("new crop applied");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
-        shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResizeScaleToWindow_BufferQueue) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
-    // setCrop_legacy is not immediate even with SCALE_TO_WINDOW override
-    Transaction()
-            .setCrop_legacy(layer, Rect(4, 4, 12, 12))
-            .setSize(layer, 16, 16)
-            .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
-            .setGeometryAppliesWithResize(layer)
-            .apply();
-    {
-        SCOPED_TRACE("new crop pending");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
-        shot->expectBorder(Rect(0, 0, 16, 16), Color::BLACK);
-    }
-
-    // XXX crop is never latched without other geometry change (b/69315677)
-    Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply();
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
-    Transaction().setPosition(layer, 0, 0).apply();
-    {
-        SCOPED_TRACE("new crop applied");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
-        shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-    const Rect frame(8, 8, 24, 24);
-
-    Transaction().setFrame(layer, frame).apply();
-    auto shot = getScreenCapture();
-    shot->expectColor(frame, Color::RED);
-    shot->expectBorder(frame, Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
-    {
-        SCOPED_TRACE("empty rect");
-        Transaction().setFrame(layer, Rect(8, 8, 8, 8)).apply();
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
-    }
-
-    {
-        SCOPED_TRACE("negative rect");
-        Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply();
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10));
-
-    // A parentless layer will default to a frame with the same size as the buffer
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
-    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) {
-    sp<SurfaceControl> parent, child;
-    ASSERT_NO_FATAL_FAILURE(
-            parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
-    Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
-
-    ASSERT_NO_FATAL_FAILURE(
-            child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
-
-    Transaction().reparent(child, parent->getHandle()).apply();
-
-    // A layer will default to the frame of its parent
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
-    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) {
-    sp<SurfaceControl> parent, child;
-    ASSERT_NO_FATAL_FAILURE(parent = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, Color::RED, 32, 32));
-
-    ASSERT_NO_FATAL_FAILURE(
-            child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
-
-    Transaction().reparent(child, parent->getHandle()).apply();
-
-    // A layer will default to the frame of its parent
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
-    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameUpdate_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-    Transaction().setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
-    std::this_thread::sleep_for(500ms);
-
-    Transaction().setFrame(layer, Rect(16, 16, 48, 48)).apply();
-
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
-    shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameOutsideBounds_BufferState) {
-    sp<SurfaceControl> parent, child;
-    ASSERT_NO_FATAL_FAILURE(
-            parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(
-            child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-    Transaction().reparent(child, parent->getHandle()).apply();
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
-    Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
-    Transaction().setFrame(child, Rect(0, 16, 32, 32)).apply();
-
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(0, 0, 32, 16), Color::RED);
-    shot->expectColor(Rect(0, 16, 32, 32), Color::BLUE);
-    shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBufferBasic_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
-    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
-    {
-        SCOPED_TRACE("set buffer 1");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
-        shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-    }
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32));
-
-    {
-        SCOPED_TRACE("set buffer 2");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLUE);
-        shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-    }
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
-    {
-        SCOPED_TRACE("set buffer 3");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
-        shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) {
-    sp<SurfaceControl> layer1;
-    ASSERT_NO_FATAL_FAILURE(
-            layer1 = createLayer("test", 64, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    sp<SurfaceControl> layer2;
-    ASSERT_NO_FATAL_FAILURE(
-            layer2 = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::RED, 64, 64));
-
-    Transaction().setFrame(layer1, Rect(0, 0, 64, 64)).apply();
-    {
-        SCOPED_TRACE("set layer 1 buffer red");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
-    }
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32));
-
-    Transaction().setFrame(layer2, Rect(0, 0, 32, 32)).apply();
-    {
-        SCOPED_TRACE("set layer 2 buffer blue");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
-        shot->expectColor(Rect(0, 32, 64, 64), Color::RED);
-        shot->expectColor(Rect(0, 32, 32, 64), Color::RED);
-    }
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::GREEN, 64, 64));
-    {
-        SCOPED_TRACE("set layer 1 buffer green");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
-        shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
-        shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
-    }
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::WHITE, 32, 32));
-
-    {
-        SCOPED_TRACE("set layer 2 buffer white");
-        auto shot = getScreenCapture();
-        shot->expectColor(Rect(0, 0, 32, 32), Color::WHITE);
-        shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
-        shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
-
-    std::array<sp<GraphicBuffer>, 10> buffers;
-
-    size_t idx = 0;
-    for (auto& buffer : buffers) {
-        buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                                   BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                           BufferUsage::COMPOSER_OVERLAY,
-                                   "test");
-        Color color = colors[idx % colors.size()];
-        fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
-        idx++;
-    }
-
-    // Set each buffer twice. The first time adds it to the cache, the second time tests that the
-    // cache is working.
-    idx = 0;
-    for (auto& buffer : buffers) {
-        for (int i = 0; i < 2; i++) {
-            Transaction().setBuffer(layer, buffer).apply();
-
-            Color color = colors[idx % colors.size()];
-            auto shot = screenshot();
-            shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
-            shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-        }
-        idx++;
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
-
-    std::array<sp<GraphicBuffer>, 70> buffers;
-
-    size_t idx = 0;
-    for (auto& buffer : buffers) {
-        buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                                   BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                           BufferUsage::COMPOSER_OVERLAY,
-                                   "test");
-        Color color = colors[idx % colors.size()];
-        fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
-        idx++;
-    }
-
-    // Set each buffer twice. The first time adds it to the cache, the second time tests that the
-    // cache is working.
-    idx = 0;
-    for (auto& buffer : buffers) {
-        for (int i = 0; i < 2; i++) {
-            Transaction().setBuffer(layer, buffer).apply();
-
-            Color color = colors[idx % colors.size()];
-            auto shot = screenshot();
-            shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
-            shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-        }
-        idx++;
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
-
-    std::array<sp<GraphicBuffer>, 65> buffers;
-
-    size_t idx = 0;
-    for (auto& buffer : buffers) {
-        buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                                   BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                           BufferUsage::COMPOSER_OVERLAY,
-                                   "test");
-        Color color = colors[idx % colors.size()];
-        fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
-        idx++;
-    }
-
-    // Set each buffer twice. The first time adds it to the cache, the second time tests that the
-    // cache is working.
-    idx = 0;
-    for (auto& buffer : buffers) {
-        for (int i = 0; i < 2; i++) {
-            Transaction().setBuffer(layer, buffer).apply();
-
-            Color color = colors[idx % colors.size()];
-            auto shot = screenshot();
-            shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
-            shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-        }
-        if (idx == 0) {
-            buffers[0].clear();
-        }
-        idx++;
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
-                                                         Color::BLUE, Color::WHITE));
-
-    Transaction()
-            .setFrame(layer, Rect(0, 0, 32, 32))
-            .setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90)
-            .apply();
-
-    getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
-                                       Color::GREEN, true /* filtered */);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipH_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
-                                                         Color::BLUE, Color::WHITE));
-
-    Transaction()
-            .setFrame(layer, Rect(0, 0, 32, 32))
-            .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H)
-            .apply();
-
-    getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
-                                       Color::BLUE, true /* filtered */);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipV_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
-                                                         Color::BLUE, Color::WHITE));
-
-    Transaction()
-            .setFrame(layer, Rect(0, 0, 32, 32))
-            .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V)
-            .apply();
-
-    getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
-                                       Color::GREEN, true /* filtered */);
-}
-
-TEST_F(LayerTransactionTest, SetTransformToDisplayInverse_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    Transaction().setTransformToDisplayInverse(layer, false).apply();
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::GREEN, 32, 32));
-
-    Transaction().setTransformToDisplayInverse(layer, true).apply();
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFenceBasic_BufferState) {
-    sp<SurfaceControl> layer;
-    Transaction transaction;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY,
-                              "test");
-    fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
-    sp<Fence> fence;
-    if (getBuffer(nullptr, &fence) != NO_ERROR) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply();
-
-    status_t status = fence->wait(1000);
-    ASSERT_NE(static_cast<status_t>(Fence::Status::Unsignaled), status);
-    std::this_thread::sleep_for(200ms);
-
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
-    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY,
-                              "test");
-    fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
-    sp<Fence> fence = Fence::NO_FENCE;
-
-    Transaction()
-            .setBuffer(layer, buffer)
-            .setAcquireFence(layer, fence)
-            .apply();
-
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
-    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY,
-                              "test");
-    fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
-    Transaction()
-            .setBuffer(layer, buffer)
-            .setDataspace(layer, ui::Dataspace::UNKNOWN)
-            .apply();
-
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
-    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY,
-                              "test");
-    fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
-    HdrMetadata hdrMetadata;
-    hdrMetadata.validTypes = 0;
-    Transaction()
-            .setBuffer(layer, buffer)
-            .setHdrMetadata(layer, hdrMetadata)
-            .apply();
-
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
-    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY,
-                              "test");
-    fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
-    Region region;
-    region.set(32, 32);
-    Transaction()
-            .setBuffer(layer, buffer)
-            .setSurfaceDamageRegion(layer, region)
-            .apply();
-
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
-    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    sp<GraphicBuffer> buffer =
-            new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
-                              BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-                                      BufferUsage::COMPOSER_OVERLAY,
-                              "test");
-    fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
-    Transaction()
-            .setBuffer(layer, buffer)
-            .setApi(layer, NATIVE_WINDOW_API_CPU)
-            .apply();
-
-    auto shot = getScreenCapture();
-    shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
-    shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_F(LayerTransactionTest, SetSidebandStreamNull_BufferState) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(
-            layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    // verify this doesn't cause a crash
-    Transaction().setSidebandStream(layer, nullptr).apply();
-}
-
-TEST_F(LayerTransactionTest, ReparentToSelf) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-    Transaction().reparent(layer, layer->getHandle()).apply();
-
-    {
-        // We expect the transaction to be silently dropped, but for SurfaceFlinger
-        // to still be functioning.
-        SCOPED_TRACE("after reparent to self");
-        const Rect rect(0, 0, 32, 32);
-        auto shot = screenshot();
-        shot->expectColor(rect, Color::RED);
-        shot->expectBorder(rect, Color::BLACK);
-    }
-}
-
-class ColorTransformHelper {
-public:
-    static void DegammaColorSingle(half& s) {
-        if (s <= 0.03928f)
-            s = s / 12.92f;
-        else
-            s = pow((s + 0.055f) / 1.055f, 2.4f);
-    }
-
-    static void DegammaColor(half3& color) {
-        DegammaColorSingle(color.r);
-        DegammaColorSingle(color.g);
-        DegammaColorSingle(color.b);
-    }
-
-    static void GammaColorSingle(half& s) {
-        if (s <= 0.0031308f) {
-            s = s * 12.92f;
-        } else {
-            s = 1.055f * pow(s, (1.0f / 2.4f)) - 0.055f;
-        }
-    }
-
-    static void GammaColor(half3& color) {
-        GammaColorSingle(color.r);
-        GammaColorSingle(color.g);
-        GammaColorSingle(color.b);
-    }
-
-    static void applyMatrix(half3& color, const mat3& mat) {
-        half3 ret = half3(0);
-
-        for (int i = 0; i < 3; i++) {
-            for (int j = 0; j < 3; j++) {
-                ret[i] = ret[i] + color[j] * mat[j][i];
-            }
-        }
-        color = ret;
-    }
-};
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) {
-    sp<SurfaceControl> colorLayer;
-    ASSERT_NO_FATAL_FAILURE(colorLayer =
-                                    createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
-                                                ISurfaceComposerClient::eFXSurfaceColor));
-    Transaction()
-            .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
-            .setLayer(colorLayer, mLayerZBase + 1)
-            .apply();
-    {
-        SCOPED_TRACE("default color");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
-    }
-
-    const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
-    half3 expected = color;
-    mat3 matrix;
-    matrix[0][0] = 0.3; matrix[1][0] = 0.59; matrix[2][0] = 0.11;
-    matrix[0][1] = 0.3; matrix[1][1] = 0.59; matrix[2][1] = 0.11;
-    matrix[0][2] = 0.3; matrix[1][2] = 0.59; matrix[2][2] = 0.11;
-
-    // degamma before applying the matrix
-    if (mColorManagementUsed) {
-        ColorTransformHelper::DegammaColor(expected);
-    }
-
-    ColorTransformHelper::applyMatrix(expected, matrix);
-
-    if (mColorManagementUsed) {
-        ColorTransformHelper::GammaColor(expected);
-    }
-
-    const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
-                                 uint8_t(expected.b * 255), 255};
-
-    // this is handwavy, but the precison loss scaled by 255 (8-bit per
-    // channel) should be less than one
-    const uint8_t tolerance = 1;
-
-    Transaction().setColor(colorLayer, color)
-        .setColorTransform(colorLayer, matrix, vec3()).apply();
-    {
-        SCOPED_TRACE("new color");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnParent) {
-    sp<SurfaceControl> parentLayer;
-    sp<SurfaceControl> colorLayer;
-    ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
-                                                      0 /* buffer height */,
-                                                      ISurfaceComposerClient::eFXSurfaceContainer));
-    ASSERT_NO_FATAL_FAILURE(
-            colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
-                                     ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get()));
-
-    Transaction()
-            .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
-            .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
-            .setLayer(parentLayer, mLayerZBase + 1)
-            .apply();
-    {
-        SCOPED_TRACE("default color");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
-    }
-
-    const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
-    half3 expected = color;
-    mat3 matrix;
-    matrix[0][0] = 0.3; matrix[1][0] = 0.59; matrix[2][0] = 0.11;
-    matrix[0][1] = 0.3; matrix[1][1] = 0.59; matrix[2][1] = 0.11;
-    matrix[0][2] = 0.3; matrix[1][2] = 0.59; matrix[2][2] = 0.11;
-
-    // degamma before applying the matrix
-    if (mColorManagementUsed) {
-        ColorTransformHelper::DegammaColor(expected);
-    }
-
-    ColorTransformHelper::applyMatrix(expected, matrix);
-
-    if (mColorManagementUsed) {
-        ColorTransformHelper::GammaColor(expected);
-    }
-
-    const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
-                                 uint8_t(expected.b * 255), 255};
-
-    // this is handwavy, but the precison loss scaled by 255 (8-bit per
-    // channel) should be less than one
-    const uint8_t tolerance = 1;
-
-    Transaction()
-            .setColor(colorLayer, color)
-            .setColorTransform(parentLayer, matrix, vec3())
-            .apply();
-    {
-        SCOPED_TRACE("new color");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
-    }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnChildAndParent) {
-    sp<SurfaceControl> parentLayer;
-    sp<SurfaceControl> colorLayer;
-    ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
-                                                      0 /* buffer height */,
-                                                      ISurfaceComposerClient::eFXSurfaceContainer));
-    ASSERT_NO_FATAL_FAILURE(
-            colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
-                                     ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get()));
-
-    Transaction()
-            .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
-            .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
-            .setLayer(parentLayer, mLayerZBase + 1)
-            .apply();
-    {
-        SCOPED_TRACE("default color");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
-    }
-
-    const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
-    half3 expected = color;
-    mat3 matrixChild;
-    matrixChild[0][0] = 0.3; matrixChild[1][0] = 0.59; matrixChild[2][0] = 0.11;
-    matrixChild[0][1] = 0.3; matrixChild[1][1] = 0.59; matrixChild[2][1] = 0.11;
-    matrixChild[0][2] = 0.3; matrixChild[1][2] = 0.59; matrixChild[2][2] = 0.11;
-    mat3 matrixParent;
-    matrixParent[0][0] = 0.2; matrixParent[1][0] = 0.4; matrixParent[2][0] = 0.10;
-    matrixParent[0][1] = 0.2; matrixParent[1][1] = 0.4; matrixParent[2][1] = 0.10;
-    matrixParent[0][2] = 0.2; matrixParent[1][2] = 0.4; matrixParent[2][2] = 0.10;
-
-    // degamma before applying the matrix
-    if (mColorManagementUsed) {
-        ColorTransformHelper::DegammaColor(expected);
-    }
-
-    ColorTransformHelper::applyMatrix(expected, matrixChild);
-    ColorTransformHelper::applyMatrix(expected, matrixParent);
-
-    if (mColorManagementUsed) {
-        ColorTransformHelper::GammaColor(expected);
-    }
-
-    const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
-                                 uint8_t(expected.b * 255), 255};
-
-    // this is handwavy, but the precison loss scaled by 255 (8-bit per
-    // channel) should be less than one
-    const uint8_t tolerance = 1;
-
-    Transaction()
-            .setColor(colorLayer, color)
-            .setColorTransform(parentLayer, matrixParent, vec3())
-            .setColorTransform(colorLayer, matrixChild, vec3())
-            .apply();
-    {
-        SCOPED_TRACE("new color");
-        getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
-    }
-}
-
-struct CallbackData {
-    CallbackData() = default;
-    CallbackData(nsecs_t time, const sp<Fence>& fence,
-                 const std::vector<SurfaceControlStats>& stats)
-          : latchTime(time), presentFence(fence), surfaceControlStats(stats) {}
-
-    nsecs_t latchTime;
-    sp<Fence> presentFence;
-    std::vector<SurfaceControlStats> surfaceControlStats;
-};
-
-class ExpectedResult {
-public:
-    enum Transaction {
-        NOT_PRESENTED = 0,
-        PRESENTED,
-    };
-
-    enum Buffer {
-        NOT_ACQUIRED = 0,
-        ACQUIRED,
-    };
-
-    enum PreviousBuffer {
-        NOT_RELEASED = 0,
-        RELEASED,
-        UNKNOWN,
-    };
-
-    void reset() {
-        mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
-        mExpectedSurfaceResults.clear();
-    }
-
-    void addSurface(ExpectedResult::Transaction transactionResult, const sp<SurfaceControl>& layer,
-                    ExpectedResult::Buffer bufferResult = ACQUIRED,
-                    ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
-        mTransactionResult = transactionResult;
-        mExpectedSurfaceResults.emplace(std::piecewise_construct, std::forward_as_tuple(layer),
-                                        std::forward_as_tuple(bufferResult, previousBufferResult));
-    }
-
-    void addSurfaces(ExpectedResult::Transaction transactionResult,
-                     const std::vector<sp<SurfaceControl>>& layers,
-                     ExpectedResult::Buffer bufferResult = ACQUIRED,
-                     ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
-        for (const auto& layer : layers) {
-            addSurface(transactionResult, layer, bufferResult, previousBufferResult);
-        }
-    }
-
-    void addExpectedPresentTime(nsecs_t expectedPresentTime) {
-        mExpectedPresentTime = expectedPresentTime;
-    }
-
-    void verifyCallbackData(const CallbackData& callbackData) const {
-        const auto& [latchTime, presentFence, surfaceControlStats] = callbackData;
-        if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
-            ASSERT_GE(latchTime, 0) << "bad latch time";
-            ASSERT_NE(presentFence, nullptr);
-            if (mExpectedPresentTime >= 0) {
-                ASSERT_EQ(presentFence->wait(3000), NO_ERROR);
-                ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6));
-                // if the panel is running at 30 hz, at the worst case, our expected time just
-                // misses vsync and we have to wait another 33.3ms
-                ASSERT_LE(presentFence->getSignalTime(),
-                          mExpectedPresentTime + nsecs_t(66.666666 * 1e6));
-            }
-        } else {
-            ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented";
-            ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
-        }
-
-        ASSERT_EQ(surfaceControlStats.size(), mExpectedSurfaceResults.size())
-                << "wrong number of surfaces";
-
-        for (const auto& stats : surfaceControlStats) {
-            ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control";
-
-            const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl);
-            ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end())
-                    << "unexpected surface control";
-            expectedSurfaceResult->second.verifySurfaceControlStats(stats, latchTime);
-        }
-    }
-
-private:
-    class ExpectedSurfaceResult {
-    public:
-        ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult,
-                              ExpectedResult::PreviousBuffer previousBufferResult)
-              : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
-
-        void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
-                                       nsecs_t latchTime) const {
-            const auto& [surfaceControl, acquireTime, previousReleaseFence] = surfaceControlStats;
-
-            ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
-                    << "bad acquire time";
-            ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
-
-            if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
-                ASSERT_NE(previousReleaseFence, nullptr)
-                        << "failed to set release prev buffer fence";
-            } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) {
-                ASSERT_EQ(previousReleaseFence, nullptr)
-                        << "should not have set released prev buffer fence";
-            }
-        }
-
-    private:
-        ExpectedResult::Buffer mBufferResult;
-        ExpectedResult::PreviousBuffer mPreviousBufferResult;
-    };
-
-    struct SCHash {
-        std::size_t operator()(const sp<SurfaceControl>& sc) const {
-            return std::hash<IBinder*>{}(sc->getHandle().get());
-        }
-    };
-    ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
-    nsecs_t mExpectedPresentTime = -1;
-    std::unordered_map<sp<SurfaceControl>, ExpectedSurfaceResult, SCHash> mExpectedSurfaceResults;
-};
-
-class CallbackHelper {
-public:
-    static void function(void* callbackContext, nsecs_t latchTime, const sp<Fence>& presentFence,
-                         const std::vector<SurfaceControlStats>& stats) {
-        if (!callbackContext) {
-            ALOGE("failed to get callback context");
-        }
-        CallbackHelper* helper = static_cast<CallbackHelper*>(callbackContext);
-        std::lock_guard lock(helper->mMutex);
-        helper->mCallbackDataQueue.emplace(latchTime, presentFence, stats);
-        helper->mConditionVariable.notify_all();
-    }
-
-    void getCallbackData(CallbackData* outData) {
-        std::unique_lock lock(mMutex);
-
-        if (mCallbackDataQueue.empty()) {
-            ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)),
-                      std::cv_status::timeout)
-                    << "did not receive callback";
-        }
-
-        *outData = std::move(mCallbackDataQueue.front());
-        mCallbackDataQueue.pop();
-    }
-
-    void verifyFinalState() {
-        // Wait to see if there are extra callbacks
-        std::this_thread::sleep_for(500ms);
-
-        std::lock_guard lock(mMutex);
-        EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received";
-        mCallbackDataQueue = {};
-    }
-
-    void* getContext() { return static_cast<void*>(this); }
-
-    std::mutex mMutex;
-    std::condition_variable mConditionVariable;
-    std::queue<CallbackData> mCallbackDataQueue;
-};
-
-class LayerCallbackTest : public LayerTransactionTest {
-public:
-    virtual sp<SurfaceControl> createBufferStateLayer() {
-        return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState);
-    }
-
-    static int fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
-                               const sp<SurfaceControl>& layer = nullptr, bool setBuffer = true,
-                               bool setBackgroundColor = false) {
-        if (layer) {
-            sp<GraphicBuffer> buffer;
-            sp<Fence> fence;
-            if (setBuffer) {
-                int err = getBuffer(&buffer, &fence);
-                if (err != NO_ERROR) {
-                    return err;
-                }
-
-                transaction.setBuffer(layer, buffer);
-                transaction.setAcquireFence(layer, fence);
-            }
-
-            if (setBackgroundColor) {
-                transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f,
-                                               ui::Dataspace::UNKNOWN);
-            }
-        }
-
-        transaction.addTransactionCompletedCallback(callbackHelper->function,
-                                                    callbackHelper->getContext());
-        return NO_ERROR;
-    }
-
-    static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
-                                bool finalState = false) {
-        CallbackData callbackData;
-        ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData));
-        EXPECT_NO_FATAL_FAILURE(expectedResult.verifyCallbackData(callbackData));
-
-        if (finalState) {
-            ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
-        }
-    }
-
-    static void waitForCallbacks(CallbackHelper& helper,
-                                 const std::vector<ExpectedResult>& expectedResults,
-                                 bool finalState = false) {
-        for (const auto& expectedResult : expectedResults) {
-            waitForCallback(helper, expectedResult);
-        }
-        if (finalState) {
-            ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
-        }
-    }
-};
-
-TEST_F(LayerCallbackTest, BufferColor) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    Transaction transaction;
-    CallbackHelper callback;
-    int err = fillTransaction(transaction, &callback, layer, true, true);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction.apply();
-
-    ExpectedResult expected;
-    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, NoBufferNoColor) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    Transaction transaction;
-    CallbackHelper callback;
-    int err = fillTransaction(transaction, &callback, layer, false, false);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
-    ExpectedResult expected;
-    expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
-                        ExpectedResult::Buffer::NOT_ACQUIRED);
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, BufferNoColor) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    Transaction transaction;
-    CallbackHelper callback;
-    int err = fillTransaction(transaction, &callback, layer, true, false);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
-    ExpectedResult expected;
-    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, NoBufferColor) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    Transaction transaction;
-    CallbackHelper callback;
-    int err = fillTransaction(transaction, &callback, layer, false, true);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
-    ExpectedResult expected;
-    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
-                        ExpectedResult::Buffer::NOT_ACQUIRED);
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, NoStateChange) {
-    Transaction transaction;
-    CallbackHelper callback;
-    int err = fillTransaction(transaction, &callback);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction.apply();
-
-    ExpectedResult expected;
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, OffScreen) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    Transaction transaction;
-    CallbackHelper callback;
-    int err = fillTransaction(transaction, &callback, layer);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction.setFrame(layer, Rect(-100, -100, 100, 100)).apply();
-
-    ExpectedResult expected;
-    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MergeBufferNoColor) {
-    sp<SurfaceControl> layer1, layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
-    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
-    Transaction transaction1, transaction2;
-    CallbackHelper callback1, callback2;
-    int err = fillTransaction(transaction1, &callback1, layer1);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-    err = fillTransaction(transaction2, &callback2, layer2);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
-    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
-    ExpectedResult expected;
-    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MergeNoBufferColor) {
-    sp<SurfaceControl> layer1, layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
-    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
-    Transaction transaction1, transaction2;
-    CallbackHelper callback1, callback2;
-    int err = fillTransaction(transaction1, &callback1, layer1, false, true);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-    err = fillTransaction(transaction2, &callback2, layer2, false, true);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
-    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
-    ExpectedResult expected;
-    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
-                         ExpectedResult::Buffer::NOT_ACQUIRED);
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MergeOneBufferOneColor) {
-    sp<SurfaceControl> layer1, layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
-    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
-    Transaction transaction1, transaction2;
-    CallbackHelper callback1, callback2;
-    int err = fillTransaction(transaction1, &callback1, layer1);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-    err = fillTransaction(transaction2, &callback2, layer2, false, true);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
-    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
-    ExpectedResult expected;
-    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer1);
-    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer2,
-                        ExpectedResult::Buffer::NOT_ACQUIRED);
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-TEST_F(LayerCallbackTest, Merge_SameCallback) {
-    sp<SurfaceControl> layer1, layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
-    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
-    Transaction transaction1, transaction2;
-    CallbackHelper callback;
-    int err = fillTransaction(transaction1, &callback, layer1);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-    err = fillTransaction(transaction2, &callback, layer2);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction2.merge(std::move(transaction1)).apply();
-
-    ExpectedResult expected;
-    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, Merge_SameLayer) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    Transaction transaction1, transaction2;
-    CallbackHelper callback1, callback2;
-    int err = fillTransaction(transaction1, &callback1, layer);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-    err = fillTransaction(transaction2, &callback2, layer);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction2.merge(std::move(transaction1)).apply();
-
-    ExpectedResult expected;
-    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, Merge_DifferentClients) {
-    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
-            client2(new SurfaceComposerClient);
-
-    ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
-    ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
-
-    sp<SurfaceControl> layer1, layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
-                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
-                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    Transaction transaction1, transaction2;
-    CallbackHelper callback1, callback2;
-    int err = fillTransaction(transaction1, &callback1, layer1);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-    err = fillTransaction(transaction2, &callback2, layer2);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
-    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
-    ExpectedResult expected;
-    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    Transaction transaction;
-    CallbackHelper callback;
-    for (size_t i = 0; i < 10; i++) {
-        int err = fillTransaction(transaction, &callback, layer);
-        if (err) {
-            GTEST_SUCCEED() << "test not supported";
-            return;
-        }
-
-        transaction.apply();
-
-        ExpectedResult expected;
-        expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
-                            ExpectedResult::Buffer::ACQUIRED,
-                            (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
-                                     : ExpectedResult::PreviousBuffer::RELEASED);
-        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
-    }
-    ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_NoStateChange) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    Transaction transaction;
-    CallbackHelper callback;
-    for (size_t i = 0; i < 10; i++) {
-        ExpectedResult expected;
-
-        if (i == 0) {
-            int err = fillTransaction(transaction, &callback, layer);
-            if (err) {
-                GTEST_SUCCEED() << "test not supported";
-                return;
-            }
-            expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
-        } else {
-            int err = fillTransaction(transaction, &callback);
-            if (err) {
-                GTEST_SUCCEED() << "test not supported";
-                return;
-            }
-        }
-
-        transaction.apply();
-
-        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
-    }
-    ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    Transaction transaction;
-    CallbackHelper callback;
-    for (size_t i = 0; i < 10; i++) {
-        if (i == 0) {
-            int err = fillTransaction(transaction, &callback, layer);
-            if (err) {
-                GTEST_SUCCEED() << "test not supported";
-                return;
-            }
-        } else {
-            int err = fillTransaction(transaction, &callback);
-            if (err) {
-                GTEST_SUCCEED() << "test not supported";
-                return;
-            }
-        }
-
-        transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
-        ExpectedResult expected;
-        expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED
-                                     : ExpectedResult::Transaction::NOT_PRESENTED,
-                            layer,
-                            (i == 0) ? ExpectedResult::Buffer::ACQUIRED
-                                     : ExpectedResult::Buffer::NOT_ACQUIRED);
-        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, i == 0));
-    }
-    ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_Merge) {
-    sp<SurfaceControl> layer1, layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
-    ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
-    Transaction transaction1, transaction2;
-    CallbackHelper callback1, callback2;
-    for (size_t i = 0; i < 10; i++) {
-        int err = fillTransaction(transaction1, &callback1, layer1);
-        if (err) {
-            GTEST_SUCCEED() << "test not supported";
-            return;
-        }
-        err = fillTransaction(transaction2, &callback2, layer2);
-        if (err) {
-            GTEST_SUCCEED() << "test not supported";
-            return;
-        }
-
-        transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
-        transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
-        ExpectedResult expected;
-        expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
-                             ExpectedResult::Buffer::ACQUIRED,
-                             (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
-                                      : ExpectedResult::PreviousBuffer::RELEASED);
-        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
-        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
-    }
-    ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
-    ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) {
-    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
-            client2(new SurfaceComposerClient);
-    ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
-    ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
-
-    sp<SurfaceControl> layer1, layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
-                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
-                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    Transaction transaction1, transaction2;
-    CallbackHelper callback1, callback2;
-    for (size_t i = 0; i < 10; i++) {
-        int err = fillTransaction(transaction1, &callback1, layer1);
-        if (err) {
-            GTEST_SUCCEED() << "test not supported";
-            return;
-        }
-        err = fillTransaction(transaction2, &callback2, layer2);
-        if (err) {
-            GTEST_SUCCEED() << "test not supported";
-            return;
-        }
-
-        transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
-        transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
-        ExpectedResult expected;
-        expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
-                             ExpectedResult::Buffer::ACQUIRED,
-                             (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
-                                      : ExpectedResult::PreviousBuffer::RELEASED);
-        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
-        EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
-    }
-    ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
-    ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateChange) {
-    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
-            client2(new SurfaceComposerClient);
-    ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
-    ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
-
-    sp<SurfaceControl> layer1, layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
-                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
-                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    Transaction transaction1, transaction2;
-    CallbackHelper callback1, callback2;
-
-    // Normal call to set up test
-    int err = fillTransaction(transaction1, &callback1, layer1);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-    err = fillTransaction(transaction2, &callback2, layer2);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
-    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
-    ExpectedResult expected;
-    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-    expected.reset();
-
-    // Test
-    err = fillTransaction(transaction1, &callback1);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-    err = fillTransaction(transaction2, &callback2);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction2.merge(std::move(transaction1)).apply();
-
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateChange) {
-    sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
-            client2(new SurfaceComposerClient);
-
-    ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
-    ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
-
-    sp<SurfaceControl> layer1, layer2;
-    ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
-                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
-    ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
-                                                 ISurfaceComposerClient::eFXSurfaceBufferState));
-
-    Transaction transaction1, transaction2;
-    CallbackHelper callback1, callback2;
-
-    // Normal call to set up test
-    int err = fillTransaction(transaction1, &callback1, layer1);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-    err = fillTransaction(transaction2, &callback2, layer2);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
-    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
-    ExpectedResult expected;
-    expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-    expected.reset();
-
-    // Test
-    err = fillTransaction(transaction1, &callback1);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-    err = fillTransaction(transaction2, &callback2);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
-    expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2,
-                        ExpectedResult::Buffer::NOT_ACQUIRED);
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    Transaction transaction;
-    CallbackHelper callback;
-    std::vector<ExpectedResult> expectedResults(50);
-    for (auto& expected : expectedResults) {
-        expected.reset();
-        expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
-                            ExpectedResult::Buffer::ACQUIRED,
-                            ExpectedResult::PreviousBuffer::UNKNOWN);
-
-        int err = fillTransaction(transaction, &callback, layer);
-        if (err) {
-            GTEST_SUCCEED() << "test not supported";
-            return;
-        }
-
-        transaction.apply();
-    }
-    EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_NoStateChange) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    // Normal call to set up test
-    Transaction transaction;
-    CallbackHelper callback;
-    int err = fillTransaction(transaction, &callback, layer);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction.apply();
-
-    ExpectedResult expected;
-    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-
-    // Test
-    std::vector<ExpectedResult> expectedResults(50);
-    for (auto& expected : expectedResults) {
-        expected.reset();
-
-        err = fillTransaction(transaction, &callback);
-        if (err) {
-            GTEST_SUCCEED() << "test not supported";
-            return;
-        }
-
-        transaction.apply();
-    }
-    EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    // Normal call to set up test
-    Transaction transaction;
-    CallbackHelper callback;
-    int err = fillTransaction(transaction, &callback, layer);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
-    ExpectedResult expectedResult;
-    expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expectedResult, true));
-
-    // Test
-    std::vector<ExpectedResult> expectedResults(50);
-    for (auto& expected : expectedResults) {
-        expected.reset();
-        expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
-                            ExpectedResult::Buffer::NOT_ACQUIRED);
-
-        err = fillTransaction(transaction, &callback);
-        if (err) {
-            GTEST_SUCCEED() << "test not supported";
-            return;
-        }
-
-        transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-    }
-    EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
-}
-
-TEST_F(LayerCallbackTest, DesiredPresentTime) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    Transaction transaction;
-    CallbackHelper callback;
-    int err = fillTransaction(transaction, &callback, layer);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    // Try to present 100ms in the future
-    nsecs_t time = systemTime() + (100 * 1e6);
-
-    transaction.setDesiredPresentTime(time);
-    transaction.apply();
-
-    ExpectedResult expected;
-    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
-    expected.addExpectedPresentTime(time);
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    Transaction transaction;
-    CallbackHelper callback1;
-    int err = fillTransaction(transaction, &callback1, layer);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    // Try to present 100ms in the future
-    nsecs_t time = systemTime() + (100 * 1e6);
-
-    transaction.setDesiredPresentTime(time);
-    transaction.apply();
-
-    ExpectedResult expected1;
-    expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
-    expected1.addExpectedPresentTime(time);
-
-    CallbackHelper callback2;
-    err = fillTransaction(transaction, &callback2, layer);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    // Try to present 33ms after the first frame
-    time += (33.3 * 1e6);
-
-    transaction.setDesiredPresentTime(time);
-    transaction.apply();
-
-    ExpectedResult expected2;
-    expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
-                         ExpectedResult::Buffer::ACQUIRED,
-                         ExpectedResult::PreviousBuffer::RELEASED);
-    expected2.addExpectedPresentTime(time);
-
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
-}
-
-TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    Transaction transaction;
-    CallbackHelper callback1;
-    int err = fillTransaction(transaction, &callback1, layer);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    // Try to present 100ms in the future
-    nsecs_t time = systemTime() + (100 * 1e6);
-
-    transaction.setDesiredPresentTime(time);
-    transaction.apply();
-
-    ExpectedResult expected1;
-    expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
-    expected1.addExpectedPresentTime(time);
-
-    CallbackHelper callback2;
-    err = fillTransaction(transaction, &callback2, layer);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    // Try to present 33ms before the previous frame
-    time -= (33.3 * 1e6);
-
-    transaction.setDesiredPresentTime(time);
-    transaction.apply();
-
-    ExpectedResult expected2;
-    expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
-                         ExpectedResult::Buffer::ACQUIRED,
-                         ExpectedResult::PreviousBuffer::RELEASED);
-
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
-}
-
-TEST_F(LayerCallbackTest, DesiredPresentTime_Past) {
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
-    Transaction transaction;
-    CallbackHelper callback;
-    int err = fillTransaction(transaction, &callback, layer);
-    if (err) {
-        GTEST_SUCCEED() << "test not supported";
-        return;
-    }
-
-    // Try to present 100ms in the past
-    nsecs_t time = systemTime() - (100 * 1e6);
-
-    transaction.setDesiredPresentTime(time);
-    transaction.apply();
-
-    ExpectedResult expected;
-    expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
-    expected.addExpectedPresentTime(systemTime());
-    EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-class LayerUpdateTest : public LayerTransactionTest {
-protected:
-    virtual void SetUp() {
-        LayerTransactionTest::SetUp();
-        ASSERT_EQ(NO_ERROR, mClient->initCheck());
-
-        const auto display = SurfaceComposerClient::getInternalDisplayToken();
-        ASSERT_FALSE(display == nullptr);
-
-        DisplayInfo info;
-        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
-
-        ssize_t displayWidth = info.w;
-        ssize_t displayHeight = info.h;
-
-        // Background surface
-        mBGSurfaceControl = createLayer(String8("BG Test Surface"), displayWidth,
-                                               displayHeight, 0);
-        ASSERT_TRUE(mBGSurfaceControl != nullptr);
-        ASSERT_TRUE(mBGSurfaceControl->isValid());
-        fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195);
-
-        // Foreground surface
-        mFGSurfaceControl = createLayer(String8("FG Test Surface"), 64, 64, 0);
-
-        ASSERT_TRUE(mFGSurfaceControl != nullptr);
-        ASSERT_TRUE(mFGSurfaceControl->isValid());
-
-        fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
-
-        // Synchronization surface
-        mSyncSurfaceControl = createLayer(String8("Sync Test Surface"), 1, 1, 0);
-        ASSERT_TRUE(mSyncSurfaceControl != nullptr);
-        ASSERT_TRUE(mSyncSurfaceControl->isValid());
-
-        fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
-
-        asTransaction([&](Transaction& t) {
-            t.setDisplayLayerStack(display, 0);
-
-            t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl);
-
-            t.setLayer(mFGSurfaceControl, INT32_MAX - 1)
-                    .setPosition(mFGSurfaceControl, 64, 64)
-                    .show(mFGSurfaceControl);
-
-            t.setLayer(mSyncSurfaceControl, INT32_MAX - 1)
-                    .setPosition(mSyncSurfaceControl, displayWidth - 2, displayHeight - 2)
-                    .show(mSyncSurfaceControl);
-        });
-    }
-
-    virtual void TearDown() {
-        LayerTransactionTest::TearDown();
-        mBGSurfaceControl = 0;
-        mFGSurfaceControl = 0;
-        mSyncSurfaceControl = 0;
-    }
-
-    void waitForPostedBuffers() {
-        // Since the sync surface is in synchronous mode (i.e. double buffered)
-        // posting three buffers to it should ensure that at least two
-        // SurfaceFlinger::handlePageFlip calls have been made, which should
-        // guaranteed that a buffer posted to another Surface has been retired.
-        fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
-        fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
-        fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
-    }
-
-
-    sp<SurfaceControl> mBGSurfaceControl;
-    sp<SurfaceControl> mFGSurfaceControl;
-
-    // This surface is used to ensure that the buffers posted to
-    // mFGSurfaceControl have been picked up by SurfaceFlinger.
-    sp<SurfaceControl> mSyncSurfaceControl;
-};
-
-TEST_F(LayerUpdateTest, RelativesAreNotDetached) {
-
-    std::unique_ptr<ScreenCapture> sc;
-
-    sp<SurfaceControl> relative = createLayer(String8("relativeTestSurface"), 10, 10, 0);
-    fillSurfaceRGBA8(relative, 10, 10, 10);
-    waitForPostedBuffers();
-
-    Transaction{}
-            .setRelativeLayer(relative, mFGSurfaceControl->getHandle(), 1)
-            .setPosition(relative, 64, 64)
-            .apply();
-
-    {
-        // The relative should be on top of the FG control.
-        ScreenCapture::captureScreen(&sc);
-        sc->checkPixel(64, 64, 10, 10, 10);
-    }
-    Transaction{}.detachChildren(mFGSurfaceControl).apply();
-
-    {
-        // Nothing should change at this point.
-        ScreenCapture::captureScreen(&sc);
-        sc->checkPixel(64, 64, 10, 10, 10);
-    }
-
-    Transaction{}.hide(relative).apply();
-
-    {
-        // Ensure that the relative was actually hidden, rather than
-        // being left in the detached but visible state.
-        ScreenCapture::captureScreen(&sc);
-        sc->expectFGColor(64, 64);
-    }
-}
-
-class GeometryLatchingTest : public LayerUpdateTest {
-protected:
-    void EXPECT_INITIAL_STATE(const char* trace) {
-        SCOPED_TRACE(trace);
-        ScreenCapture::captureScreen(&sc);
-        // We find the leading edge of the FG surface.
-        sc->expectFGColor(127, 127);
-        sc->expectBGColor(128, 128);
-    }
-
-    void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63, false); }
-
-    void unlockFGBuffer() {
-        sp<Surface> s = mFGSurfaceControl->getSurface();
-        ASSERT_EQ(NO_ERROR, s->unlockAndPost());
-        waitForPostedBuffers();
-    }
-
-    void completeFGResize() {
-        fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
-        waitForPostedBuffers();
-    }
-    void restoreInitialState() {
-        asTransaction([&](Transaction& t) {
-            t.setSize(mFGSurfaceControl, 64, 64);
-            t.setPosition(mFGSurfaceControl, 64, 64);
-            t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
-        });
-
-        EXPECT_INITIAL_STATE("After restoring initial state");
-    }
-    std::unique_ptr<ScreenCapture> sc;
-};
-
-class CropLatchingTest : public GeometryLatchingTest {
-protected:
-    void EXPECT_CROPPED_STATE(const char* trace) {
-        SCOPED_TRACE(trace);
-        ScreenCapture::captureScreen(&sc);
-        // The edge should be moved back one pixel by our crop.
-        sc->expectFGColor(126, 126);
-        sc->expectBGColor(127, 127);
-        sc->expectBGColor(128, 128);
-    }
-
-    void EXPECT_RESIZE_STATE(const char* trace) {
-        SCOPED_TRACE(trace);
-        ScreenCapture::captureScreen(&sc);
-        // The FG is now resized too 128,128 at 64,64
-        sc->expectFGColor(64, 64);
-        sc->expectFGColor(191, 191);
-        sc->expectBGColor(192, 192);
-    }
-};
-
-TEST_F(LayerUpdateTest, DeferredTransactionTest) {
-    std::unique_ptr<ScreenCapture> sc;
-    {
-        SCOPED_TRACE("before anything");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(32, 32);
-        sc->expectFGColor(96, 96);
-        sc->expectBGColor(160, 160);
-    }
-
-    // set up two deferred transactions on different frames
-    asTransaction([&](Transaction& t) {
-        t.setAlpha(mFGSurfaceControl, 0.75);
-        t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
-                                       mSyncSurfaceControl->getSurface()->getNextFrameNumber());
-    });
-
-    asTransaction([&](Transaction& t) {
-        t.setPosition(mFGSurfaceControl, 128, 128);
-        t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
-                                       mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
-    });
-
-    {
-        SCOPED_TRACE("before any trigger");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(32, 32);
-        sc->expectFGColor(96, 96);
-        sc->expectBGColor(160, 160);
-    }
-
-    // should trigger the first deferred transaction, but not the second one
-    fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
-    {
-        SCOPED_TRACE("after first trigger");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(32, 32);
-        sc->checkPixel(96, 96, 162, 63, 96);
-        sc->expectBGColor(160, 160);
-    }
-
-    // should show up immediately since it's not deferred
-    asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 1.0); });
-
-    // trigger the second deferred transaction
-    fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
-    {
-        SCOPED_TRACE("after second trigger");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(32, 32);
-        sc->expectBGColor(96, 96);
-        sc->expectFGColor(160, 160);
-    }
-}
-
-TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) {
-    std::unique_ptr<ScreenCapture> sc;
-
-    sp<SurfaceControl> childNoBuffer =
-            createSurface(mClient, "Bufferless child", 0 /* buffer width */, 0 /* buffer height */,
-                          PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-    sp<SurfaceControl> childBuffer = createSurface(mClient, "Buffered child", 20, 20,
-                                                   PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get());
-    fillSurfaceRGBA8(childBuffer, 200, 200, 200);
-    SurfaceComposerClient::Transaction{}
-            .setCrop_legacy(childNoBuffer, Rect(0, 0, 10, 10))
-            .show(childNoBuffer)
-            .show(childBuffer)
-            .apply(true);
-    {
-        ScreenCapture::captureScreen(&sc);
-        sc->expectChildColor(73, 73);
-        sc->expectFGColor(74, 74);
-    }
-    SurfaceComposerClient::Transaction{}
-            .setCrop_legacy(childNoBuffer, Rect(0, 0, 20, 20))
-            .apply(true);
-    {
-        ScreenCapture::captureScreen(&sc);
-        sc->expectChildColor(73, 73);
-        sc->expectChildColor(74, 74);
-    }
-}
-
-TEST_F(LayerUpdateTest, MergingTransactions) {
-    std::unique_ptr<ScreenCapture> sc;
-    {
-        SCOPED_TRACE("before move");
-        ScreenCapture::captureScreen(&sc);
-        sc->expectBGColor(0, 12);
-        sc->expectFGColor(75, 75);
-        sc->expectBGColor(145, 145);
-    }
-
-    Transaction t1, t2;
-    t1.setPosition(mFGSurfaceControl, 128, 128);
-    t2.setPosition(mFGSurfaceControl, 0, 0);
-    // We expect that the position update from t2 now
-    // overwrites the position update from t1.
-    t1.merge(std::move(t2));
-    t1.apply();
-
-    {
-        ScreenCapture::captureScreen(&sc);
-        sc->expectFGColor(1, 1);
-    }
-}
-
-class ChildLayerTest : public LayerUpdateTest {
-protected:
-    void SetUp() override {
-        LayerUpdateTest::SetUp();
-        mChild = createSurface(mClient, "Child surface", 10, 15, PIXEL_FORMAT_RGBA_8888, 0,
-                               mFGSurfaceControl.get());
-        fillSurfaceRGBA8(mChild, 200, 200, 200);
-
-        {
-            SCOPED_TRACE("before anything");
-            mCapture = screenshot();
-            mCapture->expectChildColor(64, 64);
-        }
-    }
-    void TearDown() override {
-        LayerUpdateTest::TearDown();
-        mChild = 0;
-    }
-
-    sp<SurfaceControl> mChild;
-    std::unique_ptr<ScreenCapture> mCapture;
-};
-
-TEST_F(ChildLayerTest, ChildLayerPositioning) {
-    asTransaction([&](Transaction& t) {
-        t.show(mChild);
-        t.setPosition(mChild, 10, 10);
-        t.setPosition(mFGSurfaceControl, 64, 64);
-    });
-
-    {
-        mCapture = screenshot();
-        // Top left of foreground must now be visible
-        mCapture->expectFGColor(64, 64);
-        // But 10 pixels in we should see the child surface
-        mCapture->expectChildColor(74, 74);
-        // And 10 more pixels we should be back to the foreground surface
-        mCapture->expectFGColor(84, 84);
-    }
-
-    asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); });
-
-    {
-        mCapture = screenshot();
-        // Top left of foreground should now be at 0, 0
-        mCapture->expectFGColor(0, 0);
-        // But 10 pixels in we should see the child surface
-        mCapture->expectChildColor(10, 10);
-        // And 10 more pixels we should be back to the foreground surface
-        mCapture->expectFGColor(20, 20);
-    }
-}
-
-TEST_F(ChildLayerTest, ChildLayerCropping) {
-    asTransaction([&](Transaction& t) {
-        t.show(mChild);
-        t.setPosition(mChild, 0, 0);
-        t.setPosition(mFGSurfaceControl, 0, 0);
-        t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
-    });
-
-    {
-        mCapture = screenshot();
-        mCapture->expectChildColor(0, 0);
-        mCapture->expectChildColor(4, 4);
-        mCapture->expectBGColor(5, 5);
-    }
-}
-
-TEST_F(ChildLayerTest, ChildLayerConstraints) {
-    asTransaction([&](Transaction& t) {
-        t.show(mChild);
-        t.setPosition(mFGSurfaceControl, 0, 0);
-        t.setPosition(mChild, 63, 63);
-    });
-
-    {
-        mCapture = screenshot();
-        mCapture->expectFGColor(0, 0);
-        // Last pixel in foreground should now be the child.
-        mCapture->expectChildColor(63, 63);
-        // But the child should be constrained and the next pixel
-        // must be the background
-        mCapture->expectBGColor(64, 64);
-    }
-}
-
-TEST_F(ChildLayerTest, ChildLayerScaling) {
-    asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); });
-
-    // Find the boundary between the parent and child
-    {
-        mCapture = screenshot();
-        mCapture->expectChildColor(9, 9);
-        mCapture->expectFGColor(10, 10);
-    }
-
-    asTransaction([&](Transaction& t) { t.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0); });
-
-    // The boundary should be twice as far from the origin now.
-    // The pixels from the last test should all be child now
-    {
-        mCapture = screenshot();
-        mCapture->expectChildColor(9, 9);
-        mCapture->expectChildColor(10, 10);
-        mCapture->expectChildColor(19, 19);
-        mCapture->expectFGColor(20, 20);
-    }
-}
-
-// A child with a scale transform should be cropped by its parent bounds.
-TEST_F(ChildLayerTest, ChildLayerScalingCroppedByParent) {
-    asTransaction([&](Transaction& t) {
-        t.setPosition(mFGSurfaceControl, 0, 0);
-        t.setPosition(mChild, 0, 0);
-    });
-
-    // Find the boundary between the parent and child.
-    {
-        mCapture = screenshot();
-        mCapture->expectChildColor(0, 0);
-        mCapture->expectChildColor(9, 9);
-        mCapture->expectFGColor(10, 10);
-    }
-
-    asTransaction([&](Transaction& t) { t.setMatrix(mChild, 10.0, 0, 0, 10.0); });
-
-    // The child should fill its parent bounds and be cropped by it.
-    {
-        mCapture = screenshot();
-        mCapture->expectChildColor(0, 0);
-        mCapture->expectChildColor(63, 63);
-        mCapture->expectBGColor(64, 64);
-    }
-}
-
-TEST_F(ChildLayerTest, ChildLayerAlpha) {
-    fillSurfaceRGBA8(mBGSurfaceControl, 0, 0, 254);
-    fillSurfaceRGBA8(mFGSurfaceControl, 254, 0, 0);
-    fillSurfaceRGBA8(mChild, 0, 254, 0);
-    waitForPostedBuffers();
-
-    asTransaction([&](Transaction& t) {
-        t.show(mChild);
-        t.setPosition(mChild, 0, 0);
-        t.setPosition(mFGSurfaceControl, 0, 0);
-    });
-
-    {
-        mCapture = screenshot();
-        // Unblended child color
-        mCapture->checkPixel(0, 0, 0, 254, 0);
-    }
-
-    asTransaction([&](Transaction& t) { t.setAlpha(mChild, 0.5); });
-
-    {
-        mCapture = screenshot();
-        // Child and BG blended.
-        mCapture->checkPixel(0, 0, 127, 127, 0);
-    }
-
-    asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 0.5); });
-
-    {
-        mCapture = screenshot();
-        // Child and BG blended.
-        mCapture->checkPixel(0, 0, 95, 64, 95);
-    }
-}
-
-TEST_F(ChildLayerTest, ReparentChildren) {
-    asTransaction([&](Transaction& t) {
-        t.show(mChild);
-        t.setPosition(mChild, 10, 10);
-        t.setPosition(mFGSurfaceControl, 64, 64);
-    });
-
-    {
-        mCapture = screenshot();
-        // Top left of foreground must now be visible
-        mCapture->expectFGColor(64, 64);
-        // But 10 pixels in we should see the child surface
-        mCapture->expectChildColor(74, 74);
-        // And 10 more pixels we should be back to the foreground surface
-        mCapture->expectFGColor(84, 84);
-    }
-
-    asTransaction([&](Transaction& t) {
-        t.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
-    });
-
-    {
-        mCapture = screenshot();
-        mCapture->expectFGColor(64, 64);
-        // In reparenting we should have exposed the entire foreground surface.
-        mCapture->expectFGColor(74, 74);
-        // And the child layer should now begin at 10, 10 (since the BG
-        // layer is at (0, 0)).
-        mCapture->expectBGColor(9, 9);
-        mCapture->expectChildColor(10, 10);
-    }
-}
-
-TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) {
-    sp<SurfaceControl> mGrandChild =
-            createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
-    fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
-
-    {
-        SCOPED_TRACE("Grandchild visible");
-        ScreenCapture::captureScreen(&mCapture);
-        mCapture->checkPixel(64, 64, 111, 111, 111);
-    }
-
-    mChild.clear();
-
-    {
-        SCOPED_TRACE("After destroying child");
-        ScreenCapture::captureScreen(&mCapture);
-        mCapture->expectFGColor(64, 64);
-    }
-
-    asTransaction([&](Transaction& t) {
-         t.reparent(mGrandChild, mFGSurfaceControl->getHandle());
-    });
-
-    {
-        SCOPED_TRACE("After reparenting grandchild");
-        ScreenCapture::captureScreen(&mCapture);
-        mCapture->checkPixel(64, 64, 111, 111, 111);
-    }
-}
-
-TEST_F(ChildLayerTest, DetachChildrenSameClient) {
-    asTransaction([&](Transaction& t) {
-        t.show(mChild);
-        t.setPosition(mChild, 10, 10);
-        t.setPosition(mFGSurfaceControl, 64, 64);
-    });
-
-    {
-        mCapture = screenshot();
-        // Top left of foreground must now be visible
-        mCapture->expectFGColor(64, 64);
-        // But 10 pixels in we should see the child surface
-        mCapture->expectChildColor(74, 74);
-        // And 10 more pixels we should be back to the foreground surface
-        mCapture->expectFGColor(84, 84);
-    }
-
-
-    asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
-
-    asTransaction([&](Transaction& t) { t.hide(mChild); });
-
-    // Since the child has the same client as the parent, it will not get
-    // detached and will be hidden.
-    {
-        mCapture = screenshot();
-        mCapture->expectFGColor(64, 64);
-        mCapture->expectFGColor(74, 74);
-        mCapture->expectFGColor(84, 84);
-    }
-}
-
-TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
-    sp<SurfaceComposerClient> mNewComposerClient = new SurfaceComposerClient;
-    sp<SurfaceControl> mChildNewClient =
-            createSurface(mNewComposerClient, "New Child Test Surface", 10, 10,
-                          PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
-    ASSERT_TRUE(mChildNewClient->isValid());
-
-    fillSurfaceRGBA8(mChildNewClient, 200, 200, 200);
-
-    asTransaction([&](Transaction& t) {
-        t.hide(mChild);
-        t.show(mChildNewClient);
-        t.setPosition(mChildNewClient, 10, 10);
-        t.setPosition(mFGSurfaceControl, 64, 64);
-    });
-
-    {
-        mCapture = screenshot();
-        // Top left of foreground must now be visible
-        mCapture->expectFGColor(64, 64);
-        // But 10 pixels in we should see the child surface
-        mCapture->expectChildColor(74, 74);
-        // And 10 more pixels we should be back to the foreground surface
-        mCapture->expectFGColor(84, 84);
-    }
-
-    asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
-
-    asTransaction([&](Transaction& t) { t.hide(mChildNewClient); });
-
-    // Nothing should have changed.
-    {
-        mCapture = screenshot();
-        mCapture->expectFGColor(64, 64);
-        mCapture->expectChildColor(74, 74);
-        mCapture->expectFGColor(84, 84);
-    }
-}
-
-TEST_F(ChildLayerTest, DetachChildrenThenAttach) {
-    sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
-    sp<SurfaceControl> childNewClient =
-            newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
-                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
-    ASSERT_TRUE(childNewClient != nullptr);
-    ASSERT_TRUE(childNewClient->isValid());
-
-    fillSurfaceRGBA8(childNewClient, 200, 200, 200);
-
-    Transaction()
-            .hide(mChild)
-            .show(childNewClient)
-            .setPosition(childNewClient, 10, 10)
-            .setPosition(mFGSurfaceControl, 64, 64)
-            .apply();
-
-    {
-        mCapture = screenshot();
-        // Top left of foreground must now be visible
-        mCapture->expectFGColor(64, 64);
-        // But 10 pixels in we should see the child surface
-        mCapture->expectChildColor(74, 74);
-        // And 10 more pixels we should be back to the foreground surface
-        mCapture->expectFGColor(84, 84);
-    }
-
-    Transaction().detachChildren(mFGSurfaceControl).apply();
-    Transaction().hide(childNewClient).apply();
-
-    // Nothing should have changed.
-    {
-        mCapture = screenshot();
-        mCapture->expectFGColor(64, 64);
-        mCapture->expectChildColor(74, 74);
-        mCapture->expectFGColor(84, 84);
-    }
-
-    sp<SurfaceControl> newParentSurface = createLayer(String8("New Parent Surface"), 32, 32, 0);
-    fillLayerColor(ISurfaceComposerClient::eFXSurfaceBufferQueue, newParentSurface, Color::RED, 32,
-                   32);
-    Transaction()
-            .setLayer(newParentSurface, INT32_MAX - 1)
-            .show(newParentSurface)
-            .setPosition(newParentSurface, 20, 20)
-            .reparent(childNewClient, newParentSurface->getHandle())
-            .apply();
-    {
-        mCapture = screenshot();
-        // Child is now hidden.
-        mCapture->expectColor(Rect(20, 20, 52, 52), Color::RED);
-    }
-}
-TEST_F(ChildLayerTest, DetachChildrenWithDeferredTransaction) {
-    sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
-    sp<SurfaceControl> childNewClient =
-            newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
-                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
-    ASSERT_TRUE(childNewClient != nullptr);
-    ASSERT_TRUE(childNewClient->isValid());
-
-    fillSurfaceRGBA8(childNewClient, 200, 200, 200);
-
-    Transaction()
-            .hide(mChild)
-            .show(childNewClient)
-            .setPosition(childNewClient, 10, 10)
-            .setPosition(mFGSurfaceControl, 64, 64)
-            .apply();
-
-    {
-        mCapture = screenshot();
-        Rect rect = Rect(74, 74, 84, 84);
-        mCapture->expectBorder(rect, Color{195, 63, 63, 255});
-        mCapture->expectColor(rect, Color{200, 200, 200, 255});
-    }
-
-    Transaction()
-            .deferTransactionUntil_legacy(childNewClient, mFGSurfaceControl->getHandle(),
-                                          mFGSurfaceControl->getSurface()->getNextFrameNumber())
-            .apply();
-    Transaction().detachChildren(mFGSurfaceControl).apply();
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(mFGSurfaceControl, Color::RED, 32, 32));
-
-    // BufferLayer can still dequeue buffers even though there's a detached layer with a
-    // deferred transaction.
-    {
-        SCOPED_TRACE("new buffer");
-        mCapture = screenshot();
-        Rect rect = Rect(74, 74, 84, 84);
-        mCapture->expectBorder(rect, Color::RED);
-        mCapture->expectColor(rect, Color{200, 200, 200, 255});
-    }
-}
-
-TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
-    asTransaction([&](Transaction& t) {
-        t.show(mChild);
-        t.setPosition(mChild, 0, 0);
-        t.setPosition(mFGSurfaceControl, 0, 0);
-    });
-
-    {
-        mCapture = screenshot();
-        // We've positioned the child in the top left.
-        mCapture->expectChildColor(0, 0);
-        // But it's only 10x15.
-        mCapture->expectFGColor(10, 15);
-    }
-
-    asTransaction([&](Transaction& t) {
-        t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-        // We cause scaling by 2.
-        t.setSize(mFGSurfaceControl, 128, 128);
-    });
-
-    {
-        mCapture = screenshot();
-        // We've positioned the child in the top left.
-        mCapture->expectChildColor(0, 0);
-        mCapture->expectChildColor(10, 10);
-        mCapture->expectChildColor(19, 29);
-        // And now it should be scaled all the way to 20x30
-        mCapture->expectFGColor(20, 30);
-    }
-}
-
-// Regression test for b/37673612
-TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
-    asTransaction([&](Transaction& t) {
-        t.show(mChild);
-        t.setPosition(mChild, 0, 0);
-        t.setPosition(mFGSurfaceControl, 0, 0);
-    });
-
-    {
-        mCapture = screenshot();
-        // We've positioned the child in the top left.
-        mCapture->expectChildColor(0, 0);
-        mCapture->expectChildColor(9, 14);
-        // But it's only 10x15.
-        mCapture->expectFGColor(10, 15);
-    }
-    // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
-    // the WM specified state size.
-    asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
-    sp<Surface> s = mFGSurfaceControl->getSurface();
-    auto anw = static_cast<ANativeWindow*>(s.get());
-    native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
-    native_window_set_buffers_dimensions(anw, 64, 128);
-    fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
-    waitForPostedBuffers();
-
-    {
-        // The child should still be in the same place and not have any strange scaling as in
-        // b/37673612.
-        mCapture = screenshot();
-        mCapture->expectChildColor(0, 0);
-        mCapture->expectFGColor(10, 10);
-    }
-}
-
-// A child with a buffer transform from its parents should be cropped by its parent bounds.
-TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferTransform) {
-    asTransaction([&](Transaction& t) {
-        t.show(mChild);
-        t.setPosition(mChild, 0, 0);
-        t.setPosition(mFGSurfaceControl, 0, 0);
-        t.setSize(mChild, 100, 100);
-    });
-    fillSurfaceRGBA8(mChild, 200, 200, 200);
-
-    {
-        mCapture = screenshot();
-
-        mCapture->expectChildColor(0, 0);
-        mCapture->expectChildColor(63, 63);
-        mCapture->expectBGColor(64, 64);
-    }
-
-    asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
-    sp<Surface> s = mFGSurfaceControl->getSurface();
-    auto anw = static_cast<ANativeWindow*>(s.get());
-    // Apply a 90 transform on the buffer.
-    native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
-    native_window_set_buffers_dimensions(anw, 64, 128);
-    fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
-    waitForPostedBuffers();
-
-    // The child should be cropped by the new parent bounds.
-    {
-        mCapture = screenshot();
-        mCapture->expectChildColor(0, 0);
-        mCapture->expectChildColor(99, 63);
-        mCapture->expectFGColor(100, 63);
-        mCapture->expectBGColor(128, 64);
-    }
-}
-
-// A child with a scale transform from its parents should be cropped by its parent bounds.
-TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferScale) {
-    asTransaction([&](Transaction& t) {
-        t.show(mChild);
-        t.setPosition(mChild, 0, 0);
-        t.setPosition(mFGSurfaceControl, 0, 0);
-        t.setSize(mChild, 200, 200);
-    });
-    fillSurfaceRGBA8(mChild, 200, 200, 200);
-
-    {
-        mCapture = screenshot();
-
-        mCapture->expectChildColor(0, 0);
-        mCapture->expectChildColor(63, 63);
-        mCapture->expectBGColor(64, 64);
-    }
-
-    asTransaction([&](Transaction& t) {
-        t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-        // Set a scaling by 2.
-        t.setSize(mFGSurfaceControl, 128, 128);
-    });
-
-    // Child should inherit its parents scale but should be cropped by its parent bounds.
-    {
-        mCapture = screenshot();
-        mCapture->expectChildColor(0, 0);
-        mCapture->expectChildColor(127, 127);
-        mCapture->expectBGColor(128, 128);
-    }
-}
-
-// Regression test for b/127368943
-// Child should ignore the buffer transform but apply parent scale transform.
-TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) {
-    asTransaction([&](Transaction& t) {
-        t.show(mChild);
-        t.setPosition(mChild, 0, 0);
-        t.setPosition(mFGSurfaceControl, 0, 0);
-    });
-
-    {
-        mCapture = screenshot();
-        mCapture->expectChildColor(0, 0);
-        mCapture->expectChildColor(9, 14);
-        mCapture->expectFGColor(10, 15);
-    }
-
-    // Change the size of the foreground to 128 * 64 so we can test rotation as well.
-    asTransaction([&](Transaction& t) {
-        t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-        t.setSize(mFGSurfaceControl, 128, 64);
-    });
-    sp<Surface> s = mFGSurfaceControl->getSurface();
-    auto anw = static_cast<ANativeWindow*>(s.get());
-    // Apply a 90 transform on the buffer and submit a buffer half the expected size so that we
-    // have an effective scale of 2.0 applied to the buffer along with a rotation transform.
-    native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
-    native_window_set_buffers_dimensions(anw, 32, 64);
-    fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
-    waitForPostedBuffers();
-
-    // The child should ignore the buffer transform but apply the 2.0 scale from parent.
-    {
-        mCapture = screenshot();
-        mCapture->expectChildColor(0, 0);
-        mCapture->expectChildColor(19, 29);
-        mCapture->expectFGColor(20, 30);
-    }
-}
-
-TEST_F(ChildLayerTest, Bug36858924) {
-    // Destroy the child layer
-    mChild.clear();
-
-    // Now recreate it as hidden
-    mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888,
-                           ISurfaceComposerClient::eHidden, mFGSurfaceControl.get());
-
-    // Show the child layer in a deferred transaction
-    asTransaction([&](Transaction& t) {
-        t.deferTransactionUntil_legacy(mChild, mFGSurfaceControl->getHandle(),
-                                       mFGSurfaceControl->getSurface()->getNextFrameNumber());
-        t.show(mChild);
-    });
-
-    // Render the foreground surface a few times
-    //
-    // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third
-    // frame because SurfaceFlinger would never process the deferred transaction and would therefore
-    // never acquire/release the first buffer
-    ALOGI("Filling 1");
-    fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
-    ALOGI("Filling 2");
-    fillSurfaceRGBA8(mFGSurfaceControl, 0, 0, 255);
-    ALOGI("Filling 3");
-    fillSurfaceRGBA8(mFGSurfaceControl, 255, 0, 0);
-    ALOGI("Filling 4");
-    fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
-}
-
-TEST_F(ChildLayerTest, Reparent) {
-    asTransaction([&](Transaction& t) {
-        t.show(mChild);
-        t.setPosition(mChild, 10, 10);
-        t.setPosition(mFGSurfaceControl, 64, 64);
-    });
-
-    {
-        mCapture = screenshot();
-        // Top left of foreground must now be visible
-        mCapture->expectFGColor(64, 64);
-        // But 10 pixels in we should see the child surface
-        mCapture->expectChildColor(74, 74);
-        // And 10 more pixels we should be back to the foreground surface
-        mCapture->expectFGColor(84, 84);
-    }
-
-    asTransaction([&](Transaction& t) { t.reparent(mChild, mBGSurfaceControl->getHandle()); });
-
-    {
-        mCapture = screenshot();
-        mCapture->expectFGColor(64, 64);
-        // In reparenting we should have exposed the entire foreground surface.
-        mCapture->expectFGColor(74, 74);
-        // And the child layer should now begin at 10, 10 (since the BG
-        // layer is at (0, 0)).
-        mCapture->expectBGColor(9, 9);
-        mCapture->expectChildColor(10, 10);
-    }
-}
-
-TEST_F(ChildLayerTest, ReparentToNoParent) {
-    asTransaction([&](Transaction& t) {
-        t.show(mChild);
-        t.setPosition(mChild, 10, 10);
-        t.setPosition(mFGSurfaceControl, 64, 64);
-    });
-
-    {
-        mCapture = screenshot();
-        // Top left of foreground must now be visible
-        mCapture->expectFGColor(64, 64);
-        // But 10 pixels in we should see the child surface
-        mCapture->expectChildColor(74, 74);
-        // And 10 more pixels we should be back to the foreground surface
-        mCapture->expectFGColor(84, 84);
-    }
-    asTransaction([&](Transaction& t) { t.reparent(mChild, nullptr); });
-    {
-        mCapture = screenshot();
-        // The surface should now be offscreen.
-        mCapture->expectFGColor(64, 64);
-        mCapture->expectFGColor(74, 74);
-        mCapture->expectFGColor(84, 84);
-    }
-}
-
-TEST_F(ChildLayerTest, ReparentFromNoParent) {
-    sp<SurfaceControl> newSurface = createLayer(String8("New Surface"), 10, 10, 0);
-    ASSERT_TRUE(newSurface != nullptr);
-    ASSERT_TRUE(newSurface->isValid());
-
-    fillSurfaceRGBA8(newSurface, 63, 195, 63);
-    asTransaction([&](Transaction& t) {
-        t.hide(mChild);
-        t.show(newSurface);
-        t.setPosition(newSurface, 10, 10);
-        t.setLayer(newSurface, INT32_MAX - 2);
-        t.setPosition(mFGSurfaceControl, 64, 64);
-    });
-
-    {
-        mCapture = screenshot();
-        // Top left of foreground must now be visible
-        mCapture->expectFGColor(64, 64);
-        // At 10, 10 we should see the new surface
-        mCapture->checkPixel(10, 10, 63, 195, 63);
-    }
-
-    asTransaction([&](Transaction& t) { t.reparent(newSurface, mFGSurfaceControl->getHandle()); });
-
-    {
-        mCapture = screenshot();
-        // newSurface will now be a child of mFGSurface so it will be 10, 10 offset from
-        // mFGSurface, putting it at 74, 74.
-        mCapture->expectFGColor(64, 64);
-        mCapture->checkPixel(74, 74, 63, 195, 63);
-        mCapture->expectFGColor(84, 84);
-    }
-}
-
-TEST_F(ChildLayerTest, NestedChildren) {
-    sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 10, 10,
-                                                  PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
-    fillSurfaceRGBA8(grandchild, 50, 50, 50);
-
-    {
-        mCapture = screenshot();
-        // Expect the grandchild to begin at 64, 64 because it's a child of mChild layer
-        // which begins at 64, 64
-        mCapture->checkPixel(64, 64, 50, 50, 50);
-    }
-}
-
-TEST_F(ChildLayerTest, ChildLayerRelativeLayer) {
-    sp<SurfaceControl> relative = createLayer(String8("Relative surface"), 128, 128, 0);
-    fillSurfaceRGBA8(relative, 255, 255, 255);
-
-    Transaction t;
-    t.setLayer(relative, INT32_MAX)
-            .setRelativeLayer(mChild, relative->getHandle(), 1)
-            .setPosition(mFGSurfaceControl, 0, 0)
-            .apply(true);
-
-    // We expect that the child should have been elevated above our
-    // INT_MAX layer even though it's not a child of it.
-    {
-        mCapture = screenshot();
-        mCapture->expectChildColor(0, 0);
-        mCapture->expectChildColor(9, 9);
-        mCapture->checkPixel(10, 10, 255, 255, 255);
-    }
-}
-
-class BoundlessLayerTest : public LayerUpdateTest {
-protected:
-    std::unique_ptr<ScreenCapture> mCapture;
-};
-
-// Verify setting a size on a buffer layer has no effect.
-TEST_F(BoundlessLayerTest, BufferLayerIgnoresSize) {
-    sp<SurfaceControl> bufferLayer =
-            createSurface(mClient, "BufferLayer", 45, 45, PIXEL_FORMAT_RGBA_8888, 0,
-                          mFGSurfaceControl.get());
-    ASSERT_TRUE(bufferLayer->isValid());
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::BLACK, 30, 30));
-    asTransaction([&](Transaction& t) { t.show(bufferLayer); });
-    {
-        mCapture = screenshot();
-        // Top left of background must now be visible
-        mCapture->expectBGColor(0, 0);
-        // Foreground Surface bounds must be color layer
-        mCapture->expectColor(Rect(64, 64, 94, 94), Color::BLACK);
-        // Buffer layer should not extend past buffer bounds
-        mCapture->expectFGColor(95, 95);
-    }
-}
-
-// Verify a boundless color layer will fill its parent bounds. The parent has a buffer size
-// which will crop the color layer.
-TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) {
-    sp<SurfaceControl> colorLayer =
-            createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
-                          ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
-    ASSERT_TRUE(colorLayer->isValid());
-    asTransaction([&](Transaction& t) {
-        t.setColor(colorLayer, half3{0, 0, 0});
-        t.show(colorLayer);
-    });
-    {
-        mCapture = screenshot();
-        // Top left of background must now be visible
-        mCapture->expectBGColor(0, 0);
-        // Foreground Surface bounds must be color layer
-        mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
-        // Color layer should not extend past foreground bounds
-        mCapture->expectBGColor(129, 129);
-    }
-}
-
-// Verify a boundless color layer will fill its parent bounds. The parent has no buffer but has
-// a crop which will be used to crop the color layer.
-TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) {
-    sp<SurfaceControl> cropLayer = createSurface(mClient, "CropLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
-                                                 0 /* flags */, mFGSurfaceControl.get());
-    ASSERT_TRUE(cropLayer->isValid());
-    sp<SurfaceControl> colorLayer =
-            createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
-                          ISurfaceComposerClient::eFXSurfaceColor, cropLayer.get());
-    ASSERT_TRUE(colorLayer->isValid());
-    asTransaction([&](Transaction& t) {
-        t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10));
-        t.setColor(colorLayer, half3{0, 0, 0});
-        t.show(cropLayer);
-        t.show(colorLayer);
-    });
-    {
-        mCapture = screenshot();
-        // Top left of background must now be visible
-        mCapture->expectBGColor(0, 0);
-        // Top left of foreground must now be visible
-        mCapture->expectFGColor(64, 64);
-        // 5 pixels from the foreground we should see the child surface
-        mCapture->expectColor(Rect(69, 69, 74, 74), Color::BLACK);
-        // 10 pixels from the foreground we should be back to the foreground surface
-        mCapture->expectFGColor(74, 74);
-    }
-}
-
-// Verify for boundless layer with no children, their transforms have no effect.
-TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) {
-    sp<SurfaceControl> colorLayer =
-            createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
-                          ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
-    ASSERT_TRUE(colorLayer->isValid());
-    asTransaction([&](Transaction& t) {
-        t.setPosition(colorLayer, 320, 320);
-        t.setMatrix(colorLayer, 2, 0, 0, 2);
-        t.setColor(colorLayer, half3{0, 0, 0});
-        t.show(colorLayer);
-    });
-    {
-        mCapture = screenshot();
-        // Top left of background must now be visible
-        mCapture->expectBGColor(0, 0);
-        // Foreground Surface bounds must be color layer
-        mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
-        // Color layer should not extend past foreground bounds
-        mCapture->expectBGColor(129, 129);
-    }
-}
-
-// Verify for boundless layer with children, their transforms have an effect.
-TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerCanSetTransform) {
-    sp<SurfaceControl> boundlessLayerRightShift =
-            createSurface(mClient, "BoundlessLayerRightShift", 0, 0, PIXEL_FORMAT_RGBA_8888,
-                          0 /* flags */, mFGSurfaceControl.get());
-    ASSERT_TRUE(boundlessLayerRightShift->isValid());
-    sp<SurfaceControl> boundlessLayerDownShift =
-            createSurface(mClient, "BoundlessLayerLeftShift", 0, 0, PIXEL_FORMAT_RGBA_8888,
-                          0 /* flags */, boundlessLayerRightShift.get());
-    ASSERT_TRUE(boundlessLayerDownShift->isValid());
-    sp<SurfaceControl> colorLayer =
-            createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
-                          ISurfaceComposerClient::eFXSurfaceColor, boundlessLayerDownShift.get());
-    ASSERT_TRUE(colorLayer->isValid());
-    asTransaction([&](Transaction& t) {
-        t.setPosition(boundlessLayerRightShift, 32, 0);
-        t.show(boundlessLayerRightShift);
-        t.setPosition(boundlessLayerDownShift, 0, 32);
-        t.show(boundlessLayerDownShift);
-        t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
-        t.setColor(colorLayer, half3{0, 0, 0});
-        t.show(colorLayer);
-    });
-    {
-        mCapture = screenshot();
-        // Top left of background must now be visible
-        mCapture->expectBGColor(0, 0);
-        // Top left of foreground must now be visible
-        mCapture->expectFGColor(64, 64);
-        // Foreground Surface bounds must be color layer
-        mCapture->expectColor(Rect(96, 96, 128, 128), Color::BLACK);
-        // Color layer should not extend past foreground bounds
-        mCapture->expectBGColor(129, 129);
-    }
-}
-
-// Verify child layers do not get clipped if they temporarily move into the negative
-// coordinate space as the result of an intermediate transformation.
-TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) {
-    sp<SurfaceControl> boundlessLayer =
-            mClient->createSurface(String8("BoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
-                                   0 /* flags */, mFGSurfaceControl.get());
-    ASSERT_TRUE(boundlessLayer != nullptr);
-    ASSERT_TRUE(boundlessLayer->isValid());
-    sp<SurfaceControl> colorLayer =
-            mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
-                                   ISurfaceComposerClient::eFXSurfaceColor, boundlessLayer.get());
-    ASSERT_TRUE(colorLayer != nullptr);
-    ASSERT_TRUE(colorLayer->isValid());
-    asTransaction([&](Transaction& t) {
-        // shift child layer off bounds. If this layer was not boundless, we will
-        // expect the child layer to be cropped.
-        t.setPosition(boundlessLayer, 32, 32);
-        t.show(boundlessLayer);
-        t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
-        // undo shift by parent
-        t.setPosition(colorLayer, -32, -32);
-        t.setColor(colorLayer, half3{0, 0, 0});
-        t.show(colorLayer);
-    });
-    {
-        mCapture = screenshot();
-        // Top left of background must now be visible
-        mCapture->expectBGColor(0, 0);
-        // Foreground Surface bounds must be color layer
-        mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
-        // Color layer should not extend past foreground bounds
-        mCapture->expectBGColor(129, 129);
-    }
-}
-
-// Verify for boundless root layers with children, their transforms have an effect.
-TEST_F(BoundlessLayerTest, RootBoundlessLayerCanSetTransform) {
-    sp<SurfaceControl> rootBoundlessLayer = createSurface(mClient, "RootBoundlessLayer", 0, 0,
-                                                          PIXEL_FORMAT_RGBA_8888, 0 /* flags */);
-    ASSERT_TRUE(rootBoundlessLayer->isValid());
-    sp<SurfaceControl> colorLayer =
-            createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
-                          ISurfaceComposerClient::eFXSurfaceColor, rootBoundlessLayer.get());
-
-    ASSERT_TRUE(colorLayer->isValid());
-    asTransaction([&](Transaction& t) {
-        t.setLayer(rootBoundlessLayer, INT32_MAX - 1);
-        t.setPosition(rootBoundlessLayer, 32, 32);
-        t.show(rootBoundlessLayer);
-        t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
-        t.setColor(colorLayer, half3{0, 0, 0});
-        t.show(colorLayer);
-        t.hide(mFGSurfaceControl);
-    });
-    {
-        mCapture = screenshot();
-        // Top left of background must now be visible
-        mCapture->expectBGColor(0, 0);
-        // Top left of foreground must now be visible
-        mCapture->expectBGColor(31, 31);
-        // Foreground Surface bounds must be color layer
-        mCapture->expectColor(Rect(32, 32, 96, 96), Color::BLACK);
-        // Color layer should not extend past foreground bounds
-        mCapture->expectBGColor(97, 97);
-    }
-}
-
-class ScreenCaptureTest : public LayerUpdateTest {
-protected:
-    std::unique_ptr<ScreenCapture> mCapture;
-};
-
-TEST_F(ScreenCaptureTest, CaptureSingleLayer) {
-    auto bgHandle = mBGSurfaceControl->getHandle();
-    ScreenCapture::captureLayers(&mCapture, bgHandle);
-    mCapture->expectBGColor(0, 0);
-    // Doesn't capture FG layer which is at 64, 64
-    mCapture->expectBGColor(64, 64);
-}
-
-TEST_F(ScreenCaptureTest, CaptureLayerWithChild) {
-    auto fgHandle = mFGSurfaceControl->getHandle();
-
-    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
-                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-    fillSurfaceRGBA8(child, 200, 200, 200);
-
-    SurfaceComposerClient::Transaction().show(child).apply(true);
-
-    // Captures mFGSurfaceControl layer and its child.
-    ScreenCapture::captureLayers(&mCapture, fgHandle);
-    mCapture->expectFGColor(10, 10);
-    mCapture->expectChildColor(0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureLayerChildOnly) {
-    auto fgHandle = mFGSurfaceControl->getHandle();
-
-    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
-                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-    fillSurfaceRGBA8(child, 200, 200, 200);
-
-    SurfaceComposerClient::Transaction().show(child).apply(true);
-
-    // Captures mFGSurfaceControl's child
-    ScreenCapture::captureChildLayers(&mCapture, fgHandle);
-    mCapture->checkPixel(10, 10, 0, 0, 0);
-    mCapture->expectChildColor(0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureLayerExclude) {
-    auto fgHandle = mFGSurfaceControl->getHandle();
-
-    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
-                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-    fillSurfaceRGBA8(child, 200, 200, 200);
-    sp<SurfaceControl> child2 = createSurface(mClient, "Child surface", 10, 10,
-                                              PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-    fillSurfaceRGBA8(child2, 200, 0, 200);
-
-    SurfaceComposerClient::Transaction()
-            .show(child)
-            .show(child2)
-            .setLayer(child, 1)
-            .setLayer(child2, 2)
-            .apply(true);
-
-    // Child2 would be visible but its excluded, so we should see child1 color instead.
-    ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
-    mCapture->checkPixel(10, 10, 0, 0, 0);
-    mCapture->checkPixel(0, 0, 200, 200, 200);
-}
-
-// Like the last test but verifies that children are also exclude.
-TEST_F(ScreenCaptureTest, CaptureLayerExcludeTree) {
-    auto fgHandle = mFGSurfaceControl->getHandle();
-
-    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
-                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-    fillSurfaceRGBA8(child, 200, 200, 200);
-    sp<SurfaceControl> child2 = createSurface(mClient, "Child surface", 10, 10,
-                                              PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-    fillSurfaceRGBA8(child2, 200, 0, 200);
-    sp<SurfaceControl> child3 = createSurface(mClient, "Child surface", 10, 10,
-                                              PIXEL_FORMAT_RGBA_8888, 0, child2.get());
-    fillSurfaceRGBA8(child2, 200, 0, 200);
-
-    SurfaceComposerClient::Transaction()
-            .show(child)
-            .show(child2)
-            .show(child3)
-            .setLayer(child, 1)
-            .setLayer(child2, 2)
-            .apply(true);
-
-    // Child2 would be visible but its excluded, so we should see child1 color instead.
-    ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
-    mCapture->checkPixel(10, 10, 0, 0, 0);
-    mCapture->checkPixel(0, 0, 200, 200, 200);
-}
-
-TEST_F(ScreenCaptureTest, CaptureTransparent) {
-    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
-                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
-    fillSurfaceRGBA8(child, 200, 200, 200);
-
-    SurfaceComposerClient::Transaction().show(child).apply(true);
-
-    auto childHandle = child->getHandle();
-
-    // Captures child
-    ScreenCapture::captureLayers(&mCapture, childHandle, {0, 0, 10, 20});
-    mCapture->expectColor(Rect(0, 0, 9, 9), {200, 200, 200, 255});
-    // Area outside of child's bounds is transparent.
-    mCapture->expectColor(Rect(0, 10, 9, 19), {0, 0, 0, 0});
-}
-
-TEST_F(ScreenCaptureTest, DontCaptureRelativeOutsideTree) {
-    auto fgHandle = mFGSurfaceControl->getHandle();
-
-    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
-                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-    ASSERT_NE(nullptr, child.get()) << "failed to create surface";
-    sp<SurfaceControl> relative = createLayer(String8("Relative surface"), 10, 10, 0);
-    fillSurfaceRGBA8(child, 200, 200, 200);
-    fillSurfaceRGBA8(relative, 100, 100, 100);
-
-    SurfaceComposerClient::Transaction()
-            .show(child)
-            // Set relative layer above fg layer so should be shown above when computing all layers.
-            .setRelativeLayer(relative, fgHandle, 1)
-            .show(relative)
-            .apply(true);
-
-    // Captures mFGSurfaceControl layer and its child. Relative layer shouldn't be captured.
-    ScreenCapture::captureLayers(&mCapture, fgHandle);
-    mCapture->expectFGColor(10, 10);
-    mCapture->expectChildColor(0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureRelativeInTree) {
-    auto fgHandle = mFGSurfaceControl->getHandle();
-
-    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
-                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-    sp<SurfaceControl> relative = createSurface(mClient, "Relative surface", 10, 10,
-                                                PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-    fillSurfaceRGBA8(child, 200, 200, 200);
-    fillSurfaceRGBA8(relative, 100, 100, 100);
-
-    SurfaceComposerClient::Transaction()
-            .show(child)
-            // Set relative layer below fg layer but relative to child layer so it should be shown
-            // above child layer.
-            .setLayer(relative, -1)
-            .setRelativeLayer(relative, child->getHandle(), 1)
-            .show(relative)
-            .apply(true);
-
-    // Captures mFGSurfaceControl layer and its children. Relative layer is a child of fg so its
-    // relative value should be taken into account, placing it above child layer.
-    ScreenCapture::captureLayers(&mCapture, fgHandle);
-    mCapture->expectFGColor(10, 10);
-    // Relative layer is showing on top of child layer
-    mCapture->expectColor(Rect(0, 0, 9, 9), {100, 100, 100, 255});
-}
-
-// In the following tests we verify successful skipping of a parent layer,
-// so we use the same verification logic and only change how we mutate
-// the parent layer to verify that various properties are ignored.
-class ScreenCaptureChildOnlyTest : public LayerUpdateTest {
-public:
-    void SetUp() override {
-        LayerUpdateTest::SetUp();
-
-        mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0,
-                               mFGSurfaceControl.get());
-        fillSurfaceRGBA8(mChild, 200, 200, 200);
-
-        SurfaceComposerClient::Transaction().show(mChild).apply(true);
-    }
-
-    void verify(std::function<void()> verifyStartingState) {
-        // Verify starting state before a screenshot is taken.
-        verifyStartingState();
-
-        // Verify child layer does not inherit any of the properties of its
-        // parent when its screenshot is captured.
-        auto fgHandle = mFGSurfaceControl->getHandle();
-        ScreenCapture::captureChildLayers(&mCapture, fgHandle);
-        mCapture->checkPixel(10, 10, 0, 0, 0);
-        mCapture->expectChildColor(0, 0);
-
-        // Verify all assumptions are still true after the screenshot is taken.
-        verifyStartingState();
-    }
-
-    std::unique_ptr<ScreenCapture> mCapture;
-    sp<SurfaceControl> mChild;
-};
-
-// Regression test b/76099859
-TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentVisibility) {
-
-    SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
-
-    // Even though the parent is hidden we should still capture the child.
-
-    // Before and after reparenting, verify child is properly hidden
-    // when rendering full-screen.
-    verify([&] { screenshot()->expectBGColor(64, 64); });
-}
-
-TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentCrop) {
-    SurfaceComposerClient::Transaction()
-            .setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 1, 1))
-            .apply(true);
-
-    // Even though the parent is cropped out we should still capture the child.
-
-    // Before and after reparenting, verify child is cropped by parent.
-    verify([&] { screenshot()->expectBGColor(65, 65); });
-}
-
-// Regression test b/124372894
-TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) {
-    SurfaceComposerClient::Transaction().setMatrix(mFGSurfaceControl, 2, 0, 0, 2).apply(true);
-
-    // We should not inherit the parent scaling.
-
-    // Before and after reparenting, verify child is properly scaled.
-    verify([&] { screenshot()->expectChildColor(80, 80); });
-}
-
-
-TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) {
-    auto fgHandle = mFGSurfaceControl->getHandle();
-
-    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
-                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-    fillSurfaceRGBA8(child, 200, 200, 200);
-
-    sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 5, 5,
-                                                  PIXEL_FORMAT_RGBA_8888, 0, child.get());
-
-    fillSurfaceRGBA8(grandchild, 50, 50, 50);
-    SurfaceComposerClient::Transaction()
-            .show(child)
-            .setPosition(grandchild, 5, 5)
-            .show(grandchild)
-            .apply(true);
-
-    // Captures mFGSurfaceControl, its child, and the grandchild.
-    ScreenCapture::captureLayers(&mCapture, fgHandle);
-    mCapture->expectFGColor(10, 10);
-    mCapture->expectChildColor(0, 0);
-    mCapture->checkPixel(5, 5, 50, 50, 50);
-}
-
-TEST_F(ScreenCaptureTest, CaptureChildOnly) {
-    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
-                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-    fillSurfaceRGBA8(child, 200, 200, 200);
-    auto childHandle = child->getHandle();
-
-    SurfaceComposerClient::Transaction().setPosition(child, 5, 5).show(child).apply(true);
-
-    // Captures only the child layer, and not the parent.
-    ScreenCapture::captureLayers(&mCapture, childHandle);
-    mCapture->expectChildColor(0, 0);
-    mCapture->expectChildColor(9, 9);
-}
-
-TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) {
-    sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
-                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-    fillSurfaceRGBA8(child, 200, 200, 200);
-    auto childHandle = child->getHandle();
-
-    sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 5, 5,
-                                                  PIXEL_FORMAT_RGBA_8888, 0, child.get());
-    fillSurfaceRGBA8(grandchild, 50, 50, 50);
-
-    SurfaceComposerClient::Transaction()
-            .show(child)
-            .setPosition(grandchild, 5, 5)
-            .show(grandchild)
-            .apply(true);
-
-    auto grandchildHandle = grandchild->getHandle();
-
-    // Captures only the grandchild.
-    ScreenCapture::captureLayers(&mCapture, grandchildHandle);
-    mCapture->checkPixel(0, 0, 50, 50, 50);
-    mCapture->checkPixel(4, 4, 50, 50, 50);
-}
-
-TEST_F(ScreenCaptureTest, CaptureCrop) {
-    sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
-    sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
-                                                 PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
-
-    SurfaceComposerClient::Transaction()
-            .setLayer(redLayer, INT32_MAX - 1)
-            .show(redLayer)
-            .show(blueLayer)
-            .apply(true);
-
-    auto redLayerHandle = redLayer->getHandle();
-
-    // Capturing full screen should have both red and blue are visible.
-    ScreenCapture::captureLayers(&mCapture, redLayerHandle);
-    mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
-    // red area below the blue area
-    mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
-    // red area to the right of the blue area
-    mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
-
-    const Rect crop = Rect(0, 0, 30, 30);
-    ScreenCapture::captureLayers(&mCapture, redLayerHandle, crop);
-    // Capturing the cropped screen, cropping out the shown red area, should leave only the blue
-    // area visible.
-    mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
-    mCapture->checkPixel(30, 30, 0, 0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureSize) {
-    sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
-    sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
-                                                 PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
-
-    SurfaceComposerClient::Transaction()
-            .setLayer(redLayer, INT32_MAX - 1)
-            .show(redLayer)
-            .show(blueLayer)
-            .apply(true);
-
-    auto redLayerHandle = redLayer->getHandle();
-
-    // Capturing full screen should have both red and blue are visible.
-    ScreenCapture::captureLayers(&mCapture, redLayerHandle);
-    mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
-    // red area below the blue area
-    mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
-    // red area to the right of the blue area
-    mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
-
-    ScreenCapture::captureLayers(&mCapture, redLayerHandle, Rect::EMPTY_RECT, 0.5);
-    // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area.
-    mCapture->expectColor(Rect(0, 0, 14, 14), Color::BLUE);
-    // red area below the blue area
-    mCapture->expectColor(Rect(0, 15, 29, 29), Color::RED);
-    // red area to the right of the blue area
-    mCapture->expectColor(Rect(15, 0, 29, 29), Color::RED);
-    mCapture->checkPixel(30, 30, 0, 0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
-    sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
-
-    ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
-
-    auto redLayerHandle = redLayer->getHandle();
-    redLayer.clear();
-    SurfaceComposerClient::Transaction().apply(true);
-
-    sp<GraphicBuffer> outBuffer;
-
-    // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, &outBuffer, Rect::EMPTY_RECT, 1.0));
-}
-
-
-class DereferenceSurfaceControlTest : public LayerTransactionTest {
-protected:
-    void SetUp() override {
-        LayerTransactionTest::SetUp();
-        bgLayer = createLayer("BG layer", 20, 20);
-        fillBufferQueueLayerColor(bgLayer, Color::RED, 20, 20);
-        fgLayer = createLayer("FG layer", 20, 20);
-        fillBufferQueueLayerColor(fgLayer, Color::BLUE, 20, 20);
-        Transaction().setLayer(fgLayer, mLayerZBase + 1).apply();
-        {
-            SCOPED_TRACE("before anything");
-            auto shot = screenshot();
-            shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
-        }
-    }
-    void TearDown() override {
-        LayerTransactionTest::TearDown();
-        bgLayer = 0;
-        fgLayer = 0;
-    }
-
-    sp<SurfaceControl> bgLayer;
-    sp<SurfaceControl> fgLayer;
-};
-
-TEST_F(DereferenceSurfaceControlTest, LayerNotInTransaction) {
-    fgLayer = nullptr;
-    {
-        SCOPED_TRACE("after setting null");
-        auto shot = screenshot();
-        shot->expectColor(Rect(0, 0, 20, 20), Color::RED);
-    }
-}
-
-TEST_F(DereferenceSurfaceControlTest, LayerInTransaction) {
-    auto transaction = Transaction().show(fgLayer);
-    fgLayer = nullptr;
-    {
-        SCOPED_TRACE("after setting null");
-        auto shot = screenshot();
-        shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
-    }
-}
-
-class MultiDisplayLayerBoundsTest : public LayerTransactionTest {
-protected:
-    virtual void SetUp() {
-        LayerTransactionTest::SetUp();
-        ASSERT_EQ(NO_ERROR, mClient->initCheck());
-
-        mMainDisplay = SurfaceComposerClient::getInternalDisplayToken();
-        SurfaceComposerClient::getDisplayInfo(mMainDisplay, &mMainDisplayInfo);
-
-        sp<IGraphicBufferConsumer> consumer;
-        BufferQueue::createBufferQueue(&mProducer, &consumer);
-        consumer->setConsumerName(String8("Virtual disp consumer"));
-        consumer->setDefaultBufferSize(mMainDisplayInfo.w, mMainDisplayInfo.h);
-    }
-
-    virtual void TearDown() {
-        SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
-        LayerTransactionTest::TearDown();
-        mColorLayer = 0;
-    }
-
-    void createDisplay(const Rect& layerStackRect, uint32_t layerStack) {
-        mVirtualDisplay =
-                SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), false /*secure*/);
-        asTransaction([&](Transaction& t) {
-            t.setDisplaySurface(mVirtualDisplay, mProducer);
-            t.setDisplayLayerStack(mVirtualDisplay, layerStack);
-            t.setDisplayProjection(mVirtualDisplay, mMainDisplayInfo.orientation, layerStackRect,
-                                   Rect(mMainDisplayInfo.w, mMainDisplayInfo.h));
-        });
-    }
-
-    void createColorLayer(uint32_t layerStack) {
-        mColorLayer =
-                createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */,
-                              PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
-        ASSERT_TRUE(mColorLayer != nullptr);
-        ASSERT_TRUE(mColorLayer->isValid());
-        asTransaction([&](Transaction& t) {
-            t.setLayerStack(mColorLayer, layerStack);
-            t.setCrop_legacy(mColorLayer, Rect(0, 0, 30, 40));
-            t.setLayer(mColorLayer, INT32_MAX - 2);
-            t.setColor(mColorLayer,
-                       half3{mExpectedColor.r / 255.0f, mExpectedColor.g / 255.0f,
-                             mExpectedColor.b / 255.0f});
-            t.show(mColorLayer);
-        });
-    }
-
-    DisplayInfo mMainDisplayInfo;
-    sp<IBinder> mMainDisplay;
-    sp<IBinder> mVirtualDisplay;
-    sp<IGraphicBufferProducer> mProducer;
-    sp<SurfaceControl> mColorLayer;
-    Color mExpectedColor = {63, 63, 195, 255};
-};
-
-TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) {
-    createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 1 /* layerStack */);
-    createColorLayer(1 /* layerStack */);
-
-    asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
-
-    // Verify color layer does not render on main display.
-    std::unique_ptr<ScreenCapture> sc;
-    ScreenCapture::captureScreen(&sc, mMainDisplay);
-    sc->expectColor(Rect(10, 10, 40, 50), {0, 0, 0, 255});
-    sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
-
-    // Verify color layer renders correctly on virtual display.
-    ScreenCapture::captureScreen(&sc, mVirtualDisplay);
-    sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
-    sc->expectColor(Rect(1, 1, 9, 9), {0, 0, 0, 0});
-}
-
-TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) {
-    // Create a display and set its layer stack to the main display's layer stack so
-    // the contents of the main display are mirrored on to the virtual display.
-
-    // Assumption here is that the new mirrored display has the same viewport as the
-    // primary display that it is mirroring.
-    createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 0 /* layerStack */);
-    createColorLayer(0 /* layerStack */);
-
-    asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
-
-    // Verify color layer renders correctly on main display and it is mirrored on the
-    // virtual display.
-    std::unique_ptr<ScreenCapture> sc;
-    ScreenCapture::captureScreen(&sc, mMainDisplay);
-    sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
-    sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
-
-    ScreenCapture::captureScreen(&sc, mVirtualDisplay);
-    sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
-    sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
-}
-
-class DisplayActiveConfigTest : public ::testing::Test {
-protected:
-    void SetUp() override {
-        mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
-        SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &mDisplayconfigs);
-        EXPECT_GT(mDisplayconfigs.size(), 0);
-
-        // set display power to on to make sure config can be changed
-        SurfaceComposerClient::setDisplayPowerMode(mDisplayToken, HWC_POWER_MODE_NORMAL);
-    }
-
-    sp<IBinder> mDisplayToken;
-    Vector<DisplayInfo> mDisplayconfigs;
-};
-
-TEST_F(DisplayActiveConfigTest, allConfigsAllowed) {
-    std::vector<int32_t> allowedConfigs;
-
-    // Add all configs to the allowed configs
-    for (int i = 0; i < mDisplayconfigs.size(); i++) {
-        allowedConfigs.push_back(i);
-    }
-
-    status_t res = SurfaceComposerClient::setAllowedDisplayConfigs(mDisplayToken, allowedConfigs);
-    EXPECT_EQ(res, NO_ERROR);
-
-    std::vector<int32_t> outConfigs;
-    res = SurfaceComposerClient::getAllowedDisplayConfigs(mDisplayToken, &outConfigs);
-    EXPECT_EQ(res, NO_ERROR);
-    EXPECT_EQ(allowedConfigs, outConfigs);
-}
-
-TEST_F(DisplayActiveConfigTest, changeAllowedConfig) {
-    // we need at least 2 configs available for this test
-    if (mDisplayconfigs.size() <= 1) return;
-
-    int activeConfig = SurfaceComposerClient::getActiveConfig(mDisplayToken);
-
-    // We want to set the allowed config to everything but the active config
-    std::vector<int32_t> allowedConfigs;
-    for (int i = 0; i < mDisplayconfigs.size(); i++) {
-        if (i != activeConfig) {
-            allowedConfigs.push_back(i);
-        }
-    }
-
-    status_t res = SurfaceComposerClient::setAllowedDisplayConfigs(mDisplayToken, allowedConfigs);
-    EXPECT_EQ(res, NO_ERROR);
-
-    // Allow some time for the config change
-    std::this_thread::sleep_for(200ms);
-
-    int newActiveConfig = SurfaceComposerClient::getActiveConfig(mDisplayToken);
-    EXPECT_NE(activeConfig, newActiveConfig);
-
-    // Make sure the new config is part of allowed config
-    EXPECT_TRUE(std::find(allowedConfigs.begin(), allowedConfigs.end(), newActiveConfig) !=
-                allowedConfigs.end());
-}
-
-class RelativeZTest : public LayerTransactionTest {
-protected:
-    virtual void SetUp() {
-        LayerTransactionTest::SetUp();
-        ASSERT_EQ(NO_ERROR, mClient->initCheck());
-
-        const auto display = SurfaceComposerClient::getInternalDisplayToken();
-        ASSERT_FALSE(display == nullptr);
-
-        // Back layer
-        mBackgroundLayer = createColorLayer("Background layer", Color::RED);
-
-        // Front layer
-        mForegroundLayer = createColorLayer("Foreground layer", Color::GREEN);
-
-        asTransaction([&](Transaction& t) {
-            t.setDisplayLayerStack(display, 0);
-            t.setLayer(mBackgroundLayer, INT32_MAX - 2).show(mBackgroundLayer);
-            t.setLayer(mForegroundLayer, INT32_MAX - 1).show(mForegroundLayer);
-        });
-    }
-
-    virtual void TearDown() {
-        LayerTransactionTest::TearDown();
-        mBackgroundLayer = 0;
-        mForegroundLayer = 0;
-    }
-
-    sp<SurfaceControl> mBackgroundLayer;
-    sp<SurfaceControl> mForegroundLayer;
-};
-
-// When a layer is reparented offscreen, remove relative z order if the relative parent
-// is still onscreen so that the layer is not drawn.
-TEST_F(RelativeZTest, LayerRemoved) {
-    std::unique_ptr<ScreenCapture> sc;
-
-    // Background layer (RED)
-    //   Child layer (WHITE) (relative to foregroud layer)
-    // Foregroud layer (GREEN)
-    sp<SurfaceControl> childLayer =
-            createColorLayer("Child layer", Color::BLUE, mBackgroundLayer.get());
-
-    Transaction{}
-            .setRelativeLayer(childLayer, mForegroundLayer->getHandle(), 1)
-            .show(childLayer)
-            .apply();
-
-    {
-        // The childLayer should be in front of the FG control.
-        ScreenCapture::captureScreen(&sc);
-        sc->checkPixel(1, 1, Color::BLUE.r, Color::BLUE.g, Color::BLUE.b);
-    }
-
-    // Background layer (RED)
-    // Foregroud layer (GREEN)
-    Transaction{}.reparent(childLayer, nullptr).apply();
-
-    // Background layer (RED)
-    //   Child layer (WHITE)
-    // Foregroud layer (GREEN)
-    Transaction{}.reparent(childLayer, mBackgroundLayer->getHandle()).apply();
-
-    {
-        // The relative z info for child layer should be reset, leaving FG control on top.
-        ScreenCapture::captureScreen(&sc);
-        sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
-    }
-}
-
-// When a layer is reparented offscreen, preseve relative z order if the relative parent
-// is also offscreen. Regression test b/132613412
-TEST_F(RelativeZTest, LayerRemovedOffscreenRelativeParent) {
-    std::unique_ptr<ScreenCapture> sc;
-
-    // Background layer (RED)
-    // Foregroud layer (GREEN)
-    //   child level 1 (WHITE)
-    //     child level 2a (BLUE)
-    //       child level 3 (GREEN) (relative to child level 2b)
-    //     child level 2b (BLACK)
-    sp<SurfaceControl> childLevel1 =
-            createColorLayer("child level 1", Color::WHITE, mForegroundLayer.get());
-    sp<SurfaceControl> childLevel2a =
-            createColorLayer("child level 2a", Color::BLUE, childLevel1.get());
-    sp<SurfaceControl> childLevel2b =
-            createColorLayer("child level 2b", Color::BLACK, childLevel1.get());
-    sp<SurfaceControl> childLevel3 =
-            createColorLayer("child level 3", Color::GREEN, childLevel2a.get());
-
-    Transaction{}
-            .setRelativeLayer(childLevel3, childLevel2b->getHandle(), 1)
-            .show(childLevel2a)
-            .show(childLevel2b)
-            .show(childLevel3)
-            .apply();
-
-    {
-        // The childLevel3 should be in front of childLevel2b.
-        ScreenCapture::captureScreen(&sc);
-        sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
-    }
-
-    // Background layer (RED)
-    // Foregroud layer (GREEN)
-    Transaction{}.reparent(childLevel1, nullptr).apply();
-
-    // Background layer (RED)
-    // Foregroud layer (GREEN)
-    //   child level 1 (WHITE)
-    //     child level 2 back (BLUE)
-    //       child level 3 (GREEN) (relative to child level 2b)
-    //     child level 2 front (BLACK)
-    Transaction{}.reparent(childLevel1, mForegroundLayer->getHandle()).apply();
-
-    {
-        // Nothing should change at this point since relative z info was preserved.
-        ScreenCapture::captureScreen(&sc);
-        sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
-    }
-}
-
-// This test ensures that when we drop an app buffer in SurfaceFlinger, we merge
-// the dropped buffer's damage region into the next buffer's damage region. If
-// we don't do this, we'll report an incorrect damage region to hardware
-// composer, resulting in broken rendering. This test checks the BufferQueue
-// case.
-//
-// Unfortunately, we don't currently have a way to inspect the damage region
-// SurfaceFlinger sends to hardware composer from a test, so this test requires
-// the dev to manually watch the device's screen during the test to spot broken
-// rendering. Because the results can't be automatically verified, this test is
-// marked disabled.
-TEST_F(LayerTransactionTest, DISABLED_BufferQueueLayerMergeDamageRegionWhenDroppingBuffers) {
-    const int width = mDisplayWidth;
-    const int height = mDisplayHeight;
-    sp<SurfaceControl> layer;
-    ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
-    const auto producer = layer->getIGraphicBufferProducer();
-    const sp<IProducerListener> dummyListener(new DummyProducerListener);
-    IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
-    ASSERT_EQ(OK,
-              producer->connect(dummyListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput));
-
-    std::map<int, sp<GraphicBuffer>> slotMap;
-    auto slotToBuffer = [&](int slot, sp<GraphicBuffer>* buf) {
-        ASSERT_NE(nullptr, buf);
-        const auto iter = slotMap.find(slot);
-        ASSERT_NE(slotMap.end(), iter);
-        *buf = iter->second;
-    };
-
-    auto dequeue = [&](int* outSlot) {
-        ASSERT_NE(nullptr, outSlot);
-        *outSlot = -1;
-        int slot;
-        sp<Fence> fence;
-        uint64_t age;
-        FrameEventHistoryDelta timestamps;
-        const status_t dequeueResult =
-                producer->dequeueBuffer(&slot, &fence, width, height, PIXEL_FORMAT_RGBA_8888,
-                                        GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
-                                        &age, &timestamps);
-        if (dequeueResult == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
-            sp<GraphicBuffer> newBuf;
-            ASSERT_EQ(OK, producer->requestBuffer(slot, &newBuf));
-            ASSERT_NE(nullptr, newBuf.get());
-            slotMap[slot] = newBuf;
-        } else {
-            ASSERT_EQ(OK, dequeueResult);
-        }
-        *outSlot = slot;
-    };
-
-    auto queue = [&](int slot, const Region& damage, nsecs_t displayTime) {
-        IGraphicBufferProducer::QueueBufferInput input(
-                /*timestamp=*/displayTime, /*isAutoTimestamp=*/false, HAL_DATASPACE_UNKNOWN,
-                /*crop=*/Rect::EMPTY_RECT, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
-                /*transform=*/0, Fence::NO_FENCE);
-        input.setSurfaceDamage(damage);
-        IGraphicBufferProducer::QueueBufferOutput output;
-        ASSERT_EQ(OK, producer->queueBuffer(slot, input, &output));
-    };
-
-    auto fillAndPostBuffers = [&](const Color& color) {
-        int slot1;
-        ASSERT_NO_FATAL_FAILURE(dequeue(&slot1));
-        int slot2;
-        ASSERT_NO_FATAL_FAILURE(dequeue(&slot2));
-
-        sp<GraphicBuffer> buf1;
-        ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot1, &buf1));
-        sp<GraphicBuffer> buf2;
-        ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot2, &buf2));
-        fillGraphicBufferColor(buf1, Rect(width, height), color);
-        fillGraphicBufferColor(buf2, Rect(width, height), color);
-
-        const auto displayTime = systemTime() + milliseconds_to_nanoseconds(100);
-        ASSERT_NO_FATAL_FAILURE(queue(slot1, Region::INVALID_REGION, displayTime));
-        ASSERT_NO_FATAL_FAILURE(
-                queue(slot2, Region(Rect(width / 3, height / 3, 2 * width / 3, 2 * height / 3)),
-                      displayTime));
-    };
-
-    const auto startTime = systemTime();
-    const std::array<Color, 3> colors = {Color::RED, Color::GREEN, Color::BLUE};
-    int colorIndex = 0;
-    while (nanoseconds_to_seconds(systemTime() - startTime) < 10) {
-        ASSERT_NO_FATAL_FAILURE(fillAndPostBuffers(colors[colorIndex++ % colors.size()]));
-        std::this_thread::sleep_for(1s);
-    }
-
-    ASSERT_EQ(OK, producer->disconnect(NATIVE_WINDOW_API_CPU));
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 2feff45..2861013 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -10,32 +10,38 @@
     ],
     shared_libs: [
         "android.hardware.graphics.composer@2.1",
+        "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.3",
+        "android.hardware.graphics.composer@2.4",
+        "android.hardware.graphics.composer@2.1-resources",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@3.0",
+        "android.hardware.graphics.mapper@4.0",
         "android.hardware.power@1.3",
         "libbase",
         "libbinder",
         "libcutils",
         "libfmq",
         "libgui",
-        "libhardware",
         "libhidlbase",
         "liblayers_proto",
         "liblog",
         "libnativewindow",
         "libsync",
-        "libtimestats_proto",
+        "libtimestats",
         "libui",
         "libutils",
     ],
     static_libs: [
+        "libcompositionengine",
         "libgmock",
+        "libperfetto_client_experimental",
         "librenderengine",
         "libtrace_proto",
     ],
     header_libs: [
-        "android.hardware.graphics.composer@2.1-command-buffer",
-        "android.hardware.graphics.composer@2.1-hal",
+        "android.hardware.graphics.composer@2.4-command-buffer",
+        "android.hardware.graphics.composer@2.4-hal",
         "libsurfaceflinger_headers",
     ],
 }
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
index eeb6efe..5cbf2ef 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 //#define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "FakeComposer"
@@ -146,6 +150,7 @@
 
 FakeComposerClient::FakeComposerClient()
       : mEventCallback(nullptr),
+        mEventCallback_2_4(nullptr),
         mCurrentConfig(NULL_DISPLAY_CONFIG),
         mVsyncEnabled(false),
         mLayers(),
@@ -165,6 +170,9 @@
 
 void FakeComposerClient::registerEventCallback(EventCallback* callback) {
     ALOGV("registerEventCallback");
+    LOG_FATAL_IF(mEventCallback_2_4 != nullptr,
+                 "already registered using registerEventCallback_2_4");
+
     mEventCallback = callback;
     if (mEventCallback) {
         mEventCallback->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
@@ -179,12 +187,16 @@
 void FakeComposerClient::hotplugDisplay(Display display, IComposerCallback::Connection state) {
     if (mEventCallback) {
         mEventCallback->onHotplug(display, state);
+    } else if (mEventCallback_2_4) {
+        mEventCallback_2_4->onHotplug(display, state);
     }
 }
 
 void FakeComposerClient::refreshDisplay(Display display) {
     if (mEventCallback) {
         mEventCallback->onRefresh(display);
+    } else if (mEventCallback_2_4) {
+        mEventCallback_2_4->onRefresh(display);
     }
 }
 
@@ -193,33 +205,37 @@
     return 1;
 }
 
-Error FakeComposerClient::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/,
-                                               PixelFormat* /*format*/, Display* /*outDisplay*/) {
+V2_1::Error FakeComposerClient::createVirtualDisplay(uint32_t /*width*/, uint32_t /*height*/,
+                                                     V1_0::PixelFormat* /*format*/,
+                                                     Display* /*outDisplay*/) {
     ALOGV("createVirtualDisplay");
-    return Error::NONE;
+    return V2_1::Error::NONE;
 }
 
-Error FakeComposerClient::destroyVirtualDisplay(Display /*display*/) {
+V2_1::Error FakeComposerClient::destroyVirtualDisplay(Display /*display*/) {
     ALOGV("destroyVirtualDisplay");
-    return Error::NONE;
+    return V2_1::Error::NONE;
 }
 
-Error FakeComposerClient::createLayer(Display /*display*/, Layer* outLayer) {
+V2_1::Error FakeComposerClient::createLayer(Display /*display*/, Layer* outLayer) {
     ALOGV("createLayer");
     *outLayer = mLayers.size();
     auto newLayer = std::make_unique<LayerImpl>();
     mLayers.push_back(std::move(newLayer));
-    return Error::NONE;
+    return V2_1::Error::NONE;
 }
 
-Error FakeComposerClient::destroyLayer(Display /*display*/, Layer layer) {
+V2_1::Error FakeComposerClient::destroyLayer(Display /*display*/, Layer layer) {
     ALOGV("destroyLayer");
     mLayers[layer]->mValid = false;
-    return Error::NONE;
+    return V2_1::Error::NONE;
 }
 
-Error FakeComposerClient::getActiveConfig(Display /*display*/, Config* outConfig) {
+V2_1::Error FakeComposerClient::getActiveConfig(Display display, Config* outConfig) {
     ALOGV("getActiveConfig");
+    if (mMockHal) {
+        return mMockHal->getActiveConfig(display, outConfig);
+    }
 
     // TODO Assert outConfig != nullptr
 
@@ -227,30 +243,480 @@
     // IComposerClient::getActiveConfig, but returning BAD_CONFIG
     // seems to not fit SurfaceFlinger plans. See version 2 below.
     // if (mCurrentConfig == NULL_DISPLAY_CONFIG) {
-    //     return Error::BAD_CONFIG;
+    //     return V2_1::Error::BAD_CONFIG;
     // }
     //*outConfig = mCurrentConfig;
     *outConfig = 1; // Very special config for you my friend
-    return Error::NONE;
+    return V2_1::Error::NONE;
 }
 
-Error FakeComposerClient::getClientTargetSupport(Display /*display*/, uint32_t /*width*/,
-                                                 uint32_t /*height*/, PixelFormat /*format*/,
-                                                 Dataspace /*dataspace*/) {
+V2_1::Error FakeComposerClient::getClientTargetSupport(Display /*display*/, uint32_t /*width*/,
+                                                       uint32_t /*height*/,
+                                                       V1_0::PixelFormat /*format*/,
+                                                       V1_0::Dataspace /*dataspace*/) {
     ALOGV("getClientTargetSupport");
-    return Error::NONE;
+    return V2_1::Error::NONE;
 }
 
-Error FakeComposerClient::getColorModes(Display /*display*/, hidl_vec<ColorMode>* /*outModes*/) {
+V2_1::Error FakeComposerClient::getColorModes(Display /*display*/,
+                                              hidl_vec<V1_0::ColorMode>* /*outModes*/) {
     ALOGV("getColorModes");
-    return Error::NONE;
+    return V2_1::Error::NONE;
 }
 
-Error FakeComposerClient::getDisplayAttribute(Display display, Config config,
-                                              IComposerClient::Attribute attribute,
-                                              int32_t* outValue) {
+V2_1::Error FakeComposerClient::getDisplayAttribute(Display display, Config config,
+                                                    V2_1::IComposerClient::Attribute attribute,
+                                                    int32_t* outValue) {
+    auto tmpError =
+            getDisplayAttribute_2_4(display, config,
+                                    static_cast<IComposerClient::Attribute>(attribute), outValue);
+    return static_cast<V2_1::Error>(tmpError);
+}
+
+V2_1::Error FakeComposerClient::getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) {
+    ALOGV("getDisplayConfigs");
+    if (mMockHal) {
+        return mMockHal->getDisplayConfigs(display, outConfigs);
+    }
+
+    // TODO assert display == 1, outConfigs != nullptr
+
+    outConfigs->resize(1);
+    (*outConfigs)[0] = 1;
+
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::getDisplayName(Display /*display*/, hidl_string* /*outName*/) {
+    ALOGV("getDisplayName");
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::getDisplayType(Display /*display*/,
+                                               IComposerClient::DisplayType* outType) {
+    ALOGV("getDisplayType");
+    // TODO: This setting nothing on the output had no effect on initial trials. Is first display
+    // assumed to be physical?
+    *outType = static_cast<IComposerClient::DisplayType>(HWC2_DISPLAY_TYPE_PHYSICAL);
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::getDozeSupport(Display /*display*/, bool* /*outSupport*/) {
+    ALOGV("getDozeSupport");
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::getHdrCapabilities(Display /*display*/,
+                                                   hidl_vec<V1_0::Hdr>* /*outTypes*/,
+                                                   float* /*outMaxLuminance*/,
+                                                   float* /*outMaxAverageLuminance*/,
+                                                   float* /*outMinLuminance*/) {
+    ALOGV("getHdrCapabilities");
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setActiveConfig(Display display, Config config) {
+    ALOGV("setActiveConfig");
+    if (mMockHal) {
+        return mMockHal->setActiveConfig(display, config);
+    }
+    mCurrentConfig = config;
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setColorMode(Display /*display*/, V1_0::ColorMode /*mode*/) {
+    ALOGV("setColorMode");
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setPowerMode(Display /*display*/,
+                                             V2_1::IComposerClient::PowerMode /*mode*/) {
+    ALOGV("setPowerMode");
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setVsyncEnabled(Display /*display*/,
+                                                IComposerClient::Vsync enabled) {
+    mVsyncEnabled = (enabled == IComposerClient::Vsync::ENABLE);
+    ALOGV("setVsyncEnabled(%s)", mVsyncEnabled ? "ENABLE" : "DISABLE");
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setColorTransform(Display /*display*/, const float* /*matrix*/,
+                                                  int32_t /*hint*/) {
+    ALOGV("setColorTransform");
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setClientTarget(Display /*display*/, buffer_handle_t /*target*/,
+                                                int32_t /*acquireFence*/, int32_t /*dataspace*/,
+                                                const std::vector<hwc_rect_t>& /*damage*/) {
+    ALOGV("setClientTarget");
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setOutputBuffer(Display /*display*/, buffer_handle_t /*buffer*/,
+                                                int32_t /*releaseFence*/) {
+    ALOGV("setOutputBuffer");
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::validateDisplay(
+        Display /*display*/, std::vector<Layer>* /*outChangedLayers*/,
+        std::vector<IComposerClient::Composition>* /*outCompositionTypes*/,
+        uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/,
+        std::vector<uint32_t>* /*outRequestMasks*/) {
+    ALOGV("validateDisplay");
+    // TODO: Assume touching nothing means All Korrekt!
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::acceptDisplayChanges(Display /*display*/) {
+    ALOGV("acceptDisplayChanges");
+    // Didn't ask for changes because software is omnipotent.
+    return V2_1::Error::NONE;
+}
+
+bool layerZOrdering(const std::unique_ptr<FrameRect>& a, const std::unique_ptr<FrameRect>& b) {
+    return a->z <= b->z;
+}
+
+V2_1::Error FakeComposerClient::presentDisplay(Display /*display*/, int32_t* /*outPresentFence*/,
+                                               std::vector<Layer>* /*outLayers*/,
+                                               std::vector<int32_t>* /*outReleaseFences*/) {
+    ALOGV("presentDisplay");
+    // TODO Leaving layers and their fences out for now. Doing so
+    // means that we've already processed everything. Important to
+    // test that the fences are respected, though. (How?)
+
+    std::unique_ptr<Frame> newFrame(new Frame);
+    for (uint64_t layer = 0; layer < mLayers.size(); layer++) {
+        const LayerImpl& layerImpl = *mLayers[layer];
+
+        if (!layerImpl.mValid) continue;
+
+        auto rect = std::make_unique<FrameRect>(layer, layerImpl.mRenderState, layerImpl.mZ);
+        newFrame->rectangles.push_back(std::move(rect));
+    }
+    std::sort(newFrame->rectangles.begin(), newFrame->rectangles.end(), layerZOrdering);
+    {
+        Mutex::Autolock _l(mStateMutex);
+        mFrames.push_back(std::move(newFrame));
+        mFramesAvailable.broadcast();
+    }
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerCursorPosition(Display /*display*/, Layer /*layer*/,
+                                                       int32_t /*x*/, int32_t /*y*/) {
+    ALOGV("setLayerCursorPosition");
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerBuffer(Display /*display*/, Layer layer,
+                                               buffer_handle_t buffer, int32_t acquireFence) {
+    ALOGV("setLayerBuffer");
+    LayerImpl& l = getLayerImpl(layer);
+    if (buffer != l.mRenderState.mBuffer) {
+        l.mRenderState.mSwapCount++; // TODO: Is setting to same value a swap or not?
+    }
+    l.mRenderState.mBuffer = buffer;
+    l.mRenderState.mAcquireFence = acquireFence;
+
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerSurfaceDamage(Display /*display*/, Layer /*layer*/,
+                                                      const std::vector<hwc_rect_t>& /*damage*/) {
+    ALOGV("setLayerSurfaceDamage");
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerBlendMode(Display /*display*/, Layer layer, int32_t mode) {
+    ALOGV("setLayerBlendMode");
+    getLayerImpl(layer).mRenderState.mBlendMode = static_cast<hwc2_blend_mode_t>(mode);
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerColor(Display /*display*/, Layer layer,
+                                              IComposerClient::Color color) {
+    ALOGV("setLayerColor");
+    getLayerImpl(layer).mRenderState.mLayerColor.r = color.r;
+    getLayerImpl(layer).mRenderState.mLayerColor.g = color.g;
+    getLayerImpl(layer).mRenderState.mLayerColor.b = color.b;
+    getLayerImpl(layer).mRenderState.mLayerColor.a = color.a;
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerCompositionType(Display /*display*/, Layer /*layer*/,
+                                                        int32_t /*type*/) {
+    ALOGV("setLayerCompositionType");
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerDataspace(Display /*display*/, Layer /*layer*/,
+                                                  int32_t /*dataspace*/) {
+    ALOGV("setLayerDataspace");
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerDisplayFrame(Display /*display*/, Layer layer,
+                                                     const hwc_rect_t& frame) {
+    ALOGV("setLayerDisplayFrame (%d, %d, %d, %d)", frame.left, frame.top, frame.right,
+          frame.bottom);
+    getLayerImpl(layer).mRenderState.mDisplayFrame = frame;
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerPlaneAlpha(Display /*display*/, Layer layer, float alpha) {
+    ALOGV("setLayerPlaneAlpha");
+    getLayerImpl(layer).mRenderState.mPlaneAlpha = alpha;
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerSidebandStream(Display /*display*/, Layer /*layer*/,
+                                                       buffer_handle_t /*stream*/) {
+    ALOGV("setLayerSidebandStream");
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerSourceCrop(Display /*display*/, Layer layer,
+                                                   const hwc_frect_t& crop) {
+    ALOGV("setLayerSourceCrop");
+    getLayerImpl(layer).mRenderState.mSourceCrop = crop;
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerTransform(Display /*display*/, Layer layer,
+                                                  int32_t transform) {
+    ALOGV("setLayerTransform");
+    getLayerImpl(layer).mRenderState.mTransform = static_cast<hwc_transform_t>(transform);
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerVisibleRegion(Display /*display*/, Layer layer,
+                                                      const std::vector<hwc_rect_t>& visible) {
+    ALOGV("setLayerVisibleRegion");
+    getLayerImpl(layer).mRenderState.mVisibleRegion = visible;
+    return V2_1::Error::NONE;
+}
+
+V2_1::Error FakeComposerClient::setLayerZOrder(Display /*display*/, Layer layer, uint32_t z) {
+    ALOGV("setLayerZOrder");
+    getLayerImpl(layer).mZ = z;
+    return V2_1::Error::NONE;
+}
+
+// Composer 2.2
+V2_1::Error FakeComposerClient::getPerFrameMetadataKeys(
+        Display /*display*/, std::vector<V2_2::IComposerClient::PerFrameMetadataKey>* /*outKeys*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setLayerPerFrameMetadata(
+        Display /*display*/, Layer /*layer*/,
+        const std::vector<V2_2::IComposerClient::PerFrameMetadata>& /*metadata*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getReadbackBufferAttributes(
+        Display /*display*/, graphics::common::V1_1::PixelFormat* /*outFormat*/,
+        graphics::common::V1_1::Dataspace* /*outDataspace*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setReadbackBuffer(Display /*display*/,
+                                                  const native_handle_t* /*bufferHandle*/,
+                                                  android::base::unique_fd /*fenceFd*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getReadbackBufferFence(Display /*display*/,
+                                                       android::base::unique_fd* /*outFenceFd*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::createVirtualDisplay_2_2(
+        uint32_t /*width*/, uint32_t /*height*/, graphics::common::V1_1::PixelFormat* /*format*/,
+        Display* /*outDisplay*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+V2_1::Error FakeComposerClient::getClientTargetSupport_2_2(
+        Display /*display*/, uint32_t /*width*/, uint32_t /*height*/,
+        graphics::common::V1_1::PixelFormat /*format*/,
+        graphics::common::V1_1::Dataspace /*dataspace*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setPowerMode_2_2(Display /*display*/,
+                                                 V2_2::IComposerClient::PowerMode /*mode*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setLayerFloatColor(Display /*display*/, Layer /*layer*/,
+                                                   V2_2::IComposerClient::FloatColor /*color*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getColorModes_2_2(
+        Display /*display*/, hidl_vec<graphics::common::V1_1::ColorMode>* /*outModes*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getRenderIntents(
+        Display /*display*/, graphics::common::V1_1::ColorMode /*mode*/,
+        std::vector<graphics::common::V1_1::RenderIntent>* /*outIntents*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setColorMode_2_2(Display /*display*/,
+                                                 graphics::common::V1_1::ColorMode /*mode*/,
+                                                 graphics::common::V1_1::RenderIntent /*intent*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+std::array<float, 16> FakeComposerClient::getDataspaceSaturationMatrix(
+        graphics::common::V1_1::Dataspace /*dataspace*/) {
+    return {};
+}
+
+// Composer 2.3
+V2_1::Error FakeComposerClient::getPerFrameMetadataKeys_2_3(
+        Display /*display*/, std::vector<V2_3::IComposerClient::PerFrameMetadataKey>* /*outKeys*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setColorMode_2_3(Display /*display*/,
+                                                 graphics::common::V1_2::ColorMode /*mode*/,
+                                                 graphics::common::V1_1::RenderIntent /*intent*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getRenderIntents_2_3(
+        Display /*display*/, graphics::common::V1_2::ColorMode /*mode*/,
+        std::vector<graphics::common::V1_1::RenderIntent>* /*outIntents*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getColorModes_2_3(
+        Display /*display*/, hidl_vec<graphics::common::V1_2::ColorMode>* /*outModes*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getClientTargetSupport_2_3(
+        Display /*display*/, uint32_t /*width*/, uint32_t /*height*/,
+        graphics::common::V1_2::PixelFormat /*format*/,
+        graphics::common::V1_2::Dataspace /*dataspace*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getReadbackBufferAttributes_2_3(
+        Display /*display*/, graphics::common::V1_2::PixelFormat* /*outFormat*/,
+        graphics::common::V1_2::Dataspace* /*outDataspace*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getHdrCapabilities_2_3(
+        Display /*display*/, hidl_vec<graphics::common::V1_2::Hdr>* /*outTypes*/,
+        float* /*outMaxLuminance*/, float* /*outMaxAverageLuminance*/, float* /*outMinLuminance*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setLayerPerFrameMetadata_2_3(
+        Display /*display*/, Layer /*layer*/,
+        const std::vector<V2_3::IComposerClient::PerFrameMetadata>& /*metadata*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getDisplayIdentificationData(Display /*display*/,
+                                                             uint8_t* /*outPort*/,
+                                                             std::vector<uint8_t>* /*outData*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setLayerColorTransform(Display /*display*/, Layer /*layer*/,
+                                                       const float* /*matrix*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getDisplayedContentSamplingAttributes(
+        uint64_t /*display*/, graphics::common::V1_2::PixelFormat& /*format*/,
+        graphics::common::V1_2::Dataspace& /*dataspace*/,
+        hidl_bitfield<V2_3::IComposerClient::FormatColorComponent>& /*componentMask*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setDisplayedContentSamplingEnabled(
+        uint64_t /*display*/, V2_3::IComposerClient::DisplayedContentSampling /*enable*/,
+        hidl_bitfield<V2_3::IComposerClient::FormatColorComponent> /*componentMask*/,
+        uint64_t /*maxFrames*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getDisplayedContentSample(
+        uint64_t /*display*/, uint64_t /*maxFrames*/, uint64_t /*timestamp*/,
+        uint64_t& /*frameCount*/, hidl_vec<uint64_t>& /*sampleComponent0*/,
+        hidl_vec<uint64_t>& /*sampleComponent1*/, hidl_vec<uint64_t>& /*sampleComponent2*/,
+        hidl_vec<uint64_t>& /*sampleComponent3*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getDisplayCapabilities(
+        Display /*display*/,
+        std::vector<V2_3::IComposerClient::DisplayCapability>* /*outCapabilities*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setLayerPerFrameMetadataBlobs(
+        Display /*display*/, Layer /*layer*/,
+        std::vector<V2_3::IComposerClient::PerFrameMetadataBlob>& /*blobs*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::getDisplayBrightnessSupport(Display /*display*/,
+                                                            bool* /*outSupport*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+V2_1::Error FakeComposerClient::setDisplayBrightness(Display /*display*/, float /*brightness*/) {
+    return V2_1::Error::UNSUPPORTED;
+}
+
+// Composer 2.4
+void FakeComposerClient::registerEventCallback_2_4(EventCallback_2_4* callback) {
+    ALOGV("registerEventCallback_2_4");
+    LOG_FATAL_IF(mEventCallback != nullptr, "already registered using registerEventCallback");
+
+    mEventCallback_2_4 = callback;
+    if (mEventCallback_2_4) {
+        mEventCallback_2_4->onHotplug(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
+    }
+}
+
+void FakeComposerClient::unregisterEventCallback_2_4() {
+    ALOGV("unregisterEventCallback_2_4");
+    mEventCallback_2_4 = nullptr;
+}
+
+V2_4::Error FakeComposerClient::getDisplayCapabilities_2_4(
+        Display /*display*/,
+        std::vector<V2_4::IComposerClient::DisplayCapability>* /*outCapabilities*/) {
+    return V2_4::Error::UNSUPPORTED;
+}
+
+V2_4::Error FakeComposerClient::getDisplayConnectionType(
+        Display /*display*/, V2_4::IComposerClient::DisplayConnectionType* /*outType*/) {
+    return V2_4::Error::UNSUPPORTED;
+}
+
+V2_4::Error FakeComposerClient::getDisplayAttribute_2_4(Display display, Config config,
+                                                        IComposerClient::Attribute attribute,
+                                                        int32_t* outValue) {
     ALOGV("getDisplayAttribute (%d, %d, %d, %p)", static_cast<int>(display),
           static_cast<int>(config), static_cast<int>(attribute), outValue);
+    if (mMockHal) {
+        return mMockHal->getDisplayAttribute_2_4(display, config, attribute, outValue);
+    }
 
     // TODO: SOOO much fun to be had with these alone
     switch (attribute) {
@@ -276,233 +742,69 @@
     return Error::NONE;
 }
 
-Error FakeComposerClient::getDisplayConfigs(Display /*display*/, hidl_vec<Config>* outConfigs) {
-    ALOGV("getDisplayConfigs");
-    // TODO assert display == 1, outConfigs != nullptr
+V2_4::Error FakeComposerClient::getDisplayVsyncPeriod(Display display,
+                                                      V2_4::VsyncPeriodNanos* outVsyncPeriod) {
+    ALOGV("getDisplayVsyncPeriod");
+    if (mMockHal) {
+        return mMockHal->getDisplayVsyncPeriod(display, outVsyncPeriod);
+    }
 
-    outConfigs->resize(1);
-    (*outConfigs)[0] = 1;
-
-    return Error::NONE;
+    return V2_4::Error::UNSUPPORTED;
 }
 
-Error FakeComposerClient::getDisplayName(Display /*display*/, hidl_string* /*outName*/) {
-    ALOGV("getDisplayName");
-    return Error::NONE;
+V2_4::Error FakeComposerClient::setActiveConfigWithConstraints(
+        Display display, Config config,
+        const V2_4::IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+        VsyncPeriodChangeTimeline* timeline) {
+    ALOGV("setActiveConfigWithConstraints");
+    if (mMockHal) {
+        return mMockHal->setActiveConfigWithConstraints(display, config,
+                                                        vsyncPeriodChangeConstraints, timeline);
+    }
+    return V2_4::Error::UNSUPPORTED;
 }
 
-Error FakeComposerClient::getDisplayType(Display /*display*/,
-                                         IComposerClient::DisplayType* outType) {
-    ALOGV("getDisplayType");
-    // TODO: This setting nothing on the output had no effect on initial trials. Is first display
-    // assumed to be physical?
-    *outType = static_cast<IComposerClient::DisplayType>(HWC2_DISPLAY_TYPE_PHYSICAL);
-    return Error::NONE;
+V2_4::Error FakeComposerClient::setAutoLowLatencyMode(Display, bool) {
+    ALOGV("setAutoLowLatencyMode");
+    return V2_4::Error::UNSUPPORTED;
 }
 
-Error FakeComposerClient::getDozeSupport(Display /*display*/, bool* /*outSupport*/) {
-    ALOGV("getDozeSupport");
-    return Error::NONE;
+V2_4::Error FakeComposerClient::getSupportedContentTypes(
+        Display, std::vector<IComposerClient::ContentType>*) {
+    ALOGV("getSupportedContentTypes");
+    return V2_4::Error::UNSUPPORTED;
 }
 
-Error FakeComposerClient::getHdrCapabilities(Display /*display*/, hidl_vec<Hdr>* /*outTypes*/,
-                                             float* /*outMaxLuminance*/,
-                                             float* /*outMaxAverageLuminance*/,
-                                             float* /*outMinLuminance*/) {
-    ALOGV("getHdrCapabilities");
-    return Error::NONE;
+V2_4::Error FakeComposerClient::setContentType(Display, IComposerClient::ContentType) {
+    ALOGV("setContentType");
+    return V2_4::Error::UNSUPPORTED;
 }
 
-Error FakeComposerClient::setActiveConfig(Display /*display*/, Config config) {
-    ALOGV("setActiveConfig");
-    mCurrentConfig = config;
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setColorMode(Display /*display*/, ColorMode /*mode*/) {
-    ALOGV("setColorMode");
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setPowerMode(Display /*display*/, IComposerClient::PowerMode /*mode*/) {
-    ALOGV("setPowerMode");
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setVsyncEnabled(Display /*display*/, IComposerClient::Vsync enabled) {
-    mVsyncEnabled = (enabled == IComposerClient::Vsync::ENABLE);
-    ALOGV("setVsyncEnabled(%s)", mVsyncEnabled ? "ENABLE" : "DISABLE");
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setColorTransform(Display /*display*/, const float* /*matrix*/,
-                                            int32_t /*hint*/) {
-    ALOGV("setColorTransform");
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setClientTarget(Display /*display*/, buffer_handle_t /*target*/,
-                                          int32_t /*acquireFence*/, int32_t /*dataspace*/,
-                                          const std::vector<hwc_rect_t>& /*damage*/) {
-    ALOGV("setClientTarget");
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setOutputBuffer(Display /*display*/, buffer_handle_t /*buffer*/,
-                                          int32_t /*releaseFence*/) {
-    ALOGV("setOutputBuffer");
-    return Error::NONE;
-}
-
-Error FakeComposerClient::validateDisplay(
+V2_4::Error FakeComposerClient::validateDisplay_2_4(
         Display /*display*/, std::vector<Layer>* /*outChangedLayers*/,
         std::vector<IComposerClient::Composition>* /*outCompositionTypes*/,
         uint32_t* /*outDisplayRequestMask*/, std::vector<Layer>* /*outRequestedLayers*/,
-        std::vector<uint32_t>* /*outRequestMasks*/) {
-    ALOGV("validateDisplay");
-    // TODO: Assume touching nothing means All Korrekt!
-    return Error::NONE;
+        std::vector<uint32_t>* /*outRequestMasks*/,
+        IComposerClient::ClientTargetProperty* /*outClientTargetProperty*/) {
+    return V2_4::Error::NONE;
 }
 
-Error FakeComposerClient::acceptDisplayChanges(Display /*display*/) {
-    ALOGV("acceptDisplayChanges");
-    // Didn't ask for changes because software is omnipotent.
-    return Error::NONE;
+V2_4::Error FakeComposerClient::setLayerGenericMetadata(Display, Layer, const std::string&, bool,
+                                                        const std::vector<uint8_t>&) {
+    ALOGV("setLayerGenericMetadata");
+    return V2_4::Error::UNSUPPORTED;
 }
 
-bool layerZOrdering(const std::unique_ptr<FrameRect>& a, const std::unique_ptr<FrameRect>& b) {
-    return a->z <= b->z;
-}
-
-Error FakeComposerClient::presentDisplay(Display /*display*/, int32_t* /*outPresentFence*/,
-                                         std::vector<Layer>* /*outLayers*/,
-                                         std::vector<int32_t>* /*outReleaseFences*/) {
-    ALOGV("presentDisplay");
-    // TODO Leaving layers and their fences out for now. Doing so
-    // means that we've already processed everything. Important to
-    // test that the fences are respected, though. (How?)
-
-    std::unique_ptr<Frame> newFrame(new Frame);
-    for (uint64_t layer = 0; layer < mLayers.size(); layer++) {
-        const LayerImpl& layerImpl = *mLayers[layer];
-
-        if (!layerImpl.mValid) continue;
-
-        auto rect = std::make_unique<FrameRect>(layer, layerImpl.mRenderState, layerImpl.mZ);
-        newFrame->rectangles.push_back(std::move(rect));
-    }
-    std::sort(newFrame->rectangles.begin(), newFrame->rectangles.end(), layerZOrdering);
-    {
-        Mutex::Autolock _l(mStateMutex);
-        mFrames.push_back(std::move(newFrame));
-        mFramesAvailable.broadcast();
-    }
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerCursorPosition(Display /*display*/, Layer /*layer*/,
-                                                 int32_t /*x*/, int32_t /*y*/) {
-    ALOGV("setLayerCursorPosition");
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerBuffer(Display /*display*/, Layer layer, buffer_handle_t buffer,
-                                         int32_t acquireFence) {
-    ALOGV("setLayerBuffer");
-    LayerImpl& l = getLayerImpl(layer);
-    if (buffer != l.mRenderState.mBuffer) {
-        l.mRenderState.mSwapCount++; // TODO: Is setting to same value a swap or not?
-    }
-    l.mRenderState.mBuffer = buffer;
-    l.mRenderState.mAcquireFence = acquireFence;
-
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerSurfaceDamage(Display /*display*/, Layer /*layer*/,
-                                                const std::vector<hwc_rect_t>& /*damage*/) {
-    ALOGV("setLayerSurfaceDamage");
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerBlendMode(Display /*display*/, Layer layer, int32_t mode) {
-    ALOGV("setLayerBlendMode");
-    getLayerImpl(layer).mRenderState.mBlendMode = static_cast<hwc2_blend_mode_t>(mode);
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerColor(Display /*display*/, Layer layer,
-                                        IComposerClient::Color color) {
-    ALOGV("setLayerColor");
-    getLayerImpl(layer).mRenderState.mLayerColor.r = color.r;
-    getLayerImpl(layer).mRenderState.mLayerColor.g = color.g;
-    getLayerImpl(layer).mRenderState.mLayerColor.b = color.b;
-    getLayerImpl(layer).mRenderState.mLayerColor.a = color.a;
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerCompositionType(Display /*display*/, Layer /*layer*/,
-                                                  int32_t /*type*/) {
-    ALOGV("setLayerCompositionType");
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerDataspace(Display /*display*/, Layer /*layer*/,
-                                            int32_t /*dataspace*/) {
-    ALOGV("setLayerDataspace");
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerDisplayFrame(Display /*display*/, Layer layer,
-                                               const hwc_rect_t& frame) {
-    ALOGV("setLayerDisplayFrame (%d, %d, %d, %d)", frame.left, frame.top, frame.right,
-          frame.bottom);
-    getLayerImpl(layer).mRenderState.mDisplayFrame = frame;
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerPlaneAlpha(Display /*display*/, Layer layer, float alpha) {
-    ALOGV("setLayerPlaneAlpha");
-    getLayerImpl(layer).mRenderState.mPlaneAlpha = alpha;
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerSidebandStream(Display /*display*/, Layer /*layer*/,
-                                                 buffer_handle_t /*stream*/) {
-    ALOGV("setLayerSidebandStream");
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerSourceCrop(Display /*display*/, Layer layer,
-                                             const hwc_frect_t& crop) {
-    ALOGV("setLayerSourceCrop");
-    getLayerImpl(layer).mRenderState.mSourceCrop = crop;
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerTransform(Display /*display*/, Layer layer, int32_t transform) {
-    ALOGV("setLayerTransform");
-    getLayerImpl(layer).mRenderState.mTransform = static_cast<hwc_transform_t>(transform);
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerVisibleRegion(Display /*display*/, Layer layer,
-                                                const std::vector<hwc_rect_t>& visible) {
-    ALOGV("setLayerVisibleRegion");
-    getLayerImpl(layer).mRenderState.mVisibleRegion = visible;
-    return Error::NONE;
-}
-
-Error FakeComposerClient::setLayerZOrder(Display /*display*/, Layer layer, uint32_t z) {
-    ALOGV("setLayerZOrder");
-    getLayerImpl(layer).mZ = z;
-    return Error::NONE;
+V2_4::Error FakeComposerClient::getLayerGenericMetadataKeys(
+        std::vector<IComposerClient::LayerGenericMetadataKey>*) {
+    ALOGV("getLayerGenericMetadataKeys");
+    return V2_4::Error::UNSUPPORTED;
 }
 
 //////////////////////////////////////////////////////////////////
 
 void FakeComposerClient::requestVSync(uint64_t vsyncTime) {
-    if (mEventCallback) {
+    if (mEventCallback || mEventCallback_2_4) {
         uint64_t timestamp = vsyncTime;
         ALOGV("Vsync");
         if (timestamp == 0) {
@@ -512,8 +814,10 @@
         }
         if (mSurfaceComposer != nullptr) {
             mSurfaceComposer->injectVSync(timestamp);
-        } else {
+        } else if (mEventCallback) {
             mEventCallback->onVsync(PRIMARY_DISPLAY, timestamp);
+        } else {
+            mEventCallback_2_4->onVsync_2_4(PRIMARY_DISPLAY, timestamp, 16'666'666);
         }
     }
 }
@@ -617,3 +921,6 @@
     // this might get more involving.
     return static_cast<Layer>(index);
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
index d115d79..600e765 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
@@ -16,22 +16,21 @@
 
 #pragma once
 
-#define HWC2_USE_CPP11
-#define HWC2_INCLUDE_STRINGIFICATION
-#include <composer-hal/2.1/ComposerClient.h>
-#undef HWC2_USE_CPP11
-#undef HWC2_INCLUDE_STRINGIFICATION
-#include "RenderState.h"
-
-// Needed for display type/ID enums
-#include <hardware/hwcomposer_defs.h>
-
-#include <utils/Condition.h>
-
 #include <chrono>
 
-using namespace android::hardware::graphics::composer::V2_1;
-using namespace android::hardware::graphics::composer::V2_1::hal;
+#include <composer-hal/2.1/ComposerClient.h>
+#include <composer-hal/2.2/ComposerClient.h>
+#include <composer-hal/2.3/ComposerClient.h>
+#include <composer-hal/2.4/ComposerClient.h>
+#include <utils/Condition.h>
+
+#include "MockComposerHal.h"
+#include "RenderState.h"
+
+using namespace android::hardware::graphics::common;
+using namespace android::hardware::graphics::composer;
+using namespace android::hardware::graphics::composer::V2_4;
+using namespace android::hardware::graphics::composer::V2_4::hal;
 using namespace android::hardware;
 using namespace std::chrono_literals;
 
@@ -46,7 +45,6 @@
 } // namespace android
 
 namespace sftest {
-
 // NOTE: The ID's need to be exactly these. VR composer and parts of
 // the SurfaceFlinger assume the display IDs to have these values
 // despite the enum being documented as a display type.
@@ -59,6 +57,8 @@
     FakeComposerClient();
     virtual ~FakeComposerClient();
 
+    void setMockHal(MockComposerHal* mockHal) { mMockHal = mockHal; }
+
     bool hasCapability(hwc2_capability_t capability) override;
 
     std::string dumpDebugInfo() override;
@@ -66,59 +66,193 @@
     void unregisterEventCallback() override;
 
     uint32_t getMaxVirtualDisplayCount() override;
-    Error createVirtualDisplay(uint32_t width, uint32_t height, PixelFormat* format,
-                               Display* outDisplay) override;
-    Error destroyVirtualDisplay(Display display) override;
-    Error createLayer(Display display, Layer* outLayer) override;
-    Error destroyLayer(Display display, Layer layer) override;
+    V2_1::Error createVirtualDisplay(uint32_t width, uint32_t height, V1_0::PixelFormat* format,
+                                     Display* outDisplay) override;
+    V2_1::Error destroyVirtualDisplay(Display display) override;
+    V2_1::Error createLayer(Display display, Layer* outLayer) override;
+    V2_1::Error destroyLayer(Display display, Layer layer) override;
 
-    Error getActiveConfig(Display display, Config* outConfig) override;
-    Error getClientTargetSupport(Display display, uint32_t width, uint32_t height,
-                                 PixelFormat format, Dataspace dataspace) override;
-    Error getColorModes(Display display, hidl_vec<ColorMode>* outModes) override;
-    Error getDisplayAttribute(Display display, Config config, IComposerClient::Attribute attribute,
-                              int32_t* outValue) override;
-    Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override;
-    Error getDisplayName(Display display, hidl_string* outName) override;
-    Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override;
-    Error getDozeSupport(Display display, bool* outSupport) override;
-    Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes, float* outMaxLuminance,
-                             float* outMaxAverageLuminance, float* outMinLuminance) override;
+    V2_1::Error getActiveConfig(Display display, Config* outConfig) override;
+    V2_1::Error getClientTargetSupport(Display display, uint32_t width, uint32_t height,
+                                       V1_0::PixelFormat format,
+                                       V1_0::Dataspace dataspace) override;
+    V2_1::Error getColorModes(Display display, hidl_vec<V1_0::ColorMode>* outModes) override;
+    V2_1::Error getDisplayAttribute(Display display, Config config,
+                                    V2_1::IComposerClient::Attribute attribute,
+                                    int32_t* outValue) override;
+    V2_1::Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override;
+    V2_1::Error getDisplayName(Display display, hidl_string* outName) override;
+    V2_1::Error getDisplayType(Display display, IComposerClient::DisplayType* outType) override;
+    V2_1::Error getDozeSupport(Display display, bool* outSupport) override;
+    V2_1::Error getHdrCapabilities(Display display, hidl_vec<V1_0::Hdr>* outTypes,
+                                   float* outMaxLuminance, float* outMaxAverageLuminance,
+                                   float* outMinLuminance) override;
 
-    Error setActiveConfig(Display display, Config config) override;
-    Error setColorMode(Display display, ColorMode mode) override;
-    Error setPowerMode(Display display, IComposerClient::PowerMode mode) override;
-    Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
+    V2_1::Error setActiveConfig(Display display, Config config) override;
+    V2_1::Error setColorMode(Display display, V1_0::ColorMode mode) override;
+    V2_1::Error setPowerMode(Display display, V2_1::IComposerClient::PowerMode mode) override;
+    V2_1::Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
 
-    Error setColorTransform(Display display, const float* matrix, int32_t hint) override;
-    Error setClientTarget(Display display, buffer_handle_t target, int32_t acquireFence,
-                          int32_t dataspace, const std::vector<hwc_rect_t>& damage) override;
-    Error setOutputBuffer(Display display, buffer_handle_t buffer, int32_t releaseFence) override;
-    Error validateDisplay(Display display, std::vector<Layer>* outChangedLayers,
-                          std::vector<IComposerClient::Composition>* outCompositionTypes,
-                          uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
-                          std::vector<uint32_t>* outRequestMasks) override;
-    Error acceptDisplayChanges(Display display) override;
-    Error presentDisplay(Display display, int32_t* outPresentFence, std::vector<Layer>* outLayers,
-                         std::vector<int32_t>* outReleaseFences) override;
+    V2_1::Error setColorTransform(Display display, const float* matrix, int32_t hint) override;
+    V2_1::Error setClientTarget(Display display, buffer_handle_t target, int32_t acquireFence,
+                                int32_t dataspace, const std::vector<hwc_rect_t>& damage) override;
+    V2_1::Error setOutputBuffer(Display display, buffer_handle_t buffer,
+                                int32_t releaseFence) override;
+    V2_1::Error validateDisplay(Display display, std::vector<Layer>* outChangedLayers,
+                                std::vector<IComposerClient::Composition>* outCompositionTypes,
+                                uint32_t* outDisplayRequestMask,
+                                std::vector<Layer>* outRequestedLayers,
+                                std::vector<uint32_t>* outRequestMasks) override;
+    V2_1::Error acceptDisplayChanges(Display display) override;
+    V2_1::Error presentDisplay(Display display, int32_t* outPresentFence,
+                               std::vector<Layer>* outLayers,
+                               std::vector<int32_t>* outReleaseFences) override;
 
-    Error setLayerCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override;
-    Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer,
-                         int32_t acquireFence) override;
-    Error setLayerSurfaceDamage(Display display, Layer layer,
-                                const std::vector<hwc_rect_t>& damage) override;
-    Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override;
-    Error setLayerColor(Display display, Layer layer, IComposerClient::Color color) override;
-    Error setLayerCompositionType(Display display, Layer layer, int32_t type) override;
-    Error setLayerDataspace(Display display, Layer layer, int32_t dataspace) override;
-    Error setLayerDisplayFrame(Display display, Layer layer, const hwc_rect_t& frame) override;
-    Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
-    Error setLayerSidebandStream(Display display, Layer layer, buffer_handle_t stream) override;
-    Error setLayerSourceCrop(Display display, Layer layer, const hwc_frect_t& crop) override;
-    Error setLayerTransform(Display display, Layer layer, int32_t transform) override;
-    Error setLayerVisibleRegion(Display display, Layer layer,
-                                const std::vector<hwc_rect_t>& visible) override;
-    Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
+    V2_1::Error setLayerCursorPosition(Display display, Layer layer, int32_t x, int32_t y) override;
+    V2_1::Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer,
+                               int32_t acquireFence) override;
+    V2_1::Error setLayerSurfaceDamage(Display display, Layer layer,
+                                      const std::vector<hwc_rect_t>& damage) override;
+    V2_1::Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override;
+    V2_1::Error setLayerColor(Display display, Layer layer, IComposerClient::Color color) override;
+    V2_1::Error setLayerCompositionType(Display display, Layer layer, int32_t type) override;
+    V2_1::Error setLayerDataspace(Display display, Layer layer, int32_t dataspace) override;
+    V2_1::Error setLayerDisplayFrame(Display display, Layer layer,
+                                     const hwc_rect_t& frame) override;
+    V2_1::Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
+    V2_1::Error setLayerSidebandStream(Display display, Layer layer,
+                                       buffer_handle_t stream) override;
+    V2_1::Error setLayerSourceCrop(Display display, Layer layer, const hwc_frect_t& crop) override;
+    V2_1::Error setLayerTransform(Display display, Layer layer, int32_t transform) override;
+    V2_1::Error setLayerVisibleRegion(Display display, Layer layer,
+                                      const std::vector<hwc_rect_t>& visible) override;
+    V2_1::Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
+
+    // Composer 2.2
+    V2_1::Error getPerFrameMetadataKeys(
+            Display display,
+            std::vector<V2_2::IComposerClient::PerFrameMetadataKey>* outKeys) override;
+    V2_1::Error setLayerPerFrameMetadata(
+            Display display, Layer layer,
+            const std::vector<V2_2::IComposerClient::PerFrameMetadata>& metadata) override;
+
+    V2_1::Error getReadbackBufferAttributes(
+            Display display, graphics::common::V1_1::PixelFormat* outFormat,
+            graphics::common::V1_1::Dataspace* outDataspace) override;
+    V2_1::Error setReadbackBuffer(Display display, const native_handle_t* bufferHandle,
+                                  android::base::unique_fd fenceFd) override;
+    V2_1::Error getReadbackBufferFence(Display display,
+                                       android::base::unique_fd* outFenceFd) override;
+    V2_1::Error createVirtualDisplay_2_2(uint32_t width, uint32_t height,
+                                         graphics::common::V1_1::PixelFormat* format,
+                                         Display* outDisplay) override;
+    V2_1::Error getClientTargetSupport_2_2(Display display, uint32_t width, uint32_t height,
+                                           graphics::common::V1_1::PixelFormat format,
+                                           graphics::common::V1_1::Dataspace dataspace) override;
+    V2_1::Error setPowerMode_2_2(Display display, V2_2::IComposerClient::PowerMode mode) override;
+
+    V2_1::Error setLayerFloatColor(Display display, Layer layer,
+                                   V2_2::IComposerClient::FloatColor color) override;
+
+    V2_1::Error getColorModes_2_2(Display display,
+                                  hidl_vec<graphics::common::V1_1::ColorMode>* outModes) override;
+    V2_1::Error getRenderIntents(
+            Display display, graphics::common::V1_1::ColorMode mode,
+            std::vector<graphics::common::V1_1::RenderIntent>* outIntents) override;
+    V2_1::Error setColorMode_2_2(Display display, graphics::common::V1_1::ColorMode mode,
+                                 graphics::common::V1_1::RenderIntent intent) override;
+
+    std::array<float, 16> getDataspaceSaturationMatrix(
+            graphics::common::V1_1::Dataspace dataspace) override;
+
+    // Composer 2.3
+    V2_1::Error getPerFrameMetadataKeys_2_3(
+            Display display,
+            std::vector<V2_3::IComposerClient::PerFrameMetadataKey>* outKeys) override;
+
+    V2_1::Error setColorMode_2_3(Display display, graphics::common::V1_2::ColorMode mode,
+                                 graphics::common::V1_1::RenderIntent intent) override;
+
+    V2_1::Error getRenderIntents_2_3(
+            Display display, graphics::common::V1_2::ColorMode mode,
+            std::vector<graphics::common::V1_1::RenderIntent>* outIntents) override;
+
+    V2_1::Error getColorModes_2_3(Display display,
+                                  hidl_vec<graphics::common::V1_2::ColorMode>* outModes) override;
+
+    V2_1::Error getClientTargetSupport_2_3(Display display, uint32_t width, uint32_t height,
+                                           graphics::common::V1_2::PixelFormat format,
+                                           graphics::common::V1_2::Dataspace dataspace) override;
+    V2_1::Error getReadbackBufferAttributes_2_3(
+            Display display, graphics::common::V1_2::PixelFormat* outFormat,
+            graphics::common::V1_2::Dataspace* outDataspace) override;
+    V2_1::Error getHdrCapabilities_2_3(Display display,
+                                       hidl_vec<graphics::common::V1_2::Hdr>* outTypes,
+                                       float* outMaxLuminance, float* outMaxAverageLuminance,
+                                       float* outMinLuminance) override;
+    V2_1::Error setLayerPerFrameMetadata_2_3(
+            Display display, Layer layer,
+            const std::vector<V2_3::IComposerClient::PerFrameMetadata>& metadata) override;
+    V2_1::Error getDisplayIdentificationData(Display display, uint8_t* outPort,
+                                             std::vector<uint8_t>* outData) override;
+    V2_1::Error setLayerColorTransform(Display display, Layer layer, const float* matrix) override;
+    V2_1::Error getDisplayedContentSamplingAttributes(
+            uint64_t display, graphics::common::V1_2::PixelFormat& format,
+            graphics::common::V1_2::Dataspace& dataspace,
+            hidl_bitfield<V2_3::IComposerClient::FormatColorComponent>& componentMask) override;
+    V2_1::Error setDisplayedContentSamplingEnabled(
+            uint64_t display, V2_3::IComposerClient::DisplayedContentSampling enable,
+            hidl_bitfield<V2_3::IComposerClient::FormatColorComponent> componentMask,
+            uint64_t maxFrames) override;
+    V2_1::Error getDisplayedContentSample(uint64_t display, uint64_t maxFrames, uint64_t timestamp,
+                                          uint64_t& frameCount,
+                                          hidl_vec<uint64_t>& sampleComponent0,
+                                          hidl_vec<uint64_t>& sampleComponent1,
+                                          hidl_vec<uint64_t>& sampleComponent2,
+                                          hidl_vec<uint64_t>& sampleComponent3) override;
+    V2_1::Error getDisplayCapabilities(
+            Display display,
+            std::vector<V2_3::IComposerClient::DisplayCapability>* outCapabilities) override;
+    V2_1::Error setLayerPerFrameMetadataBlobs(
+            Display display, Layer layer,
+            std::vector<V2_3::IComposerClient::PerFrameMetadataBlob>& blobs) override;
+    V2_1::Error getDisplayBrightnessSupport(Display display, bool* outSupport) override;
+    V2_1::Error setDisplayBrightness(Display display, float brightness) override;
+
+    // Composer 2.4
+    void registerEventCallback_2_4(EventCallback_2_4* callback) override;
+
+    void unregisterEventCallback_2_4() override;
+
+    V2_4::Error getDisplayCapabilities_2_4(
+            Display display,
+            std::vector<V2_4::IComposerClient::DisplayCapability>* outCapabilities) override;
+    V2_4::Error getDisplayConnectionType(
+            Display display, V2_4::IComposerClient::DisplayConnectionType* outType) override;
+    V2_4::Error getDisplayAttribute_2_4(Display display, Config config,
+                                        IComposerClient::Attribute attribute,
+                                        int32_t* outValue) override;
+    V2_4::Error getDisplayVsyncPeriod(Display display,
+                                      V2_4::VsyncPeriodNanos* outVsyncPeriod) override;
+    V2_4::Error setActiveConfigWithConstraints(
+            Display display, Config config,
+            const V2_4::IComposerClient::VsyncPeriodChangeConstraints& vsyncPeriodChangeConstraints,
+            VsyncPeriodChangeTimeline* outTimeline) override;
+    V2_4::Error setAutoLowLatencyMode(Display display, bool on) override;
+    V2_4::Error getSupportedContentTypes(
+            Display display,
+            std::vector<IComposerClient::ContentType>* outSupportedContentTypes) override;
+    V2_4::Error setContentType(Display display, IComposerClient::ContentType type) override;
+    V2_4::Error validateDisplay_2_4(
+            Display display, std::vector<Layer>* outChangedLayers,
+            std::vector<IComposerClient::Composition>* outCompositionTypes,
+            uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+            std::vector<uint32_t>* outRequestMasks,
+            IComposerClient::ClientTargetProperty* outClientTargetProperty) override;
+    V2_4::Error setLayerGenericMetadata(Display display, Layer layer, const std::string& key,
+                                        bool mandatory, const std::vector<uint8_t>& value) override;
+    V2_4::Error getLayerGenericMetadataKeys(
+            std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
 
     void setClient(ComposerClient* client);
 
@@ -150,6 +284,7 @@
     LayerImpl& getLayerImpl(Layer handle);
 
     EventCallback* mEventCallback;
+    EventCallback_2_4* mEventCallback_2_4;
     Config mCurrentConfig;
     bool mVsyncEnabled;
     std::vector<std::unique_ptr<LayerImpl>> mLayers;
@@ -159,6 +294,8 @@
     android::sp<android::SurfaceComposerClient> mSurfaceComposer; // For VSync injections
     mutable android::Mutex mStateMutex;
     mutable android::Condition mFramesAvailable;
+
+    MockComposerHal* mMockHal = nullptr;
 };
 
 } // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
index f70cbdb..c656eed 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "FakeHwcService"
@@ -22,35 +26,154 @@
 #include "FakeComposerService.h"
 
 using namespace android::hardware;
+using namespace android::hardware::graphics::composer;
 
 namespace sftest {
 
-FakeComposerService::FakeComposerService(android::sp<ComposerClient>& client) : mClient(client) {}
+FakeComposerService_2_1::FakeComposerService_2_1(android::sp<ComposerClient>& client)
+      : mClient(client) {}
 
-FakeComposerService::~FakeComposerService() {
+FakeComposerService_2_1::~FakeComposerService_2_1() {
     ALOGI("Maybe killing client %p", mClient.get());
     // Rely on sp to kill the client.
 }
 
-Return<void> FakeComposerService::getCapabilities(getCapabilities_cb hidl_cb) {
+Return<void> FakeComposerService_2_1::getCapabilities(getCapabilities_cb hidl_cb) {
     ALOGI("FakeComposerService::getCapabilities");
     hidl_cb(hidl_vec<Capability>());
     return Void();
 }
 
-Return<void> FakeComposerService::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
+Return<void> FakeComposerService_2_1::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
     ALOGI("FakeComposerService::dumpDebugInfo");
     hidl_cb(hidl_string());
     return Void();
 }
 
-Return<void> FakeComposerService::createClient(createClient_cb hidl_cb) {
+Return<void> FakeComposerService_2_1::createClient(createClient_cb hidl_cb) {
     ALOGI("FakeComposerService::createClient %p", mClient.get());
     if (!mClient->init()) {
         LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
     }
-    hidl_cb(Error::NONE, mClient);
+    hidl_cb(V2_1::Error::NONE, mClient);
+    return Void();
+}
+
+FakeComposerService_2_2::FakeComposerService_2_2(android::sp<ComposerClient>& client)
+      : mClient(client) {}
+
+FakeComposerService_2_2::~FakeComposerService_2_2() {
+    ALOGI("Maybe killing client %p", mClient.get());
+    // Rely on sp to kill the client.
+}
+
+Return<void> FakeComposerService_2_2::getCapabilities(getCapabilities_cb hidl_cb) {
+    ALOGI("FakeComposerService::getCapabilities");
+    hidl_cb(hidl_vec<Capability>());
+    return Void();
+}
+
+Return<void> FakeComposerService_2_2::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
+    ALOGI("FakeComposerService::dumpDebugInfo");
+    hidl_cb(hidl_string());
+    return Void();
+}
+
+Return<void> FakeComposerService_2_2::createClient(createClient_cb hidl_cb) {
+    ALOGI("FakeComposerService::createClient %p", mClient.get());
+    if (!mClient->init()) {
+        LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
+    }
+    hidl_cb(V2_1::Error::NONE, mClient);
+    return Void();
+}
+
+FakeComposerService_2_3::FakeComposerService_2_3(android::sp<ComposerClient>& client)
+      : mClient(client) {}
+
+FakeComposerService_2_3::~FakeComposerService_2_3() {
+    ALOGI("Maybe killing client %p", mClient.get());
+    // Rely on sp to kill the client.
+}
+
+Return<void> FakeComposerService_2_3::getCapabilities(getCapabilities_cb hidl_cb) {
+    ALOGI("FakeComposerService::getCapabilities");
+    hidl_cb(hidl_vec<Capability>());
+    return Void();
+}
+
+Return<void> FakeComposerService_2_3::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
+    ALOGI("FakeComposerService::dumpDebugInfo");
+    hidl_cb(hidl_string());
+    return Void();
+}
+
+Return<void> FakeComposerService_2_3::createClient(createClient_cb hidl_cb) {
+    LOG_ALWAYS_FATAL("createClient called on FakeComposerService_2_3");
+    if (!mClient->init()) {
+        LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
+    }
+    hidl_cb(V2_1::Error::UNSUPPORTED, nullptr);
+    return Void();
+}
+
+Return<void> FakeComposerService_2_3::createClient_2_3(createClient_2_3_cb hidl_cb) {
+    ALOGI("FakeComposerService_2_3::createClient_2_3 %p", mClient.get());
+    if (!mClient->init()) {
+        LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
+    }
+    hidl_cb(V2_1::Error::NONE, mClient);
+    return Void();
+}
+
+FakeComposerService_2_4::FakeComposerService_2_4(android::sp<ComposerClient>& client)
+      : mClient(client) {}
+
+FakeComposerService_2_4::~FakeComposerService_2_4() {
+    ALOGI("Maybe killing client %p", mClient.get());
+    // Rely on sp to kill the client.
+}
+
+Return<void> FakeComposerService_2_4::getCapabilities(getCapabilities_cb hidl_cb) {
+    ALOGI("FakeComposerService::getCapabilities");
+    hidl_cb(hidl_vec<Capability>());
+    return Void();
+}
+
+Return<void> FakeComposerService_2_4::dumpDebugInfo(dumpDebugInfo_cb hidl_cb) {
+    ALOGI("FakeComposerService::dumpDebugInfo");
+    hidl_cb(hidl_string());
+    return Void();
+}
+
+Return<void> FakeComposerService_2_4::createClient(createClient_cb hidl_cb) {
+    LOG_ALWAYS_FATAL("createClient called on FakeComposerService_2_4");
+    if (!mClient->init()) {
+        LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
+    }
+    hidl_cb(V2_1::Error::UNSUPPORTED, nullptr);
+    return Void();
+}
+
+Return<void> FakeComposerService_2_4::createClient_2_3(createClient_2_3_cb hidl_cb) {
+    LOG_ALWAYS_FATAL("createClient_2_3 called on FakeComposerService_2_4");
+    if (!mClient->init()) {
+        LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
+    }
+    hidl_cb(V2_1::Error::UNSUPPORTED, nullptr);
+    return Void();
+}
+
+Return<void> FakeComposerService_2_4::createClient_2_4(createClient_2_4_cb hidl_cb) {
+    ALOGI("FakeComposerService_2_4::createClient_2_4 %p", mClient.get());
+    if (!mClient->init()) {
+        LOG_ALWAYS_FATAL("failed to initialize ComposerClient");
+    }
+    hidl_cb(V2_4::Error::NONE, mClient);
     return Void();
 }
 
 } // namespace sftest
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
index a3fb8a6..47f970f 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerService.h
@@ -16,18 +16,24 @@
 
 #pragma once
 
+#include <android/hardware/graphics/composer/2.4/IComposer.h>
 #include <composer-hal/2.1/ComposerClient.h>
+#include <composer-hal/2.2/ComposerClient.h>
+#include <composer-hal/2.3/ComposerClient.h>
+#include <composer-hal/2.4/ComposerClient.h>
 
-using namespace android::hardware::graphics::composer::V2_1;
-using namespace android::hardware::graphics::composer::V2_1::hal;
 using android::hardware::Return;
 
+using ComposerClient = android::hardware::graphics::composer::V2_4::hal::ComposerClient;
+
 namespace sftest {
 
-class FakeComposerService : public IComposer {
+using IComposer_2_1 = android::hardware::graphics::composer::V2_1::IComposer;
+
+class FakeComposerService_2_1 : public IComposer_2_1 {
 public:
-    explicit FakeComposerService(android::sp<ComposerClient>& client);
-    virtual ~FakeComposerService();
+    explicit FakeComposerService_2_1(android::sp<ComposerClient>& client);
+    virtual ~FakeComposerService_2_1();
 
     Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
     Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
@@ -37,4 +43,50 @@
     android::sp<ComposerClient> mClient;
 };
 
+using IComposer_2_2 = android::hardware::graphics::composer::V2_2::IComposer;
+class FakeComposerService_2_2 : public IComposer_2_2 {
+public:
+    explicit FakeComposerService_2_2(android::sp<ComposerClient>& client);
+    virtual ~FakeComposerService_2_2();
+
+    Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
+    Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
+    Return<void> createClient(createClient_cb hidl_cb) override;
+
+private:
+    android::sp<ComposerClient> mClient;
+};
+
+using IComposer_2_3 = android::hardware::graphics::composer::V2_3::IComposer;
+class FakeComposerService_2_3 : public IComposer_2_3 {
+public:
+    explicit FakeComposerService_2_3(android::sp<ComposerClient>& client);
+    virtual ~FakeComposerService_2_3();
+
+    Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
+    Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
+    Return<void> createClient(createClient_cb hidl_cb) override;
+    Return<void> createClient_2_3(createClient_2_3_cb hidl_cb) override;
+
+private:
+    android::sp<ComposerClient> mClient;
+};
+
+using IComposer_2_4 = android::hardware::graphics::composer::V2_4::IComposer;
+
+class FakeComposerService_2_4 : public IComposer_2_4 {
+public:
+    explicit FakeComposerService_2_4(android::sp<ComposerClient>& client);
+    virtual ~FakeComposerService_2_4();
+
+    Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
+    Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
+    Return<void> createClient(createClient_cb hidl_cb) override;
+    Return<void> createClient_2_3(createClient_2_3_cb hidl_cb) override;
+    Return<void> createClient_2_4(createClient_2_4_cb hidl_cb) override;
+
+private:
+    android::sp<ComposerClient> mClient;
+};
+
 } // namespace sftest
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
index 51956ec..1cea25a 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "FakeHwcUtil"
@@ -25,8 +29,8 @@
 #include "SurfaceFlinger.h" // Get the name of the service...
 
 #include <binder/IServiceManager.h>
-
 #include <cutils/properties.h>
+#include <hidl/ServiceManagement.h>
 
 #include <iomanip>
 #include <thread>
@@ -167,7 +171,9 @@
     }
     // TODO: Try registering the mock as the default service instead.
     property_set("debug.sf.hwc_service_name", "mock");
-    // This allows the SurfaceFlinger to load a HIDL service not listed in manifest files.
+
+    // This allows tests/SF to register/load a HIDL service not listed in manifest files.
+    android::hardware::details::setTrebleTestingOverride(true);
     property_set("debug.sf.treble_testing_override", "true");
 }
 
@@ -177,7 +183,11 @@
     // Wait for mock call signaling teardown?
     property_set("debug.sf.nobootanimation", "0");
     property_set("debug.sf.hwc_service_name", "default");
+    system("setenforce 1");
     ALOGI("Test env tear down - done");
 }
 
 } // namespace sftest
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
index 7d20d3c..383a111 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.h
@@ -19,11 +19,7 @@
 #include "FakeComposerClient.h"
 
 #include <gui/SurfaceComposerClient.h>
-
-#include <hardware/hwcomposer_defs.h>
-
 #include <log/log.h>
-
 #include <gtest/gtest.h>
 
 // clang-format off
@@ -108,9 +104,9 @@
         LOG_ALWAYS_FATAL_IF(android::NO_ERROR != apply());
         // Make sure that exactly one frame has been rendered.
         mComposer.waitUntilFrame(frameCount + 1);
-        LOG_ALWAYS_FATAL_IF(frameCount + 1 != mComposer.getFrameCount(),
-                            "Unexpected frame advance. Delta: %d",
-                            mComposer.getFrameCount() - frameCount);
+        //        LOG_ALWAYS_FATAL_IF(frameCount + 1 != mComposer.getFrameCount(),
+        //                            "Unexpected frame advance. Delta: %d",
+        //                            mComposer.getFrameCount() - frameCount);
     }
 
     FakeComposerClient& mComposer;
diff --git a/services/surfaceflinger/tests/fakehwc/MockComposerHal.h b/services/surfaceflinger/tests/fakehwc/MockComposerHal.h
new file mode 100644
index 0000000..5dc3778
--- /dev/null
+++ b/services/surfaceflinger/tests/fakehwc/MockComposerHal.h
@@ -0,0 +1,47 @@
+/*
+ * 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 <composer-hal/2.4/ComposerClient.h>
+
+#include <gmock/gmock.h>
+
+using namespace android::hardware::graphics::common;
+using namespace android::hardware::graphics::composer;
+using namespace android::hardware::graphics::composer::V2_4;
+using namespace android::hardware::graphics::composer::V2_4::hal;
+using namespace android::hardware;
+using namespace std::chrono_literals;
+
+namespace sftest {
+
+// Mock class for ComposerHal. Implements only the functions used in the test.
+class MockComposerHal {
+public:
+    MOCK_METHOD2(getActiveConfig, V2_1::Error(Display, Config*));
+    MOCK_METHOD4(getDisplayAttribute_2_4,
+                 V2_4::Error(Display, Config, V2_4::IComposerClient::Attribute, int32_t*));
+    MOCK_METHOD2(getDisplayConfigs, V2_1::Error(Display, hidl_vec<Config>*));
+    MOCK_METHOD2(setActiveConfig, V2_1::Error(Display, Config));
+    MOCK_METHOD2(getDisplayVsyncPeriod, V2_4::Error(Display, V2_4::VsyncPeriodNanos*));
+    MOCK_METHOD4(setActiveConfigWithConstraints,
+                 V2_4::Error(Display, Config,
+                             const V2_4::IComposerClient::VsyncPeriodChangeConstraints&,
+                             VsyncPeriodChangeTimeline*));
+};
+
+} // namespace sftest
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/fakehwc/RenderState.h b/services/surfaceflinger/tests/fakehwc/RenderState.h
index 0059289..40193f2 100644
--- a/services/surfaceflinger/tests/fakehwc/RenderState.h
+++ b/services/surfaceflinger/tests/fakehwc/RenderState.h
@@ -16,8 +16,6 @@
 
 #pragma once
 
-#include <hardware/hwcomposer2.h>
-
 #include <vector>
 
 namespace sftest {
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index a892a2a..a03fd89 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 // #define LOG_NDEBUG 0
 #undef LOG_TAG
 #define LOG_TAG "FakeHwcTest"
@@ -21,6 +25,7 @@
 #include "FakeComposerClient.h"
 #include "FakeComposerService.h"
 #include "FakeComposerUtils.h"
+#include "MockComposerHal.h"
 
 #include <gui/DisplayEventReceiver.h>
 #include <gui/ISurfaceComposer.h>
@@ -36,13 +41,14 @@
 #include <hwbinder/ProcessState.h>
 #include <log/log.h>
 #include <private/gui/ComposerService.h>
-#include <ui/DisplayInfo.h>
+#include <ui/DisplayConfig.h>
 #include <utils/Looper.h>
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 #include <limits>
+#include <thread>
 
 using namespace std::chrono_literals;
 
@@ -55,12 +61,14 @@
 
 // Mock test helpers
 using ::testing::_;
+using ::testing::AtLeast;
 using ::testing::DoAll;
 using ::testing::Invoke;
 using ::testing::Return;
 using ::testing::SetArgPointee;
 
 using Transaction = SurfaceComposerClient::Transaction;
+using Attribute = V2_4::IComposerClient::Attribute;
 
 ///////////////////////////////////////////////
 
@@ -121,319 +129,1268 @@
                           static_cast<int>(bottom));
 }
 
-////////////////////////////////////////////////
-
+///////////////////////////////////////////////
+template <typename FakeComposerService>
 class DisplayTest : public ::testing::Test {
-public:
-    class MockComposerClient : public FakeComposerClient {
-    public:
-        MOCK_METHOD2(getDisplayType, Error(Display display, ComposerClient::DisplayType* outType));
-        MOCK_METHOD4(getDisplayAttribute,
-                     Error(Display display, Config config, IComposerClient::Attribute attribute,
-                           int32_t* outValue));
-
-        // Re-routing to basic fake implementation
-        Error getDisplayAttributeFake(Display display, Config config,
-                                      IComposerClient::Attribute attribute, int32_t* outValue) {
-            return FakeComposerClient::getDisplayAttribute(display, config, attribute, outValue);
-        }
+protected:
+    struct TestConfig {
+        int32_t id;
+        int32_t w;
+        int32_t h;
+        int32_t vsyncPeriod;
+        int32_t group;
     };
 
-protected:
-    static int processDisplayEvents(int fd, int events, void* data);
+    static int processDisplayEvents(int /*fd*/, int /*events*/, void* data) {
+        auto self = static_cast<DisplayTest*>(data);
 
-    void SetUp() override;
-    void TearDown() override;
+        ssize_t n;
+        DisplayEventReceiver::Event buffer[1];
 
-    void waitForDisplayTransaction();
-    bool waitForHotplugEvent(PhysicalDisplayId displayId, bool connected);
-
-    sp<IComposer> mFakeService;
-    sp<SurfaceComposerClient> mComposerClient;
-
-    MockComposerClient* mMockComposer;
-
-    std::unique_ptr<DisplayEventReceiver> mReceiver;
-    sp<Looper> mLooper;;
-    std::deque<DisplayEventReceiver::Event> mReceivedDisplayEvents;
-};
-
-void DisplayTest::SetUp() {
-    // TODO: The mMockComposer should be a unique_ptr, but it needs to
-    // outlive the test class.  Currently ComposerClient only dies
-    // when the service is replaced. The Mock deletes itself when
-    // removeClient is called on it, which is ugly.  This can be
-    // changed if HIDL ServiceManager allows removing services or
-    // ComposerClient starts taking the ownership of the contained
-    // implementation class. Moving the fake class to the HWC2
-    // interface instead of the current Composer interface might also
-    // change the situation.
-    mMockComposer = new MockComposerClient;
-    sp<ComposerClient> client = new ComposerClient(mMockComposer);
-    mFakeService = new FakeComposerService(client);
-    (void)mFakeService->registerAsService("mock");
-
-    android::hardware::ProcessState::self()->startThreadPool();
-    android::ProcessState::self()->startThreadPool();
-
-    EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _))
-            .WillOnce(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
-                            Return(Error::NONE)));
-    // Primary display will be queried twice for all 5 attributes. One
-    // set of queries comes from the SurfaceFlinger proper an the
-    // other set from the VR composer.
-    // TODO: Is VR composer always present? Change to atLeast(5)?
-    EXPECT_CALL(*mMockComposer, getDisplayAttribute(PRIMARY_DISPLAY, 1, _, _))
-            .Times(2 * 5)
-            .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
-
-    startSurfaceFlinger();
-
-    // Fake composer wants to enable VSync injection
-    mMockComposer->onSurfaceFlingerStart();
-
-    mComposerClient = new SurfaceComposerClient;
-    ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
-
-    mReceiver.reset(new DisplayEventReceiver());
-    mLooper = new Looper(false);
-    mLooper->addFd(mReceiver->getFd(), 0, ALOOPER_EVENT_INPUT, processDisplayEvents, this);
-}
-
-void DisplayTest::TearDown() {
-    mLooper = nullptr;
-    mReceiver = nullptr;
-
-    mComposerClient->dispose();
-    mComposerClient = nullptr;
-
-    // Fake composer needs to release SurfaceComposerClient before the stop.
-    mMockComposer->onSurfaceFlingerStop();
-    stopSurfaceFlinger();
-
-    mFakeService = nullptr;
-    // TODO: Currently deleted in FakeComposerClient::removeClient(). Devise better lifetime
-    // management.
-    mMockComposer = nullptr;
-}
-
-
-int DisplayTest::processDisplayEvents(int /*fd*/, int /*events*/, void* data) {
-    auto self = static_cast<DisplayTest*>(data);
-
-    ssize_t n;
-    DisplayEventReceiver::Event buffer[1];
-
-    while ((n = self->mReceiver->getEvents(buffer, 1)) > 0) {
-        for (int i=0 ; i<n ; i++) {
-            self->mReceivedDisplayEvents.push_back(buffer[i]);
+        while ((n = self->mReceiver->getEvents(buffer, 1)) > 0) {
+            for (int i = 0; i < n; i++) {
+                self->mReceivedDisplayEvents.push_back(buffer[i]);
+            }
         }
+        ALOGD_IF(n < 0, "Error reading events (%s)\n", strerror(-n));
+        return 1;
     }
-    ALOGD_IF(n < 0, "Error reading events (%s)\n", strerror(-n));
-    return 1;
-}
 
-void DisplayTest::waitForDisplayTransaction() {
-    // Both a refresh and a vsync event are needed to apply pending display
-    // transactions.
-    mMockComposer->refreshDisplay(EXTERNAL_DISPLAY);
-    mMockComposer->runVSyncAndWait();
+    Error getDisplayAttributeNoMock(Display display, Config config,
+                                    V2_4::IComposerClient::Attribute attribute, int32_t* outValue) {
+        mFakeComposerClient->setMockHal(nullptr);
+        auto ret =
+                mFakeComposerClient->getDisplayAttribute_2_4(display, config, attribute, outValue);
+        mFakeComposerClient->setMockHal(mMockComposer.get());
+        return ret;
+    }
 
-    // Extra vsync and wait to avoid a 10% flake due to a race.
-    mMockComposer->runVSyncAndWait();
-}
+    void setExpectationsForConfigs(Display display, std::vector<TestConfig> testConfigs,
+                                   Config activeConfig, V2_4::VsyncPeriodNanos defaultVsyncPeriod) {
+        std::vector<Config> configIds;
+        for (int i = 0; i < testConfigs.size(); i++) {
+            configIds.push_back(testConfigs[i].id);
 
-bool DisplayTest::waitForHotplugEvent(PhysicalDisplayId displayId, bool connected) {
-    int waitCount = 20;
-    while (waitCount--) {
-        while (!mReceivedDisplayEvents.empty()) {
-            auto event = mReceivedDisplayEvents.front();
-            mReceivedDisplayEvents.pop_front();
+            EXPECT_CALL(*mMockComposer,
+                        getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::WIDTH, _))
+                    .WillRepeatedly(DoAll(SetArgPointee<3>(testConfigs[i].w), Return(Error::NONE)));
+            EXPECT_CALL(*mMockComposer,
+                        getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::HEIGHT, _))
+                    .WillRepeatedly(DoAll(SetArgPointee<3>(testConfigs[i].h), Return(Error::NONE)));
+            EXPECT_CALL(*mMockComposer,
+                        getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::VSYNC_PERIOD,
+                                                _))
+                    .WillRepeatedly(DoAll(SetArgPointee<3>(testConfigs[i].vsyncPeriod),
+                                          Return(Error::NONE)));
+            EXPECT_CALL(*mMockComposer,
+                        getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::CONFIG_GROUP,
+                                                _))
+                    .WillRepeatedly(
+                            DoAll(SetArgPointee<3>(testConfigs[i].group), Return(Error::NONE)));
+            EXPECT_CALL(*mMockComposer,
+                        getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::DPI_X, _))
+                    .WillRepeatedly(Return(Error::UNSUPPORTED));
+            EXPECT_CALL(*mMockComposer,
+                        getDisplayAttribute_2_4(display, testConfigs[i].id, Attribute::DPI_Y, _))
+                    .WillRepeatedly(Return(Error::UNSUPPORTED));
+        }
 
-            ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
-                     "event hotplug: displayId %" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
-                     ", connected %d\t",
-                     event.header.displayId, event.hotplug.connected);
+        EXPECT_CALL(*mMockComposer, getDisplayConfigs(display, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(hidl_vec<Config>(configIds)),
+                                      Return(V2_1::Error::NONE)));
 
-            if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG &&
-                event.header.displayId == displayId && event.hotplug.connected == connected) {
-                return true;
+        EXPECT_CALL(*mMockComposer, getActiveConfig(display, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(activeConfig), Return(V2_1::Error::NONE)));
+
+        EXPECT_CALL(*mMockComposer, getDisplayVsyncPeriod(display, _))
+                .WillRepeatedly(
+                        DoAll(SetArgPointee<1>(defaultVsyncPeriod), Return(V2_4::Error::NONE)));
+    }
+
+    void SetUp() override {
+        mMockComposer = std::make_unique<MockComposerHal>();
+        mFakeComposerClient = new FakeComposerClient();
+        mFakeComposerClient->setMockHal(mMockComposer.get());
+
+        sp<V2_4::hal::ComposerClient> client = new V2_4::hal::ComposerClient(mFakeComposerClient);
+        mFakeService = new FakeComposerService(client);
+        ASSERT_EQ(android::OK, mFakeService->registerAsService("mock"));
+
+        android::hardware::ProcessState::self()->startThreadPool();
+        android::ProcessState::self()->startThreadPool();
+
+        setExpectationsForConfigs(PRIMARY_DISPLAY,
+                                  {{
+                                          .id = 1,
+                                          .w = 1920,
+                                          .h = 1024,
+                                          .vsyncPeriod = 16'666'666,
+                                          .group = 0,
+                                  }},
+                                  1, 16'666'666);
+
+        startSurfaceFlinger();
+
+        // Fake composer wants to enable VSync injection
+        mFakeComposerClient->onSurfaceFlingerStart();
+
+        mComposerClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+        mReceiver.reset(new DisplayEventReceiver(ISurfaceComposer::eVsyncSourceApp,
+                                                 ISurfaceComposer::eConfigChangedDispatch));
+        mLooper = new Looper(false);
+        mLooper->addFd(mReceiver->getFd(), 0, ALOOPER_EVENT_INPUT, processDisplayEvents, this);
+    }
+
+    void TearDown() override {
+        mLooper = nullptr;
+        mReceiver = nullptr;
+
+        mComposerClient->dispose();
+        mComposerClient = nullptr;
+
+        // Fake composer needs to release SurfaceComposerClient before the stop.
+        mFakeComposerClient->onSurfaceFlingerStop();
+        stopSurfaceFlinger();
+
+        mFakeComposerClient->setMockHal(nullptr);
+
+        mFakeService = nullptr;
+        // TODO: Currently deleted in FakeComposerClient::removeClient(). Devise better lifetime
+        // management.
+        mMockComposer = nullptr;
+    }
+
+    void waitForDisplayTransaction() {
+        // Both a refresh and a vsync event are needed to apply pending display
+        // transactions.
+        mFakeComposerClient->refreshDisplay(EXTERNAL_DISPLAY);
+        mFakeComposerClient->runVSyncAndWait();
+
+        // Extra vsync and wait to avoid a 10% flake due to a race.
+        mFakeComposerClient->runVSyncAndWait();
+    }
+
+    bool waitForHotplugEvent(PhysicalDisplayId displayId, bool connected) {
+        int waitCount = 20;
+        while (waitCount--) {
+            while (!mReceivedDisplayEvents.empty()) {
+                auto event = mReceivedDisplayEvents.front();
+                mReceivedDisplayEvents.pop_front();
+
+                ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
+                         "event hotplug: displayId %" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
+                         ", connected %d\t",
+                         event.header.displayId, event.hotplug.connected);
+
+                if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG &&
+                    event.header.displayId == displayId && event.hotplug.connected == connected) {
+                    return true;
+                }
+            }
+
+            mLooper->pollOnce(1);
+        }
+        return false;
+    }
+
+    bool waitForConfigChangedEvent(PhysicalDisplayId displayId, int32_t configId) {
+        int waitCount = 20;
+        while (waitCount--) {
+            while (!mReceivedDisplayEvents.empty()) {
+                auto event = mReceivedDisplayEvents.front();
+                mReceivedDisplayEvents.pop_front();
+
+                ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED,
+                         "event config: displayId %" ANDROID_PHYSICAL_DISPLAY_ID_FORMAT
+                         ", configId %d\t",
+                         event.header.displayId, event.config.configId);
+
+                if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED &&
+                    event.header.displayId == displayId && event.config.configId == configId) {
+                    return true;
+                }
+            }
+
+            mLooper->pollOnce(1);
+        }
+        return false;
+    }
+
+    void Test_HotplugOneConfig() {
+        ALOGD("DisplayTest::Test_Hotplug_oneConfig");
+
+        setExpectationsForConfigs(EXTERNAL_DISPLAY,
+                                  {{.id = 1,
+                                    .w = 200,
+                                    .h = 400,
+                                    .vsyncPeriod = 16'666'666,
+                                    .group = 0}},
+                                  1, 16'666'666);
+
+        mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+                                            V2_1::IComposerCallback::Connection::CONNECTED);
+        waitForDisplayTransaction();
+        EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
+
+        {
+            const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
+            EXPECT_FALSE(display == nullptr);
+
+            DisplayConfig config;
+            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+            const ui::Size& resolution = config.resolution;
+            EXPECT_EQ(ui::Size(200, 400), resolution);
+            EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
+
+            auto surfaceControl =
+                    mComposerClient->createSurface(String8("Display Test Surface Foo"),
+                                                   resolution.getWidth(), resolution.getHeight(),
+                                                   PIXEL_FORMAT_RGBA_8888, 0);
+            EXPECT_TRUE(surfaceControl != nullptr);
+            EXPECT_TRUE(surfaceControl->isValid());
+            fillSurfaceRGBA8(surfaceControl, BLUE);
+
+            {
+                TransactionScope ts(*mFakeComposerClient);
+                ts.setDisplayLayerStack(display, 0);
+
+                ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
             }
         }
 
-        mLooper->pollOnce(1);
-    }
-
-    return false;
-}
-
-TEST_F(DisplayTest, Hotplug) {
-    ALOGD("DisplayTest::Hotplug");
-
-    EXPECT_CALL(*mMockComposer, getDisplayType(EXTERNAL_DISPLAY, _))
-            .Times(2)
-            .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
-                                  Return(Error::NONE)));
-    // The attribute queries will get done twice. This is for defaults
-    EXPECT_CALL(*mMockComposer, getDisplayAttribute(EXTERNAL_DISPLAY, 1, _, _))
-            .Times(2 * 3)
-            .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
-    // ... and then special handling for dimensions. Specifying these
-    // rules later means that gmock will try them first, i.e.,
-    // ordering of width/height vs. the default implementation for
-    // other queries is significant.
-    EXPECT_CALL(*mMockComposer,
-                getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::WIDTH, _))
-            .Times(2)
-            .WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE)));
-
-    EXPECT_CALL(*mMockComposer,
-                getDisplayAttribute(EXTERNAL_DISPLAY, 1, IComposerClient::Attribute::HEIGHT, _))
-            .Times(2)
-            .WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE)));
-
-    mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED);
-
-    waitForDisplayTransaction();
-
-    EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
-
-    {
-        const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
-        ASSERT_FALSE(display == nullptr);
-
-        DisplayInfo info;
-        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
-        ASSERT_EQ(400u, info.w);
-        ASSERT_EQ(200u, info.h);
-
-        auto surfaceControl =
-                mComposerClient->createSurface(String8("Display Test Surface Foo"), info.w, info.h,
-                                               PIXEL_FORMAT_RGBA_8888, 0);
-        ASSERT_TRUE(surfaceControl != nullptr);
-        ASSERT_TRUE(surfaceControl->isValid());
-        fillSurfaceRGBA8(surfaceControl, BLUE);
+        mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+                                            V2_1::IComposerCallback::Connection::DISCONNECTED);
+        waitForDisplayTransaction();
+        mFakeComposerClient->clearFrames();
+        EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
 
         {
-            TransactionScope ts(*mMockComposer);
-            ts.setDisplayLayerStack(display, 0);
+            const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
+            EXPECT_TRUE(display == nullptr);
 
-            ts.setLayer(surfaceControl, INT32_MAX - 2)
-                .show(surfaceControl);
+            DisplayConfig config;
+            EXPECT_NE(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
         }
     }
 
-    mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
+    void Test_HotplugTwoSeparateConfigs() {
+        ALOGD("DisplayTest::Test_HotplugTwoSeparateConfigs");
 
-    mMockComposer->clearFrames();
+        setExpectationsForConfigs(EXTERNAL_DISPLAY,
+                                  {{.id = 1,
+                                    .w = 200,
+                                    .h = 400,
+                                    .vsyncPeriod = 16'666'666,
+                                    .group = 0},
+                                   {.id = 2,
+                                    .w = 800,
+                                    .h = 1600,
+                                    .vsyncPeriod = 11'111'111,
+                                    .group = 1}},
+                                  1, 16'666'666);
 
-    mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::CONNECTED);
+        mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+                                            V2_1::IComposerCallback::Connection::CONNECTED);
+        waitForDisplayTransaction();
+        EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
 
-    waitForDisplayTransaction();
-
-    EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
-    EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
-
-    {
         const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
-        ASSERT_FALSE(display == nullptr);
+        EXPECT_FALSE(display == nullptr);
 
-        DisplayInfo info;
-        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
-        ASSERT_EQ(400u, info.w);
-        ASSERT_EQ(200u, info.h);
+        DisplayConfig config;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+        EXPECT_EQ(ui::Size(200, 400), config.resolution);
+        EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
 
-        auto surfaceControl =
-                mComposerClient->createSurface(String8("Display Test Surface Bar"), info.w, info.h,
-                                               PIXEL_FORMAT_RGBA_8888, 0);
-        ASSERT_TRUE(surfaceControl != nullptr);
-        ASSERT_TRUE(surfaceControl->isValid());
-        fillSurfaceRGBA8(surfaceControl, BLUE);
+        mFakeComposerClient->clearFrames();
+        {
+            const ui::Size& resolution = config.resolution;
+            auto surfaceControl =
+                    mComposerClient->createSurface(String8("Display Test Surface Foo"),
+                                                   resolution.getWidth(), resolution.getHeight(),
+                                                   PIXEL_FORMAT_RGBA_8888, 0);
+            EXPECT_TRUE(surfaceControl != nullptr);
+            EXPECT_TRUE(surfaceControl->isValid());
+            fillSurfaceRGBA8(surfaceControl, BLUE);
+
+            {
+                TransactionScope ts(*mFakeComposerClient);
+                ts.setDisplayLayerStack(display, 0);
+
+                ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+            }
+        }
+
+        Vector<DisplayConfig> configs;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
+        EXPECT_EQ(configs.size(), 2);
+
+        // change active config
+
+        if (mIs2_4Client) {
+            EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 2, _, _))
+                    .WillOnce(Return(V2_4::Error::NONE));
+        } else {
+            EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 2))
+                    .WillOnce(Return(V2_1::Error::NONE));
+        }
+
+        for (int i = 0; i < configs.size(); i++) {
+            const auto& config = configs[i];
+            if (config.resolution.getWidth() == 800) {
+                EXPECT_EQ(NO_ERROR,
+                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate));
+                waitForDisplayTransaction();
+                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                break;
+            }
+        }
+
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+        EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+        EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
+
+        mFakeComposerClient->clearFrames();
+        {
+            const ui::Size& resolution = config.resolution;
+            auto surfaceControl =
+                    mComposerClient->createSurface(String8("Display Test Surface Foo"),
+                                                   resolution.getWidth(), resolution.getHeight(),
+                                                   PIXEL_FORMAT_RGBA_8888, 0);
+            EXPECT_TRUE(surfaceControl != nullptr);
+            EXPECT_TRUE(surfaceControl->isValid());
+            fillSurfaceRGBA8(surfaceControl, BLUE);
+
+            {
+                TransactionScope ts(*mFakeComposerClient);
+                ts.setDisplayLayerStack(display, 0);
+
+                ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+            }
+        }
+
+        mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+                                            V2_1::IComposerCallback::Connection::DISCONNECTED);
+        waitForDisplayTransaction();
+        mFakeComposerClient->clearFrames();
+        EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
+    }
+
+    void Test_HotplugTwoConfigsSameGroup() {
+        ALOGD("DisplayTest::Test_HotplugTwoConfigsSameGroup");
+
+        setExpectationsForConfigs(EXTERNAL_DISPLAY,
+                                  {{.id = 2,
+                                    .w = 800,
+                                    .h = 1600,
+                                    .vsyncPeriod = 16'666'666,
+                                    .group = 31},
+                                   {.id = 3,
+                                    .w = 800,
+                                    .h = 1600,
+                                    .vsyncPeriod = 11'111'111,
+                                    .group = 31}},
+                                  2, 16'666'666);
+
+        mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+                                            V2_1::IComposerCallback::Connection::CONNECTED);
+        waitForDisplayTransaction();
+        EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
+
+        const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
+        EXPECT_FALSE(display == nullptr);
+
+        DisplayConfig config;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+        EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+        EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
+
+        mFakeComposerClient->clearFrames();
+        {
+            const ui::Size& resolution = config.resolution;
+            auto surfaceControl =
+                    mComposerClient->createSurface(String8("Display Test Surface Foo"),
+                                                   resolution.getWidth(), resolution.getHeight(),
+                                                   PIXEL_FORMAT_RGBA_8888, 0);
+            EXPECT_TRUE(surfaceControl != nullptr);
+            EXPECT_TRUE(surfaceControl->isValid());
+            fillSurfaceRGBA8(surfaceControl, BLUE);
+
+            {
+                TransactionScope ts(*mFakeComposerClient);
+                ts.setDisplayLayerStack(display, 0);
+
+                ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+            }
+        }
+
+        Vector<DisplayConfig> configs;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
+        EXPECT_EQ(configs.size(), 2);
+
+        // change active config
+        if (mIs2_4Client) {
+            EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 3, _, _))
+                    .WillOnce(Return(V2_4::Error::NONE));
+        } else {
+            EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 3))
+                    .WillOnce(Return(V2_1::Error::NONE));
+        }
+
+        for (int i = 0; i < configs.size(); i++) {
+            const auto& config = configs[i];
+            if (config.refreshRate == 1e9f / 11'111'111) {
+                EXPECT_EQ(NO_ERROR,
+                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate));
+                waitForDisplayTransaction();
+                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                break;
+            }
+        }
+
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+        EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+        EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
+
+        mFakeComposerClient->clearFrames();
+        {
+            const ui::Size& resolution = config.resolution;
+            auto surfaceControl =
+                    mComposerClient->createSurface(String8("Display Test Surface Foo"),
+                                                   resolution.getWidth(), resolution.getHeight(),
+                                                   PIXEL_FORMAT_RGBA_8888, 0);
+            EXPECT_TRUE(surfaceControl != nullptr);
+            EXPECT_TRUE(surfaceControl->isValid());
+            fillSurfaceRGBA8(surfaceControl, BLUE);
+
+            {
+                TransactionScope ts(*mFakeComposerClient);
+                ts.setDisplayLayerStack(display, 0);
+
+                ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+            }
+        }
+
+        mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+                                            V2_1::IComposerCallback::Connection::DISCONNECTED);
+        waitForDisplayTransaction();
+        mFakeComposerClient->clearFrames();
+        EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
+    }
+
+    void Test_HotplugThreeConfigsMixedGroups() {
+        ALOGD("DisplayTest::Test_HotplugThreeConfigsMixedGroups");
+
+        setExpectationsForConfigs(EXTERNAL_DISPLAY,
+                                  {{.id = 2,
+                                    .w = 800,
+                                    .h = 1600,
+                                    .vsyncPeriod = 16'666'666,
+                                    .group = 0},
+                                   {.id = 3,
+                                    .w = 800,
+                                    .h = 1600,
+                                    .vsyncPeriod = 11'111'111,
+                                    .group = 0},
+                                   {.id = 4,
+                                    .w = 1600,
+                                    .h = 3200,
+                                    .vsyncPeriod = 8'333'333,
+                                    .group = 1},
+                                   {.id = 5,
+                                    .w = 1600,
+                                    .h = 3200,
+                                    .vsyncPeriod = 11'111'111,
+                                    .group = 1}},
+                                  2, 16'666'666);
+
+        mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+                                            V2_1::IComposerCallback::Connection::CONNECTED);
+        waitForDisplayTransaction();
+        EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
+
+        const auto display = SurfaceComposerClient::getPhysicalDisplayToken(EXTERNAL_DISPLAY);
+        EXPECT_FALSE(display == nullptr);
+
+        DisplayConfig config;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+        EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+        EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
+
+        mFakeComposerClient->clearFrames();
+        {
+            const ui::Size& resolution = config.resolution;
+            auto surfaceControl =
+                    mComposerClient->createSurface(String8("Display Test Surface Foo"),
+                                                   resolution.getWidth(), resolution.getHeight(),
+                                                   PIXEL_FORMAT_RGBA_8888, 0);
+            EXPECT_TRUE(surfaceControl != nullptr);
+            EXPECT_TRUE(surfaceControl->isValid());
+            fillSurfaceRGBA8(surfaceControl, BLUE);
+
+            {
+                TransactionScope ts(*mFakeComposerClient);
+                ts.setDisplayLayerStack(display, 0);
+
+                ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+            }
+        }
+
+        Vector<DisplayConfig> configs;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
+        EXPECT_EQ(configs.size(), 4);
+
+        // change active config to 800x1600@90Hz
+        if (mIs2_4Client) {
+            EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 3, _, _))
+                    .WillOnce(Return(V2_4::Error::NONE));
+        } else {
+            EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 3))
+                    .WillOnce(Return(V2_1::Error::NONE));
+        }
+
+        for (int i = 0; i < configs.size(); i++) {
+            const auto& config = configs[i];
+            if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) {
+                EXPECT_EQ(NO_ERROR,
+                          SurfaceComposerClient::
+                                  setDesiredDisplayConfigSpecs(display, i, configs[i].refreshRate,
+                                                               configs[i].refreshRate,
+                                                               configs[i].refreshRate,
+                                                               configs[i].refreshRate));
+                waitForDisplayTransaction();
+                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                break;
+            }
+        }
+
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+        EXPECT_EQ(ui::Size(800, 1600), config.resolution);
+        EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
+
+        mFakeComposerClient->clearFrames();
+        {
+            const ui::Size& resolution = config.resolution;
+            auto surfaceControl =
+                    mComposerClient->createSurface(String8("Display Test Surface Foo"),
+                                                   resolution.getWidth(), resolution.getHeight(),
+                                                   PIXEL_FORMAT_RGBA_8888, 0);
+            EXPECT_TRUE(surfaceControl != nullptr);
+            EXPECT_TRUE(surfaceControl->isValid());
+            fillSurfaceRGBA8(surfaceControl, BLUE);
+
+            {
+                TransactionScope ts(*mFakeComposerClient);
+                ts.setDisplayLayerStack(display, 0);
+
+                ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+            }
+        }
+
+        // change active config to 1600x3200@120Hz
+        if (mIs2_4Client) {
+            EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 4, _, _))
+                    .WillOnce(Return(V2_4::Error::NONE));
+        } else {
+            EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 4))
+                    .WillOnce(Return(V2_1::Error::NONE));
+        }
+
+        for (int i = 0; i < configs.size(); i++) {
+            const auto& config = configs[i];
+            if (config.refreshRate == 1e9f / 8'333'333) {
+                EXPECT_EQ(NO_ERROR,
+                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate));
+                waitForDisplayTransaction();
+                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                break;
+            }
+        }
+
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+        EXPECT_EQ(ui::Size(1600, 3200), config.resolution);
+        EXPECT_EQ(1e9f / 8'333'333, config.refreshRate);
+
+        mFakeComposerClient->clearFrames();
+        {
+            const ui::Size& resolution = config.resolution;
+            auto surfaceControl =
+                    mComposerClient->createSurface(String8("Display Test Surface Foo"),
+                                                   resolution.getWidth(), resolution.getHeight(),
+                                                   PIXEL_FORMAT_RGBA_8888, 0);
+            EXPECT_TRUE(surfaceControl != nullptr);
+            EXPECT_TRUE(surfaceControl->isValid());
+            fillSurfaceRGBA8(surfaceControl, BLUE);
+
+            {
+                TransactionScope ts(*mFakeComposerClient);
+                ts.setDisplayLayerStack(display, 0);
+
+                ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+            }
+        }
+
+        // change active config to 1600x3200@90Hz
+        if (mIs2_4Client) {
+            EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 5, _, _))
+                    .WillOnce(Return(V2_4::Error::NONE));
+        } else {
+            EXPECT_CALL(*mMockComposer, setActiveConfig(EXTERNAL_DISPLAY, 5))
+                    .WillOnce(Return(V2_1::Error::NONE));
+        }
+
+        for (int i = 0; i < configs.size(); i++) {
+            const auto& config = configs[i];
+            if (config.resolution.getWidth() == 1600 && config.refreshRate == 1e9f / 11'111'111) {
+                EXPECT_EQ(NO_ERROR,
+                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate,
+                                                                              config.refreshRate));
+                waitForDisplayTransaction();
+                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                break;
+            }
+        }
+
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+        EXPECT_EQ(ui::Size(1600, 3200), config.resolution);
+        EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
+
+        mFakeComposerClient->clearFrames();
+        {
+            const ui::Size& resolution = config.resolution;
+            auto surfaceControl =
+                    mComposerClient->createSurface(String8("Display Test Surface Foo"),
+                                                   resolution.getWidth(), resolution.getHeight(),
+                                                   PIXEL_FORMAT_RGBA_8888, 0);
+            EXPECT_TRUE(surfaceControl != nullptr);
+            EXPECT_TRUE(surfaceControl->isValid());
+            fillSurfaceRGBA8(surfaceControl, BLUE);
+
+            {
+                TransactionScope ts(*mFakeComposerClient);
+                ts.setDisplayLayerStack(display, 0);
+
+                ts.setLayer(surfaceControl, INT32_MAX - 2).show(surfaceControl);
+            }
+        }
+
+        mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
+                                            V2_1::IComposerCallback::Connection::DISCONNECTED);
+        waitForDisplayTransaction();
+        mFakeComposerClient->clearFrames();
+        EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
+    }
+
+    void Test_HotplugPrimaryDisplay() {
+        ALOGD("DisplayTest::HotplugPrimaryDisplay");
+
+        mFakeComposerClient->hotplugDisplay(PRIMARY_DISPLAY,
+                                            V2_1::IComposerCallback::Connection::DISCONNECTED);
+
+        waitForDisplayTransaction();
+
+        EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, false));
+        {
+            const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+            EXPECT_TRUE(display == nullptr);
+
+            DisplayConfig config;
+            auto result = SurfaceComposerClient::getActiveDisplayConfig(display, &config);
+            EXPECT_NE(NO_ERROR, result);
+        }
+
+        mFakeComposerClient->clearFrames();
+
+        setExpectationsForConfigs(PRIMARY_DISPLAY,
+                                  {{.id = 1,
+                                    .w = 400,
+                                    .h = 200,
+                                    .vsyncPeriod = 16'666'666,
+                                    .group = 0}},
+                                  1, 16'666'666);
+
+        mFakeComposerClient->hotplugDisplay(PRIMARY_DISPLAY,
+                                            V2_1::IComposerCallback::Connection::CONNECTED);
+
+        waitForDisplayTransaction();
+
+        EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, true));
 
         {
-            TransactionScope ts(*mMockComposer);
-            ts.setDisplayLayerStack(display, 0);
+            const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+            EXPECT_FALSE(display == nullptr);
 
-            ts.setLayer(surfaceControl, INT32_MAX - 2)
-                .show(surfaceControl);
+            DisplayConfig config;
+            auto result = SurfaceComposerClient::getActiveDisplayConfig(display, &config);
+            EXPECT_EQ(NO_ERROR, result);
+            ASSERT_EQ(ui::Size(400, 200), config.resolution);
+            EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
         }
     }
-    mMockComposer->hotplugDisplay(EXTERNAL_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
+
+    sp<V2_1::IComposer> mFakeService;
+    sp<SurfaceComposerClient> mComposerClient;
+
+    std::unique_ptr<MockComposerHal> mMockComposer;
+    FakeComposerClient* mFakeComposerClient;
+
+    std::unique_ptr<DisplayEventReceiver> mReceiver;
+    sp<Looper> mLooper;
+    std::deque<DisplayEventReceiver::Event> mReceivedDisplayEvents;
+
+    static constexpr bool mIs2_4Client =
+            std::is_same<FakeComposerService, FakeComposerService_2_4>::value;
+};
+
+using DisplayTest_2_1 = DisplayTest<FakeComposerService_2_1>;
+
+TEST_F(DisplayTest_2_1, HotplugOneConfig) {
+    Test_HotplugOneConfig();
 }
 
-TEST_F(DisplayTest, HotplugPrimaryDisplay) {
-    ALOGD("DisplayTest::HotplugPrimaryDisplay");
+TEST_F(DisplayTest_2_1, HotplugTwoSeparateConfigs) {
+    Test_HotplugTwoSeparateConfigs();
+}
 
-    mMockComposer->hotplugDisplay(PRIMARY_DISPLAY, IComposerCallback::Connection::DISCONNECTED);
+TEST_F(DisplayTest_2_1, HotplugTwoConfigsSameGroup) {
+    Test_HotplugTwoConfigsSameGroup();
+}
 
-    waitForDisplayTransaction();
+TEST_F(DisplayTest_2_1, HotplugThreeConfigsMixedGroups) {
+    Test_HotplugThreeConfigsMixedGroups();
+}
 
-    EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, false));
+TEST_F(DisplayTest_2_1, HotplugPrimaryOneConfig) {
+    Test_HotplugPrimaryDisplay();
+}
 
-    {
-        const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
-        EXPECT_FALSE(display == nullptr);
+using DisplayTest_2_2 = DisplayTest<FakeComposerService_2_2>;
 
-        DisplayInfo info;
-        auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
-        EXPECT_NE(NO_ERROR, result);
-    }
+TEST_F(DisplayTest_2_2, HotplugOneConfig) {
+    Test_HotplugOneConfig();
+}
 
-    mMockComposer->clearFrames();
+TEST_F(DisplayTest_2_2, HotplugTwoSeparateConfigs) {
+    Test_HotplugTwoSeparateConfigs();
+}
 
-    EXPECT_CALL(*mMockComposer, getDisplayType(PRIMARY_DISPLAY, _))
-            .Times(2)
-            .WillRepeatedly(DoAll(SetArgPointee<1>(IComposerClient::DisplayType::PHYSICAL),
-                                  Return(Error::NONE)));
-    // The attribute queries will get done twice. This is for defaults
-    EXPECT_CALL(*mMockComposer, getDisplayAttribute(PRIMARY_DISPLAY, 1, _, _))
-            .Times(2 * 3)
-            .WillRepeatedly(Invoke(mMockComposer, &MockComposerClient::getDisplayAttributeFake));
-    // ... and then special handling for dimensions. Specifying these
-    // rules later means that gmock will try them first, i.e.,
-    // ordering of width/height vs. the default implementation for
-    // other queries is significant.
-    EXPECT_CALL(*mMockComposer,
-                getDisplayAttribute(PRIMARY_DISPLAY, 1, IComposerClient::Attribute::WIDTH, _))
-            .Times(2)
-            .WillRepeatedly(DoAll(SetArgPointee<3>(400), Return(Error::NONE)));
+TEST_F(DisplayTest_2_2, HotplugTwoConfigsSameGroup) {
+    Test_HotplugTwoConfigsSameGroup();
+}
 
-    EXPECT_CALL(*mMockComposer,
-                getDisplayAttribute(PRIMARY_DISPLAY, 1, IComposerClient::Attribute::HEIGHT, _))
-            .Times(2)
-            .WillRepeatedly(DoAll(SetArgPointee<3>(200), Return(Error::NONE)));
+TEST_F(DisplayTest_2_2, HotplugThreeConfigsMixedGroups) {
+    Test_HotplugThreeConfigsMixedGroups();
+}
 
-    mMockComposer->hotplugDisplay(PRIMARY_DISPLAY, IComposerCallback::Connection::CONNECTED);
+TEST_F(DisplayTest_2_2, HotplugPrimaryOneConfig) {
+    Test_HotplugPrimaryDisplay();
+}
 
-    waitForDisplayTransaction();
+using DisplayTest_2_3 = DisplayTest<FakeComposerService_2_3>;
 
-    EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, true));
+TEST_F(DisplayTest_2_3, HotplugOneConfig) {
+    Test_HotplugOneConfig();
+}
 
-    {
-        const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
-        EXPECT_FALSE(display == nullptr);
+TEST_F(DisplayTest_2_3, HotplugTwoSeparateConfigs) {
+    Test_HotplugTwoSeparateConfigs();
+}
 
-        DisplayInfo info;
-        auto result = SurfaceComposerClient::getDisplayInfo(display, &info);
-        EXPECT_EQ(NO_ERROR, result);
-        ASSERT_EQ(400u, info.w);
-        ASSERT_EQ(200u, info.h);
-    }
+TEST_F(DisplayTest_2_3, HotplugTwoConfigsSameGroup) {
+    Test_HotplugTwoConfigsSameGroup();
+}
+
+TEST_F(DisplayTest_2_3, HotplugThreeConfigsMixedGroups) {
+    Test_HotplugThreeConfigsMixedGroups();
+}
+
+TEST_F(DisplayTest_2_3, HotplugPrimaryOneConfig) {
+    Test_HotplugPrimaryDisplay();
+}
+
+using DisplayTest_2_4 = DisplayTest<FakeComposerService_2_4>;
+
+TEST_F(DisplayTest_2_4, HotplugOneConfig) {
+    Test_HotplugOneConfig();
+}
+
+TEST_F(DisplayTest_2_4, HotplugTwoSeparateConfigs) {
+    Test_HotplugTwoSeparateConfigs();
+}
+
+TEST_F(DisplayTest_2_4, HotplugTwoConfigsSameGroup) {
+    Test_HotplugTwoConfigsSameGroup();
+}
+
+TEST_F(DisplayTest_2_4, HotplugThreeConfigsMixedGroups) {
+    Test_HotplugThreeConfigsMixedGroups();
+}
+
+TEST_F(DisplayTest_2_4, HotplugPrimaryOneConfig) {
+    Test_HotplugPrimaryDisplay();
 }
 
 ////////////////////////////////////////////////
 
+template <typename FakeComposerService>
 class TransactionTest : public ::testing::Test {
 protected:
     // Layer array indexing constants.
     constexpr static int BG_LAYER = 0;
     constexpr static int FG_LAYER = 1;
 
-    static void SetUpTestCase();
-    static void TearDownTestCase();
+    static void SetUpTestCase() {
+        // TODO: See TODO comment at DisplayTest::SetUp for background on
+        // the lifetime of the FakeComposerClient.
+        sFakeComposer = new FakeComposerClient;
+        sp<V2_4::hal::ComposerClient> client = new V2_4::hal::ComposerClient(sFakeComposer);
+        sp<V2_1::IComposer> fakeService = new FakeComposerService(client);
+        (void)fakeService->registerAsService("mock");
 
-    void SetUp() override;
-    void TearDown() override;
+        android::hardware::ProcessState::self()->startThreadPool();
+        android::ProcessState::self()->startThreadPool();
+
+        startSurfaceFlinger();
+
+        // Fake composer wants to enable VSync injection
+        sFakeComposer->onSurfaceFlingerStart();
+    }
+
+    static void TearDownTestCase() {
+        // Fake composer needs to release SurfaceComposerClient before the stop.
+        sFakeComposer->onSurfaceFlingerStop();
+        stopSurfaceFlinger();
+        // TODO: This is deleted when the ComposerClient calls
+        // removeClient. Devise better lifetime control.
+        sFakeComposer = nullptr;
+    }
+
+    void SetUp() override {
+        ALOGI("TransactionTest::SetUp");
+        mComposerClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+        ALOGI("TransactionTest::SetUp - display");
+        const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
+        ASSERT_FALSE(display == nullptr);
+
+        DisplayConfig config;
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+
+        const ui::Size& resolution = config.resolution;
+        mDisplayWidth = resolution.getWidth();
+        mDisplayHeight = resolution.getHeight();
+
+        // Background surface
+        mBGSurfaceControl =
+                mComposerClient->createSurface(String8("BG Test Surface"), mDisplayWidth,
+                                               mDisplayHeight, PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(mBGSurfaceControl != nullptr);
+        ASSERT_TRUE(mBGSurfaceControl->isValid());
+        fillSurfaceRGBA8(mBGSurfaceControl, BLUE);
+
+        // Foreground surface
+        mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64,
+                                                           PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(mFGSurfaceControl != nullptr);
+        ASSERT_TRUE(mFGSurfaceControl->isValid());
+
+        fillSurfaceRGBA8(mFGSurfaceControl, RED);
+
+        Transaction t;
+        t.setDisplayLayerStack(display, 0);
+
+        t.setLayer(mBGSurfaceControl, INT32_MAX - 2);
+        t.show(mBGSurfaceControl);
+
+        t.setLayer(mFGSurfaceControl, INT32_MAX - 1);
+        t.setPosition(mFGSurfaceControl, 64, 64);
+        t.show(mFGSurfaceControl);
+
+        // Synchronous transaction will stop this thread, so we set up a
+        // delayed, off-thread vsync request before closing the
+        // transaction. In the test code this is usually done with
+        // TransactionScope. Leaving here in the 'vanilla' form for
+        // reference.
+        ASSERT_EQ(0, sFakeComposer->getFrameCount());
+        sFakeComposer->runVSyncAfter(1ms);
+        t.apply();
+        sFakeComposer->waitUntilFrame(1);
+
+        // Reference data. This is what the HWC should see.
+        static_assert(BG_LAYER == 0 && FG_LAYER == 1, "Unexpected enum values for array indexing");
+        mBaseFrame.push_back(makeSimpleRect(0u, 0u, mDisplayWidth, mDisplayHeight));
+        mBaseFrame[BG_LAYER].mSwapCount = 1;
+        mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
+        mBaseFrame[FG_LAYER].mSwapCount = 1;
+
+        auto frame = sFakeComposer->getFrameRects(0);
+        ASSERT_TRUE(framesAreSame(mBaseFrame, frame));
+    }
+
+    void TearDown() override {
+        ALOGD("TransactionTest::TearDown");
+
+        mComposerClient->dispose();
+        mBGSurfaceControl = 0;
+        mFGSurfaceControl = 0;
+        mComposerClient = 0;
+
+        sFakeComposer->runVSyncAndWait();
+        mBaseFrame.clear();
+        sFakeComposer->clearFrames();
+        ASSERT_EQ(0, sFakeComposer->getFrameCount());
+
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        std::vector<LayerDebugInfo> layers;
+        status_t result = sf->getLayerDebugInfo(&layers);
+        if (result != NO_ERROR) {
+            ALOGE("Failed to get layers %s %d", strerror(-result), result);
+        } else {
+            // If this fails, the test being torn down leaked layers.
+            EXPECT_EQ(0u, layers.size());
+            if (layers.size() > 0) {
+                for (auto layer = layers.begin(); layer != layers.end(); ++layer) {
+                    std::cout << to_string(*layer).c_str();
+                }
+                // To ensure the next test has clean slate, will run the class
+                // tear down and setup here.
+                TearDownTestCase();
+                SetUpTestCase();
+            }
+        }
+        ALOGD("TransactionTest::TearDown - complete");
+    }
+
+    void Test_LayerMove() {
+        ALOGD("TransactionTest::LayerMove");
+
+        // The scope opens and closes a global transaction and, at the
+        // same time, makes sure the SurfaceFlinger progresses one frame
+        // after the transaction closes. The results of the transaction
+        // should be available in the latest frame stored by the fake
+        // composer.
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setPosition(mFGSurfaceControl, 128, 128);
+            // NOTE: No changes yet, so vsync will do nothing, HWC does not get any calls.
+            // (How to verify that? Throw in vsync and wait a 2x frame time? Separate test?)
+            //
+            // sFakeComposer->runVSyncAndWait();
+        }
+
+        fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+        sFakeComposer->runVSyncAndWait();
+
+        ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and
+                                                      // there's no extra frames.
+
+        // NOTE: Frame 0 is produced in the SetUp.
+        auto frame1Ref = mBaseFrame;
+        frame1Ref[FG_LAYER].mDisplayFrame =
+                hwc_rect_t{128, 128, 128 + 64, 128 + 64}; // Top-most layer moves.
+        EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
+
+        auto frame2Ref = frame1Ref;
+        frame2Ref[FG_LAYER].mSwapCount++;
+        EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
+    }
+
+    void Test_LayerResize() {
+        ALOGD("TransactionTest::LayerResize");
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setSize(mFGSurfaceControl, 128, 128);
+        }
+
+        fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
+        sFakeComposer->runVSyncAndWait();
+
+        ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and
+                                                      // there's no extra frames.
+
+        auto frame1Ref = mBaseFrame;
+        // NOTE: The resize should not be visible for frame 1 as there's no buffer with new size
+        // posted.
+        EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
+
+        auto frame2Ref = frame1Ref;
+        frame2Ref[FG_LAYER].mSwapCount++;
+        frame2Ref[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 128, 64 + 128};
+        frame2Ref[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 128.f, 128.f};
+        EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
+    }
+
+    void Test_LayerCrop() {
+        // TODO: Add scaling to confirm that crop happens in buffer space?
+        {
+            TransactionScope ts(*sFakeComposer);
+            Rect cropRect(16, 16, 32, 32);
+            ts.setCrop_legacy(mFGSurfaceControl, cropRect);
+        }
+        ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+        auto referenceFrame = mBaseFrame;
+        referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{16.f, 16.f, 32.f, 32.f};
+        referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64 + 16, 64 + 16, 64 + 32, 64 + 32};
+        EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_LayerSetLayer() {
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
+        }
+        ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+        // The layers will switch order, but both are rendered because the background layer is
+        // transparent (RGBA8888).
+        std::vector<RenderState> referenceFrame(2);
+        referenceFrame[0] = mBaseFrame[FG_LAYER];
+        referenceFrame[1] = mBaseFrame[BG_LAYER];
+        EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_LayerSetLayerOpaque() {
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
+            ts.setFlags(mBGSurfaceControl, layer_state_t::eLayerOpaque,
+                        layer_state_t::eLayerOpaque);
+        }
+        ASSERT_EQ(2, sFakeComposer->getFrameCount());
+
+        // The former foreground layer is now covered with opaque layer - it should have disappeared
+        std::vector<RenderState> referenceFrame(1);
+        referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+        EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_SetLayerStack() {
+        ALOGD("TransactionTest::SetLayerStack");
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setLayerStack(mFGSurfaceControl, 1);
+        }
+
+        // Foreground layer should have disappeared.
+        ASSERT_EQ(2, sFakeComposer->getFrameCount());
+        std::vector<RenderState> refFrame(1);
+        refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+        EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_LayerShowHide() {
+        ALOGD("TransactionTest::LayerShowHide");
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.hide(mFGSurfaceControl);
+        }
+
+        // Foreground layer should have disappeared.
+        ASSERT_EQ(2, sFakeComposer->getFrameCount());
+        std::vector<RenderState> refFrame(1);
+        refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+        EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.show(mFGSurfaceControl);
+        }
+
+        // Foreground layer should be back
+        ASSERT_EQ(3, sFakeComposer->getFrameCount());
+        EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_LayerSetAlpha() {
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setAlpha(mFGSurfaceControl, 0.75f);
+        }
+
+        ASSERT_EQ(2, sFakeComposer->getFrameCount());
+        auto referenceFrame = mBaseFrame;
+        referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
+        EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_LayerSetFlags() {
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setFlags(mFGSurfaceControl, layer_state_t::eLayerHidden,
+                        layer_state_t::eLayerHidden);
+        }
+
+        // Foreground layer should have disappeared.
+        ASSERT_EQ(2, sFakeComposer->getFrameCount());
+        std::vector<RenderState> refFrame(1);
+        refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+        EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_LayerSetMatrix() {
+        struct matrixTestData {
+            float matrix[4];
+            hwc_transform_t expectedTransform;
+            hwc_rect_t expectedDisplayFrame;
+        };
+
+        // The matrix operates on the display frame and is applied before
+        // the position is added. So, the foreground layer rect is (0, 0,
+        // 64, 64) is first transformed, potentially yielding negative
+        // coordinates and then the position (64, 64) is added yielding
+        // the final on-screen rectangles given.
+
+        const matrixTestData MATRIX_TESTS[7] = // clang-format off
+                {{{-1.f, 0.f, 0.f, 1.f},    HWC_TRANSFORM_FLIP_H,           {0, 64, 64, 128}},
+                 {{1.f, 0.f, 0.f, -1.f},    HWC_TRANSFORM_FLIP_V,           {64, 0, 128, 64}},
+                 {{0.f, 1.f, -1.f, 0.f},    HWC_TRANSFORM_ROT_90,           {0, 64, 64, 128}},
+                 {{-1.f, 0.f, 0.f, -1.f},   HWC_TRANSFORM_ROT_180,          {0, 0, 64, 64}},
+                 {{0.f, -1.f, 1.f, 0.f},    HWC_TRANSFORM_ROT_270,          {64, 0, 128, 64}},
+                 {{0.f, 1.f, 1.f, 0.f},     HWC_TRANSFORM_FLIP_H_ROT_90,    {64, 64, 128, 128}},
+                 {{0.f, 1.f, 1.f, 0.f},     HWC_TRANSFORM_FLIP_V_ROT_90,    {64, 64, 128, 128}}};
+        // clang-format on
+        constexpr int TEST_COUNT = sizeof(MATRIX_TESTS) / sizeof(matrixTestData);
+
+        for (int i = 0; i < TEST_COUNT; i++) {
+            // TODO: How to leverage the HWC2 stringifiers?
+            const matrixTestData& xform = MATRIX_TESTS[i];
+            SCOPED_TRACE(i);
+            {
+                TransactionScope ts(*sFakeComposer);
+                ts.setMatrix(mFGSurfaceControl, xform.matrix[0], xform.matrix[1], xform.matrix[2],
+                             xform.matrix[3]);
+            }
+
+            auto referenceFrame = mBaseFrame;
+            referenceFrame[FG_LAYER].mTransform = xform.expectedTransform;
+            referenceFrame[FG_LAYER].mDisplayFrame = xform.expectedDisplayFrame;
+
+            EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+        }
+    }
+
+    void Test_DeferredTransaction() {
+        // Synchronization surface
+        constexpr static int SYNC_LAYER = 2;
+        auto syncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1,
+                                                                 PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(syncSurfaceControl != nullptr);
+        ASSERT_TRUE(syncSurfaceControl->isValid());
+
+        fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setLayer(syncSurfaceControl, INT32_MAX - 1);
+            ts.setPosition(syncSurfaceControl, mDisplayWidth - 2, mDisplayHeight - 2);
+            ts.show(syncSurfaceControl);
+        }
+        auto referenceFrame = mBaseFrame;
+        referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2,
+                                                mDisplayWidth - 1, mDisplayHeight - 1));
+        referenceFrame[SYNC_LAYER].mSwapCount = 1;
+        EXPECT_EQ(2, sFakeComposer->getFrameCount());
+        EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+        // set up two deferred transactions on different frames - these should not yield composited
+        // frames
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setAlpha(mFGSurfaceControl, 0.75);
+            ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl->getHandle(),
+                                            syncSurfaceControl->getSurface()->getNextFrameNumber());
+        }
+        EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setPosition(mFGSurfaceControl, 128, 128);
+            ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl->getHandle(),
+                                            syncSurfaceControl->getSurface()->getNextFrameNumber() +
+                                                    1);
+        }
+        EXPECT_EQ(4, sFakeComposer->getFrameCount());
+        EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+        // should trigger the first deferred transaction, but not the second one
+        fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+        sFakeComposer->runVSyncAndWait();
+        EXPECT_EQ(5, sFakeComposer->getFrameCount());
+
+        referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
+        referenceFrame[SYNC_LAYER].mSwapCount++;
+        EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+        // should show up immediately since it's not deferred
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setAlpha(mFGSurfaceControl, 1.0);
+        }
+        referenceFrame[FG_LAYER].mPlaneAlpha = 1.f;
+        EXPECT_EQ(6, sFakeComposer->getFrameCount());
+        EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+        // trigger the second deferred transaction
+        fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
+        sFakeComposer->runVSyncAndWait();
+        // TODO: Compute from layer size?
+        referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{128, 128, 128 + 64, 128 + 64};
+        referenceFrame[SYNC_LAYER].mSwapCount++;
+        EXPECT_EQ(7, sFakeComposer->getFrameCount());
+        EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_SetRelativeLayer() {
+        constexpr int RELATIVE_LAYER = 2;
+        auto relativeSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), 64,
+                                                                     64, PIXEL_FORMAT_RGBA_8888, 0);
+        fillSurfaceRGBA8(relativeSurfaceControl, LIGHT_RED);
+
+        // Now we stack the surface above the foreground surface and make sure it is visible.
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setPosition(relativeSurfaceControl, 64, 64);
+            ts.show(relativeSurfaceControl);
+            ts.setRelativeLayer(relativeSurfaceControl, mFGSurfaceControl->getHandle(), 1);
+        }
+        auto referenceFrame = mBaseFrame;
+        // NOTE: All three layers will be visible as the surfaces are
+        // transparent because of the RGBA format.
+        referenceFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
+        referenceFrame[RELATIVE_LAYER].mSwapCount = 1;
+        EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+        // A call to setLayer will override a call to setRelativeLayer
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setLayer(relativeSurfaceControl, 0);
+        }
+
+        // Previous top layer will now appear at the bottom.
+        auto referenceFrame2 = mBaseFrame;
+        referenceFrame2.insert(referenceFrame2.begin(), referenceFrame[RELATIVE_LAYER]);
+        EXPECT_EQ(3, sFakeComposer->getFrameCount());
+        EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+    }
 
     sp<SurfaceComposerClient> mComposerClient;
     sp<SurfaceControl> mBGSurfaceControl;
@@ -442,944 +1399,609 @@
     uint32_t mDisplayWidth;
     uint32_t mDisplayHeight;
 
-    static FakeComposerClient* sFakeComposer;
+    static inline FakeComposerClient* sFakeComposer;
 };
 
-FakeComposerClient* TransactionTest::sFakeComposer;
+using TransactionTest_2_1 = TransactionTest<FakeComposerService_2_1>;
 
-void TransactionTest::SetUpTestCase() {
-    // TODO: See TODO comment at DisplayTest::SetUp for background on
-    // the lifetime of the FakeComposerClient.
-    sFakeComposer = new FakeComposerClient;
-    sp<ComposerClient> client = new ComposerClient(sFakeComposer);
-    sp<IComposer> fakeService = new FakeComposerService(client);
-    (void)fakeService->registerAsService("mock");
-
-    android::hardware::ProcessState::self()->startThreadPool();
-    android::ProcessState::self()->startThreadPool();
-
-    startSurfaceFlinger();
-
-    // Fake composer wants to enable VSync injection
-    sFakeComposer->onSurfaceFlingerStart();
+TEST_F(TransactionTest_2_1, DISABLED_LayerMove) {
+    Test_LayerMove();
 }
 
-void TransactionTest::TearDownTestCase() {
-    // Fake composer needs to release SurfaceComposerClient before the stop.
-    sFakeComposer->onSurfaceFlingerStop();
-    stopSurfaceFlinger();
-    // TODO: This is deleted when the ComposerClient calls
-    // removeClient. Devise better lifetime control.
-    sFakeComposer = nullptr;
+TEST_F(TransactionTest_2_1, DISABLED_LayerResize) {
+    Test_LayerResize();
 }
 
-void TransactionTest::SetUp() {
-    ALOGI("TransactionTest::SetUp");
-    mComposerClient = new SurfaceComposerClient;
-    ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
-
-    ALOGI("TransactionTest::SetUp - display");
-    const auto display = SurfaceComposerClient::getPhysicalDisplayToken(PRIMARY_DISPLAY);
-    ASSERT_FALSE(display == nullptr);
-
-    DisplayInfo info;
-    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
-
-    mDisplayWidth = info.w;
-    mDisplayHeight = info.h;
-
-    // Background surface
-    mBGSurfaceControl = mComposerClient->createSurface(String8("BG Test Surface"), mDisplayWidth,
-                                                       mDisplayHeight, PIXEL_FORMAT_RGBA_8888, 0);
-    ASSERT_TRUE(mBGSurfaceControl != nullptr);
-    ASSERT_TRUE(mBGSurfaceControl->isValid());
-    fillSurfaceRGBA8(mBGSurfaceControl, BLUE);
-
-    // Foreground surface
-    mFGSurfaceControl = mComposerClient->createSurface(String8("FG Test Surface"), 64, 64,
-                                                       PIXEL_FORMAT_RGBA_8888, 0);
-    ASSERT_TRUE(mFGSurfaceControl != nullptr);
-    ASSERT_TRUE(mFGSurfaceControl->isValid());
-
-    fillSurfaceRGBA8(mFGSurfaceControl, RED);
-
-    Transaction t;
-    t.setDisplayLayerStack(display, 0);
-
-    t.setLayer(mBGSurfaceControl, INT32_MAX - 2);
-    t.show(mBGSurfaceControl);
-
-    t.setLayer(mFGSurfaceControl, INT32_MAX - 1);
-    t.setPosition(mFGSurfaceControl, 64, 64);
-    t.show(mFGSurfaceControl);
-
-    // Synchronous transaction will stop this thread, so we set up a
-    // delayed, off-thread vsync request before closing the
-    // transaction. In the test code this is usually done with
-    // TransactionScope. Leaving here in the 'vanilla' form for
-    // reference.
-    ASSERT_EQ(0, sFakeComposer->getFrameCount());
-    sFakeComposer->runVSyncAfter(1ms);
-    t.apply();
-    sFakeComposer->waitUntilFrame(1);
-
-    // Reference data. This is what the HWC should see.
-    static_assert(BG_LAYER == 0 && FG_LAYER == 1, "Unexpected enum values for array indexing");
-    mBaseFrame.push_back(makeSimpleRect(0u, 0u, mDisplayWidth, mDisplayHeight));
-    mBaseFrame[BG_LAYER].mSwapCount = 1;
-    mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
-    mBaseFrame[FG_LAYER].mSwapCount = 1;
-
-    auto frame = sFakeComposer->getFrameRects(0);
-    ASSERT_TRUE(framesAreSame(mBaseFrame, frame));
+TEST_F(TransactionTest_2_1, DISABLED_LayerCrop) {
+    Test_LayerCrop();
 }
 
-void TransactionTest::TearDown() {
-    ALOGD("TransactionTest::TearDown");
-
-    mComposerClient->dispose();
-    mBGSurfaceControl = 0;
-    mFGSurfaceControl = 0;
-    mComposerClient = 0;
-
-    sFakeComposer->runVSyncAndWait();
-    mBaseFrame.clear();
-    sFakeComposer->clearFrames();
-    ASSERT_EQ(0, sFakeComposer->getFrameCount());
-
-    sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    std::vector<LayerDebugInfo> layers;
-    status_t result = sf->getLayerDebugInfo(&layers);
-    if (result != NO_ERROR) {
-        ALOGE("Failed to get layers %s %d", strerror(-result), result);
-    } else {
-        // If this fails, the test being torn down leaked layers.
-        EXPECT_EQ(0u, layers.size());
-        if (layers.size() > 0) {
-            for (auto layer = layers.begin(); layer != layers.end(); ++layer) {
-                std::cout << to_string(*layer).c_str();
-            }
-            // To ensure the next test has clean slate, will run the class
-            // tear down and setup here.
-            TearDownTestCase();
-            SetUpTestCase();
-        }
-    }
-    ALOGD("TransactionTest::TearDown - complete");
+TEST_F(TransactionTest_2_1, DISABLED_LayerSetLayer) {
+    Test_LayerSetLayer();
 }
 
-TEST_F(TransactionTest, LayerMove) {
-    ALOGD("TransactionTest::LayerMove");
-
-    // The scope opens and closes a global transaction and, at the
-    // same time, makes sure the SurfaceFlinger progresses one frame
-    // after the transaction closes. The results of the transaction
-    // should be available in the latest frame stored by the fake
-    // composer.
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setPosition(mFGSurfaceControl, 128, 128);
-        // NOTE: No changes yet, so vsync will do nothing, HWC does not get any calls.
-        // (How to verify that? Throw in vsync and wait a 2x frame time? Separate test?)
-        //
-        // sFakeComposer->runVSyncAndWait();
-    }
-
-    fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
-    sFakeComposer->runVSyncAndWait();
-
-    ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's
-                                                  // no extra frames.
-
-    // NOTE: Frame 0 is produced in the SetUp.
-    auto frame1Ref = mBaseFrame;
-    frame1Ref[FG_LAYER].mDisplayFrame =
-            hwc_rect_t{128, 128, 128 + 64, 128 + 64}; // Top-most layer moves.
-    EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
-
-    auto frame2Ref = frame1Ref;
-    frame2Ref[FG_LAYER].mSwapCount++;
-    EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
+TEST_F(TransactionTest_2_1, DISABLED_LayerSetLayerOpaque) {
+    Test_LayerSetLayerOpaque();
 }
 
-TEST_F(TransactionTest, LayerResize) {
-    ALOGD("TransactionTest::LayerResize");
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setSize(mFGSurfaceControl, 128, 128);
-    }
-
-    fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
-    sFakeComposer->runVSyncAndWait();
-
-    ASSERT_EQ(3, sFakeComposer->getFrameCount()); // Make sure the waits didn't time out and there's
-                                                  // no extra frames.
-
-    auto frame1Ref = mBaseFrame;
-    // NOTE: The resize should not be visible for frame 1 as there's no buffer with new size posted.
-    EXPECT_TRUE(framesAreSame(frame1Ref, sFakeComposer->getFrameRects(1)));
-
-    auto frame2Ref = frame1Ref;
-    frame2Ref[FG_LAYER].mSwapCount++;
-    frame2Ref[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 128, 64 + 128};
-    frame2Ref[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 128.f, 128.f};
-    EXPECT_TRUE(framesAreSame(frame2Ref, sFakeComposer->getFrameRects(2)));
+TEST_F(TransactionTest_2_1, DISABLED_SetLayerStack) {
+    Test_SetLayerStack();
 }
 
-TEST_F(TransactionTest, LayerCrop) {
-    // TODO: Add scaling to confirm that crop happens in buffer space?
-    {
-        TransactionScope ts(*sFakeComposer);
-        Rect cropRect(16, 16, 32, 32);
-        ts.setCrop_legacy(mFGSurfaceControl, cropRect);
-    }
-    ASSERT_EQ(2, sFakeComposer->getFrameCount());
-
-    auto referenceFrame = mBaseFrame;
-    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{16.f, 16.f, 32.f, 32.f};
-    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64 + 16, 64 + 16, 64 + 32, 64 + 32};
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(TransactionTest_2_1, DISABLED_LayerShowHide) {
+    Test_LayerShowHide();
 }
 
-TEST_F(TransactionTest, LayerSetLayer) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
-    }
-    ASSERT_EQ(2, sFakeComposer->getFrameCount());
-
-    // The layers will switch order, but both are rendered because the background layer is
-    // transparent (RGBA8888).
-    std::vector<RenderState> referenceFrame(2);
-    referenceFrame[0] = mBaseFrame[FG_LAYER];
-    referenceFrame[1] = mBaseFrame[BG_LAYER];
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(TransactionTest_2_1, DISABLED_LayerSetAlpha) {
+    Test_LayerSetAlpha();
 }
 
-TEST_F(TransactionTest, LayerSetLayerOpaque) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setLayer(mFGSurfaceControl, INT_MAX - 3);
-        ts.setFlags(mBGSurfaceControl, layer_state_t::eLayerOpaque,
-                layer_state_t::eLayerOpaque);
-    }
-    ASSERT_EQ(2, sFakeComposer->getFrameCount());
-
-    // The former foreground layer is now covered with opaque layer - it should have disappeared
-    std::vector<RenderState> referenceFrame(1);
-    referenceFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(TransactionTest_2_1, DISABLED_LayerSetFlags) {
+    Test_LayerSetFlags();
 }
 
-TEST_F(TransactionTest, SetLayerStack) {
-    ALOGD("TransactionTest::SetLayerStack");
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setLayerStack(mFGSurfaceControl, 1);
-    }
-
-    // Foreground layer should have disappeared.
-    ASSERT_EQ(2, sFakeComposer->getFrameCount());
-    std::vector<RenderState> refFrame(1);
-    refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
-    EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+TEST_F(TransactionTest_2_1, DISABLED_LayerSetMatrix) {
+    Test_LayerSetMatrix();
 }
 
-TEST_F(TransactionTest, LayerShowHide) {
-    ALOGD("TransactionTest::LayerShowHide");
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.hide(mFGSurfaceControl);
-    }
-
-    // Foreground layer should have disappeared.
-    ASSERT_EQ(2, sFakeComposer->getFrameCount());
-    std::vector<RenderState> refFrame(1);
-    refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
-    EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.show(mFGSurfaceControl);
-    }
-
-    // Foreground layer should be back
-    ASSERT_EQ(3, sFakeComposer->getFrameCount());
-    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+TEST_F(TransactionTest_2_1, DISABLED_DeferredTransaction) {
+    Test_DeferredTransaction();
 }
 
-TEST_F(TransactionTest, LayerSetAlpha) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setAlpha(mFGSurfaceControl, 0.75f);
-    }
-
-    ASSERT_EQ(2, sFakeComposer->getFrameCount());
-    auto referenceFrame = mBaseFrame;
-    referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(TransactionTest_2_1, DISABLED_SetRelativeLayer) {
+    Test_SetRelativeLayer();
 }
 
-TEST_F(TransactionTest, LayerSetFlags) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setFlags(mFGSurfaceControl, layer_state_t::eLayerHidden,
-                layer_state_t::eLayerHidden);
-    }
+template <typename FakeComposerService>
+class ChildLayerTest : public TransactionTest<FakeComposerService> {
+    using Base = TransactionTest<FakeComposerService>;
 
-    // Foreground layer should have disappeared.
-    ASSERT_EQ(2, sFakeComposer->getFrameCount());
-    std::vector<RenderState> refFrame(1);
-    refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
-    EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
-}
-
-TEST_F(TransactionTest, LayerSetMatrix) {
-    struct matrixTestData {
-        float matrix[4];
-        hwc_transform_t expectedTransform;
-        hwc_rect_t expectedDisplayFrame;
-    };
-
-    // The matrix operates on the display frame and is applied before
-    // the position is added. So, the foreground layer rect is (0, 0,
-    // 64, 64) is first transformed, potentially yielding negative
-    // coordinates and then the position (64, 64) is added yielding
-    // the final on-screen rectangles given.
-
-    const matrixTestData MATRIX_TESTS[7] = // clang-format off
-            {{{-1.f, 0.f, 0.f, 1.f},    HWC_TRANSFORM_FLIP_H,           {0, 64, 64, 128}},
-             {{1.f, 0.f, 0.f, -1.f},    HWC_TRANSFORM_FLIP_V,           {64, 0, 128, 64}},
-             {{0.f, 1.f, -1.f, 0.f},    HWC_TRANSFORM_ROT_90,           {0, 64, 64, 128}},
-             {{-1.f, 0.f, 0.f, -1.f},   HWC_TRANSFORM_ROT_180,          {0, 0, 64, 64}},
-             {{0.f, -1.f, 1.f, 0.f},    HWC_TRANSFORM_ROT_270,          {64, 0, 128, 64}},
-             {{0.f, 1.f, 1.f, 0.f},     HWC_TRANSFORM_FLIP_H_ROT_90,    {64, 64, 128, 128}},
-             {{0.f, 1.f, 1.f, 0.f},     HWC_TRANSFORM_FLIP_V_ROT_90,    {64, 64, 128, 128}}};
-    // clang-format on
-    constexpr int TEST_COUNT = sizeof(MATRIX_TESTS) / sizeof(matrixTestData);
-
-    for (int i = 0; i < TEST_COUNT; i++) {
-        // TODO: How to leverage the HWC2 stringifiers?
-        const matrixTestData& xform = MATRIX_TESTS[i];
-        SCOPED_TRACE(i);
-        {
-            TransactionScope ts(*sFakeComposer);
-            ts.setMatrix(mFGSurfaceControl, xform.matrix[0], xform.matrix[1],
-                    xform.matrix[2], xform.matrix[3]);
-        }
-
-        auto referenceFrame = mBaseFrame;
-        referenceFrame[FG_LAYER].mTransform = xform.expectedTransform;
-        referenceFrame[FG_LAYER].mDisplayFrame = xform.expectedDisplayFrame;
-
-        EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-    }
-}
-
-#if 0
-TEST_F(TransactionTest, LayerSetMatrix2) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        // TODO: PLEASE SPEC THE FUNCTION!
-        ts.setMatrix(mFGSurfaceControl, 0.11f, 0.123f,
-                -2.33f, 0.22f);
-    }
-    auto referenceFrame = mBaseFrame;
-    // TODO: Is this correct for sure?
-    //referenceFrame[FG_LAYER].mTransform = HWC_TRANSFORM_FLIP_V & HWC_TRANSFORM_ROT_90;
-
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-}
-#endif
-
-TEST_F(TransactionTest, DeferredTransaction) {
-    // Synchronization surface
-    constexpr static int SYNC_LAYER = 2;
-    auto syncSurfaceControl = mComposerClient->createSurface(String8("Sync Test Surface"), 1, 1,
-                                                             PIXEL_FORMAT_RGBA_8888, 0);
-    ASSERT_TRUE(syncSurfaceControl != nullptr);
-    ASSERT_TRUE(syncSurfaceControl->isValid());
-
-    fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setLayer(syncSurfaceControl, INT32_MAX - 1);
-        ts.setPosition(syncSurfaceControl, mDisplayWidth - 2, mDisplayHeight - 2);
-        ts.show(syncSurfaceControl);
-    }
-    auto referenceFrame = mBaseFrame;
-    referenceFrame.push_back(makeSimpleRect(mDisplayWidth - 2, mDisplayHeight - 2,
-                                            mDisplayWidth - 1, mDisplayHeight - 1));
-    referenceFrame[SYNC_LAYER].mSwapCount = 1;
-    EXPECT_EQ(2, sFakeComposer->getFrameCount());
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
-    // set up two deferred transactions on different frames - these should not yield composited
-    // frames
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setAlpha(mFGSurfaceControl, 0.75);
-        ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl->getHandle(),
-                                        syncSurfaceControl->getSurface()->getNextFrameNumber());
-    }
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setPosition(mFGSurfaceControl, 128, 128);
-        ts.deferTransactionUntil_legacy(mFGSurfaceControl, syncSurfaceControl->getHandle(),
-                                        syncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
-    }
-    EXPECT_EQ(4, sFakeComposer->getFrameCount());
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
-    // should trigger the first deferred transaction, but not the second one
-    fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
-    sFakeComposer->runVSyncAndWait();
-    EXPECT_EQ(5, sFakeComposer->getFrameCount());
-
-    referenceFrame[FG_LAYER].mPlaneAlpha = 0.75f;
-    referenceFrame[SYNC_LAYER].mSwapCount++;
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
-    // should show up immediately since it's not deferred
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setAlpha(mFGSurfaceControl, 1.0);
-    }
-    referenceFrame[FG_LAYER].mPlaneAlpha = 1.f;
-    EXPECT_EQ(6, sFakeComposer->getFrameCount());
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
-    // trigger the second deferred transaction
-    fillSurfaceRGBA8(syncSurfaceControl, DARK_GRAY);
-    sFakeComposer->runVSyncAndWait();
-    // TODO: Compute from layer size?
-    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{128, 128, 128 + 64, 128 + 64};
-    referenceFrame[SYNC_LAYER].mSwapCount++;
-    EXPECT_EQ(7, sFakeComposer->getFrameCount());
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-}
-
-TEST_F(TransactionTest, SetRelativeLayer) {
-    constexpr int RELATIVE_LAYER = 2;
-    auto relativeSurfaceControl = mComposerClient->createSurface(String8("Test Surface"), 64, 64,
-                                                                 PIXEL_FORMAT_RGBA_8888, 0);
-    fillSurfaceRGBA8(relativeSurfaceControl, LIGHT_RED);
-
-    // Now we stack the surface above the foreground surface and make sure it is visible.
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setPosition(relativeSurfaceControl, 64, 64);
-        ts.show(relativeSurfaceControl);
-        ts.setRelativeLayer(relativeSurfaceControl, mFGSurfaceControl->getHandle(), 1);
-    }
-    auto referenceFrame = mBaseFrame;
-    // NOTE: All three layers will be visible as the surfaces are
-    // transparent because of the RGBA format.
-    referenceFrame.push_back(makeSimpleRect(64, 64, 64 + 64, 64 + 64));
-    referenceFrame[RELATIVE_LAYER].mSwapCount = 1;
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
-    // A call to setLayer will override a call to setRelativeLayer
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setLayer(relativeSurfaceControl, 0);
-    }
-
-    // Previous top layer will now appear at the bottom.
-    auto referenceFrame2 = mBaseFrame;
-    referenceFrame2.insert(referenceFrame2.begin(), referenceFrame[RELATIVE_LAYER]);
-    EXPECT_EQ(3, sFakeComposer->getFrameCount());
-    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
-}
-
-class ChildLayerTest : public TransactionTest {
 protected:
     constexpr static int CHILD_LAYER = 2;
 
     void SetUp() override {
-        TransactionTest::SetUp();
-        mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10,
-                                                PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+        Base::SetUp();
+        mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10,
+                                                      PIXEL_FORMAT_RGBA_8888, 0,
+                                                      Base::mFGSurfaceControl.get());
         fillSurfaceRGBA8(mChild, LIGHT_GRAY);
 
-        sFakeComposer->runVSyncAndWait();
-        mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
-        mBaseFrame[CHILD_LAYER].mSwapCount = 1;
-        ASSERT_EQ(2, sFakeComposer->getFrameCount());
-        ASSERT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+        Base::sFakeComposer->runVSyncAndWait();
+        Base::mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
+        Base::mBaseFrame[CHILD_LAYER].mSwapCount = 1;
+        ASSERT_EQ(2, Base::sFakeComposer->getFrameCount());
+        ASSERT_TRUE(framesAreSame(Base::mBaseFrame, Base::sFakeComposer->getLatestFrame()));
     }
+
     void TearDown() override {
         mChild = 0;
-        TransactionTest::TearDown();
+        Base::TearDown();
+    }
+
+    void Test_Positioning() {
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.show(mChild);
+            ts.setPosition(mChild, 10, 10);
+            // Move to the same position as in the original setup.
+            ts.setPosition(Base::mFGSurfaceControl, 64, 64);
+        }
+
+        auto referenceFrame = Base::mBaseFrame;
+        referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+        referenceFrame[CHILD_LAYER].mDisplayFrame =
+                hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+        }
+
+        auto referenceFrame2 = Base::mBaseFrame;
+        referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 64, 0 + 64};
+        referenceFrame2[CHILD_LAYER].mDisplayFrame =
+                hwc_rect_t{0 + 10, 0 + 10, 0 + 10 + 10, 0 + 10 + 10};
+        EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_Cropping() {
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.show(mChild);
+            ts.setPosition(mChild, 0, 0);
+            ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+            ts.setCrop_legacy(Base::mFGSurfaceControl, Rect(0, 0, 5, 5));
+        }
+        // NOTE: The foreground surface would be occluded by the child
+        // now, but is included in the stack because the child is
+        // transparent.
+        auto referenceFrame = Base::mBaseFrame;
+        referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+        referenceFrame[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+        referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
+        referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
+        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_Constraints() {
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.show(mChild);
+            ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+            ts.setPosition(mChild, 63, 63);
+        }
+        auto referenceFrame = Base::mBaseFrame;
+        referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+        referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{63, 63, 64, 64};
+        referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 1.f, 1.f};
+        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_Scaling() {
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+        }
+        auto referenceFrame = Base::mBaseFrame;
+        referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+        referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.setMatrix(Base::mFGSurfaceControl, 2.0, 0, 0, 2.0);
+        }
+
+        auto referenceFrame2 = Base::mBaseFrame;
+        referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
+        referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
+        EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_LayerAlpha() {
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.show(mChild);
+            ts.setPosition(mChild, 0, 0);
+            ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+            ts.setAlpha(mChild, 0.5);
+        }
+
+        auto referenceFrame = Base::mBaseFrame;
+        referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+        referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+        referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
+        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.setAlpha(Base::mFGSurfaceControl, 0.5);
+        }
+
+        auto referenceFrame2 = referenceFrame;
+        referenceFrame2[Base::FG_LAYER].mPlaneAlpha = 0.5f;
+        referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f;
+        EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_ReparentChildren() {
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.show(mChild);
+            ts.setPosition(mChild, 10, 10);
+            ts.setPosition(Base::mFGSurfaceControl, 64, 64);
+        }
+        auto referenceFrame = Base::mBaseFrame;
+        referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+        referenceFrame[CHILD_LAYER].mDisplayFrame =
+                hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.reparentChildren(Base::mFGSurfaceControl, Base::mBGSurfaceControl->getHandle());
+        }
+
+        auto referenceFrame2 = referenceFrame;
+        referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+        referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{10, 10, 10 + 10, 10 + 10};
+        EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_DetachChildrenSameClient() {
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.show(mChild);
+            ts.setPosition(mChild, 10, 10);
+            ts.setPosition(Base::mFGSurfaceControl, 64, 64);
+        }
+
+        auto referenceFrame = Base::mBaseFrame;
+        referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+        referenceFrame[CHILD_LAYER].mDisplayFrame =
+                hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+            ts.detachChildren(Base::mFGSurfaceControl);
+        }
+
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.setPosition(Base::mFGSurfaceControl, 64, 64);
+            ts.hide(mChild);
+        }
+
+        std::vector<RenderState> refFrame(2);
+        refFrame[Base::BG_LAYER] = Base::mBaseFrame[Base::BG_LAYER];
+        refFrame[Base::FG_LAYER] = Base::mBaseFrame[Base::FG_LAYER];
+
+        EXPECT_TRUE(framesAreSame(refFrame, Base::sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_DetachChildrenDifferentClient() {
+        sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+        sp<SurfaceControl> childNewClient =
+                newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
+                                                 PIXEL_FORMAT_RGBA_8888, 0,
+                                                 Base::mFGSurfaceControl.get());
+        ASSERT_TRUE(childNewClient != nullptr);
+        ASSERT_TRUE(childNewClient->isValid());
+        fillSurfaceRGBA8(childNewClient, LIGHT_GRAY);
+
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.hide(mChild);
+            ts.show(childNewClient);
+            ts.setPosition(childNewClient, 10, 10);
+            ts.setPosition(Base::mFGSurfaceControl, 64, 64);
+        }
+
+        auto referenceFrame = Base::mBaseFrame;
+        referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+        referenceFrame[CHILD_LAYER].mDisplayFrame =
+                hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.detachChildren(Base::mFGSurfaceControl);
+            ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+        }
+
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.setPosition(Base::mFGSurfaceControl, 64, 64);
+            ts.setPosition(childNewClient, 0, 0);
+            ts.hide(childNewClient);
+        }
+
+        // Nothing should have changed. The child control becomes a no-op
+        // zombie on detach. See comments for detachChildren in the
+        // SurfaceControl.h file.
+        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_InheritNonTransformScalingFromParent() {
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.show(mChild);
+            ts.setPosition(mChild, 0, 0);
+            ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+        }
+
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.setOverrideScalingMode(Base::mFGSurfaceControl,
+                                      NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+            // We cause scaling by 2.
+            ts.setSize(Base::mFGSurfaceControl, 128, 128);
+        }
+
+        auto referenceFrame = Base::mBaseFrame;
+        referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
+        referenceFrame[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 64.f};
+        referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
+        referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 10.f, 10.f};
+        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+    }
+
+    // Regression test for b/37673612
+    void Test_ChildrenWithParentBufferTransform() {
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.show(mChild);
+            ts.setPosition(mChild, 0, 0);
+            ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+        }
+
+        // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
+        // the WM specified state size.
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.setSize(Base::mFGSurfaceControl, 128, 64);
+        }
+
+        sp<Surface> s = Base::mFGSurfaceControl->getSurface();
+        auto anw = static_cast<ANativeWindow*>(s.get());
+        native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+        native_window_set_buffers_dimensions(anw, 64, 128);
+        fillSurfaceRGBA8(Base::mFGSurfaceControl, RED);
+        Base::sFakeComposer->runVSyncAndWait();
+
+        // The child should still be in the same place and not have any strange scaling as in
+        // b/37673612.
+        auto referenceFrame = Base::mBaseFrame;
+        referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 64};
+        referenceFrame[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 128.f};
+        referenceFrame[Base::FG_LAYER].mSwapCount++;
+        referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_Bug36858924() {
+        // Destroy the child layer
+        mChild.clear();
+
+        // Now recreate it as hidden
+        mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10,
+                                                      PIXEL_FORMAT_RGBA_8888,
+                                                      ISurfaceComposerClient::eHidden,
+                                                      Base::mFGSurfaceControl.get());
+
+        // Show the child layer in a deferred transaction
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.deferTransactionUntil_legacy(mChild, Base::mFGSurfaceControl->getHandle(),
+                                            Base::mFGSurfaceControl->getSurface()
+                                                    ->getNextFrameNumber());
+            ts.show(mChild);
+        }
+
+        // Render the foreground surface a few times
+        //
+        // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the
+        // third frame because SurfaceFlinger would never process the deferred transaction and would
+        // therefore never acquire/release the first buffer
+        ALOGI("Filling 1");
+        fillSurfaceRGBA8(Base::mFGSurfaceControl, GREEN);
+        Base::sFakeComposer->runVSyncAndWait();
+        ALOGI("Filling 2");
+        fillSurfaceRGBA8(Base::mFGSurfaceControl, BLUE);
+        Base::sFakeComposer->runVSyncAndWait();
+        ALOGI("Filling 3");
+        fillSurfaceRGBA8(Base::mFGSurfaceControl, RED);
+        Base::sFakeComposer->runVSyncAndWait();
+        ALOGI("Filling 4");
+        fillSurfaceRGBA8(Base::mFGSurfaceControl, GREEN);
+        Base::sFakeComposer->runVSyncAndWait();
     }
 
     sp<SurfaceControl> mChild;
 };
 
-TEST_F(ChildLayerTest, Positioning) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.show(mChild);
-        ts.setPosition(mChild, 10, 10);
-        // Move to the same position as in the original setup.
-        ts.setPosition(mFGSurfaceControl, 64, 64);
-    }
+using ChildLayerTest_2_1 = ChildLayerTest<FakeComposerService_2_1>;
 
-    auto referenceFrame = mBaseFrame;
-    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
-    referenceFrame[CHILD_LAYER].mDisplayFrame =
-            hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setPosition(mFGSurfaceControl, 0, 0);
-    }
-
-    auto referenceFrame2 = mBaseFrame;
-    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 64, 0 + 64};
-    referenceFrame2[CHILD_LAYER].mDisplayFrame =
-            hwc_rect_t{0 + 10, 0 + 10, 0 + 10 + 10, 0 + 10 + 10};
-    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_Positioning) {
+    Test_Positioning();
 }
 
-TEST_F(ChildLayerTest, Cropping) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.show(mChild);
-        ts.setPosition(mChild, 0, 0);
-        ts.setPosition(mFGSurfaceControl, 0, 0);
-        ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
-    }
-    // NOTE: The foreground surface would be occluded by the child
-    // now, but is included in the stack because the child is
-    // transparent.
-    auto referenceFrame = mBaseFrame;
-    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
-    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
-    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 0 + 5, 0 + 5};
-    referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 5.f, 5.f};
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_Cropping) {
+    Test_Cropping();
 }
 
-TEST_F(ChildLayerTest, Constraints) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.show(mChild);
-        ts.setPosition(mFGSurfaceControl, 0, 0);
-        ts.setPosition(mChild, 63, 63);
-    }
-    auto referenceFrame = mBaseFrame;
-    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
-    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{63, 63, 64, 64};
-    referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 1.f, 1.f};
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_Constraints) {
+    Test_Constraints();
 }
 
-TEST_F(ChildLayerTest, Scaling) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setPosition(mFGSurfaceControl, 0, 0);
-    }
-    auto referenceFrame = mBaseFrame;
-    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
-    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0);
-    }
-
-    auto referenceFrame2 = mBaseFrame;
-    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
-    referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
-    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_Scaling) {
+    Test_Scaling();
 }
 
-TEST_F(ChildLayerTest, LayerAlpha) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.show(mChild);
-        ts.setPosition(mChild, 0, 0);
-        ts.setPosition(mFGSurfaceControl, 0, 0);
-        ts.setAlpha(mChild, 0.5);
-    }
-
-    auto referenceFrame = mBaseFrame;
-    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
-    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
-    referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setAlpha(mFGSurfaceControl, 0.5);
-    }
-
-    auto referenceFrame2 = referenceFrame;
-    referenceFrame2[FG_LAYER].mPlaneAlpha = 0.5f;
-    referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f;
-    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_LayerAlpha) {
+    Test_LayerAlpha();
 }
 
-TEST_F(ChildLayerTest, ReparentChildren) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.show(mChild);
-        ts.setPosition(mChild, 10, 10);
-        ts.setPosition(mFGSurfaceControl, 64, 64);
-    }
-    auto referenceFrame = mBaseFrame;
-    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
-    referenceFrame[CHILD_LAYER].mDisplayFrame =
-            hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
-    }
-
-    auto referenceFrame2 = referenceFrame;
-    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
-    referenceFrame2[CHILD_LAYER].mDisplayFrame = hwc_rect_t{10, 10, 10 + 10, 10 + 10};
-    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_ReparentChildren) {
+    Test_ReparentChildren();
 }
 
-TEST_F(ChildLayerTest, DetachChildrenSameClient) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.show(mChild);
-        ts.setPosition(mChild, 10, 10);
-        ts.setPosition(mFGSurfaceControl, 64, 64);
-    }
-
-    auto referenceFrame = mBaseFrame;
-    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
-    referenceFrame[CHILD_LAYER].mDisplayFrame =
-            hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setPosition(mFGSurfaceControl, 0, 0);
-        ts.detachChildren(mFGSurfaceControl);
-    }
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setPosition(mFGSurfaceControl, 64, 64);
-        ts.hide(mChild);
-    }
-
-    std::vector<RenderState> refFrame(2);
-    refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
-    refFrame[FG_LAYER] = mBaseFrame[FG_LAYER];
-
-    EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_DetachChildrenSameClient) {
+    Test_DetachChildrenSameClient();
 }
 
-TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
-    sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
-    sp<SurfaceControl> childNewClient =
-            newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
-                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-    ASSERT_TRUE(childNewClient != nullptr);
-    ASSERT_TRUE(childNewClient->isValid());
-    fillSurfaceRGBA8(childNewClient, LIGHT_GRAY);
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.hide(mChild);
-        ts.show(childNewClient);
-        ts.setPosition(childNewClient, 10, 10);
-        ts.setPosition(mFGSurfaceControl, 64, 64);
-    }
-
-    auto referenceFrame = mBaseFrame;
-    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
-    referenceFrame[CHILD_LAYER].mDisplayFrame =
-            hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.detachChildren(mFGSurfaceControl);
-        ts.setPosition(mFGSurfaceControl, 0, 0);
-    }
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setPosition(mFGSurfaceControl, 64, 64);
-        ts.setPosition(childNewClient, 0, 0);
-        ts.hide(childNewClient);
-    }
-
-    // Nothing should have changed. The child control becomes a no-op
-    // zombie on detach. See comments for detachChildren in the
-    // SurfaceControl.h file.
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_DetachChildrenDifferentClient) {
+    Test_DetachChildrenDifferentClient();
 }
 
-TEST_F(ChildLayerTest, InheritNonTransformScalingFromParent) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.show(mChild);
-        ts.setPosition(mChild, 0, 0);
-        ts.setPosition(mFGSurfaceControl, 0, 0);
-    }
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
-        // We cause scaling by 2.
-        ts.setSize(mFGSurfaceControl, 128, 128);
-    }
-
-    auto referenceFrame = mBaseFrame;
-    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 128};
-    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 64.f};
-    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 20, 20};
-    referenceFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 10.f, 10.f};
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_InheritNonTransformScalingFromParent) {
+    Test_InheritNonTransformScalingFromParent();
 }
 
 // Regression test for b/37673612
-TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.show(mChild);
-        ts.setPosition(mChild, 0, 0);
-        ts.setPosition(mFGSurfaceControl, 0, 0);
-    }
-
-    // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
-    // the WM specified state size.
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setSize(mFGSurfaceControl, 128, 64);
-    }
-
-    sp<Surface> s = mFGSurfaceControl->getSurface();
-    auto anw = static_cast<ANativeWindow*>(s.get());
-    native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
-    native_window_set_buffers_dimensions(anw, 64, 128);
-    fillSurfaceRGBA8(mFGSurfaceControl, RED);
-    sFakeComposer->runVSyncAndWait();
-
-    // The child should still be in the same place and not have any strange scaling as in
-    // b/37673612.
-    auto referenceFrame = mBaseFrame;
-    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 128, 64};
-    referenceFrame[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 64.f, 128.f};
-    referenceFrame[FG_LAYER].mSwapCount++;
-    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+TEST_F(ChildLayerTest_2_1, DISABLED_ChildrenWithParentBufferTransform) {
+    Test_ChildrenWithParentBufferTransform();
 }
 
-TEST_F(ChildLayerTest, Bug36858924) {
-    // Destroy the child layer
-    mChild.clear();
-
-    // Now recreate it as hidden
-    mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10,
-                                            PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eHidden,
-                                            mFGSurfaceControl.get());
-
-    // Show the child layer in a deferred transaction
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.deferTransactionUntil_legacy(mChild, mFGSurfaceControl->getHandle(),
-                                        mFGSurfaceControl->getSurface()->getNextFrameNumber());
-        ts.show(mChild);
-    }
-
-    // Render the foreground surface a few times
-    //
-    // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third
-    // frame because SurfaceFlinger would never process the deferred transaction and would therefore
-    // never acquire/release the first buffer
-    ALOGI("Filling 1");
-    fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
-    sFakeComposer->runVSyncAndWait();
-    ALOGI("Filling 2");
-    fillSurfaceRGBA8(mFGSurfaceControl, BLUE);
-    sFakeComposer->runVSyncAndWait();
-    ALOGI("Filling 3");
-    fillSurfaceRGBA8(mFGSurfaceControl, RED);
-    sFakeComposer->runVSyncAndWait();
-    ALOGI("Filling 4");
-    fillSurfaceRGBA8(mFGSurfaceControl, GREEN);
-    sFakeComposer->runVSyncAndWait();
+TEST_F(ChildLayerTest_2_1, DISABLED_Bug36858924) {
+    Test_Bug36858924();
 }
 
-class ChildColorLayerTest : public ChildLayerTest {
+template <typename FakeComposerService>
+class ChildColorLayerTest : public ChildLayerTest<FakeComposerService> {
+    using Base = ChildLayerTest<FakeComposerService>;
+
 protected:
     void SetUp() override {
-        TransactionTest::SetUp();
-        mChild = mComposerClient->createSurface(String8("Child surface"), 0, 0,
-                                                PIXEL_FORMAT_RGBA_8888,
-                                                ISurfaceComposerClient::eFXSurfaceColor,
-                                                mFGSurfaceControl.get());
+        Base::SetUp();
+        Base::mChild =
+                Base::mComposerClient->createSurface(String8("Child surface"), 0, 0,
+                                                     PIXEL_FORMAT_RGBA_8888,
+                                                     ISurfaceComposerClient::eFXSurfaceEffect,
+                                                     Base::mFGSurfaceControl.get());
         {
-            TransactionScope ts(*sFakeComposer);
-            ts.setColor(mChild,
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.setColor(Base::mChild,
                         {LIGHT_GRAY.r / 255.0f, LIGHT_GRAY.g / 255.0f, LIGHT_GRAY.b / 255.0f});
-            ts.setCrop_legacy(mChild, Rect(0, 0, 10, 10));
+            ts.setCrop_legacy(Base::mChild, Rect(0, 0, 10, 10));
         }
 
-        sFakeComposer->runVSyncAndWait();
-        mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
-        mBaseFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.0f, 0.0f, 0.0f, 0.0f};
-        mBaseFrame[CHILD_LAYER].mSwapCount = 0;
-        ASSERT_EQ(2, sFakeComposer->getFrameCount());
-        ASSERT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+        Base::sFakeComposer->runVSyncAndWait();
+        Base::mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
+        Base::mBaseFrame[Base::CHILD_LAYER].mSourceCrop = hwc_frect_t{0.0f, 0.0f, 0.0f, 0.0f};
+        Base::mBaseFrame[Base::CHILD_LAYER].mSwapCount = 0;
+        ASSERT_EQ(2, Base::sFakeComposer->getFrameCount());
+        ASSERT_TRUE(framesAreSame(Base::mBaseFrame, Base::sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_LayerAlpha() {
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.show(Base::mChild);
+            ts.setPosition(Base::mChild, 0, 0);
+            ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+            ts.setAlpha(Base::mChild, 0.5);
+        }
+
+        auto referenceFrame = Base::mBaseFrame;
+        referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+        referenceFrame[Base::CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+        referenceFrame[Base::CHILD_LAYER].mPlaneAlpha = 0.5f;
+        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.setAlpha(Base::mFGSurfaceControl, 0.5);
+        }
+
+        auto referenceFrame2 = referenceFrame;
+        referenceFrame2[Base::FG_LAYER].mPlaneAlpha = 0.5f;
+        referenceFrame2[Base::CHILD_LAYER].mPlaneAlpha = 0.25f;
+        EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_LayerZeroAlpha() {
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.show(Base::mChild);
+            ts.setPosition(Base::mChild, 0, 0);
+            ts.setPosition(Base::mFGSurfaceControl, 0, 0);
+            ts.setAlpha(Base::mChild, 0.5);
+        }
+
+        auto referenceFrame = Base::mBaseFrame;
+        referenceFrame[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+        referenceFrame[Base::CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+        referenceFrame[Base::CHILD_LAYER].mPlaneAlpha = 0.5f;
+        EXPECT_TRUE(framesAreSame(referenceFrame, Base::sFakeComposer->getLatestFrame()));
+
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.setAlpha(Base::mFGSurfaceControl, 0.0f);
+        }
+
+        std::vector<RenderState> refFrame(1);
+        refFrame[Base::BG_LAYER] = Base::mBaseFrame[Base::BG_LAYER];
+
+        EXPECT_TRUE(framesAreSame(refFrame, Base::sFakeComposer->getLatestFrame()));
     }
 };
 
-TEST_F(ChildColorLayerTest, LayerAlpha) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.show(mChild);
-        ts.setPosition(mChild, 0, 0);
-        ts.setPosition(mFGSurfaceControl, 0, 0);
-        ts.setAlpha(mChild, 0.5);
-    }
+using ChildColorLayerTest_2_1 = ChildColorLayerTest<FakeComposerService_2_1>;
 
-    auto referenceFrame = mBaseFrame;
-    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
-    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
-    referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setAlpha(mFGSurfaceControl, 0.5);
-    }
-
-    auto referenceFrame2 = referenceFrame;
-    referenceFrame2[FG_LAYER].mPlaneAlpha = 0.5f;
-    referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f;
-    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+TEST_F(ChildColorLayerTest_2_1, DISABLED_LayerAlpha) {
+    Test_LayerAlpha();
 }
 
-TEST_F(ChildColorLayerTest, LayerZeroAlpha) {
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.show(mChild);
-        ts.setPosition(mChild, 0, 0);
-        ts.setPosition(mFGSurfaceControl, 0, 0);
-        ts.setAlpha(mChild, 0.5);
-    }
-
-    auto referenceFrame = mBaseFrame;
-    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
-    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
-    referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
-    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setAlpha(mFGSurfaceControl, 0.0f);
-    }
-
-    std::vector<RenderState> refFrame(1);
-    refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
-
-    EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+TEST_F(ChildColorLayerTest_2_1, DISABLED_LayerZeroAlpha) {
+    Test_LayerZeroAlpha();
 }
 
-class LatchingTest : public TransactionTest {
+template <typename FakeComposerService>
+class LatchingTest : public TransactionTest<FakeComposerService> {
+    using Base = TransactionTest<FakeComposerService>;
+
 protected:
-    void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, RED, false); }
+    void lockAndFillFGBuffer() { fillSurfaceRGBA8(Base::mFGSurfaceControl, RED, false); }
 
     void unlockFGBuffer() {
-        sp<Surface> s = mFGSurfaceControl->getSurface();
+        sp<Surface> s = Base::mFGSurfaceControl->getSurface();
         ASSERT_EQ(NO_ERROR, s->unlockAndPost());
-        sFakeComposer->runVSyncAndWait();
+        Base::sFakeComposer->runVSyncAndWait();
     }
 
     void completeFGResize() {
-        fillSurfaceRGBA8(mFGSurfaceControl, RED);
-        sFakeComposer->runVSyncAndWait();
+        fillSurfaceRGBA8(Base::mFGSurfaceControl, RED);
+        Base::sFakeComposer->runVSyncAndWait();
     }
     void restoreInitialState() {
-        TransactionScope ts(*sFakeComposer);
-        ts.setSize(mFGSurfaceControl, 64, 64);
-        ts.setPosition(mFGSurfaceControl, 64, 64);
-        ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
+        TransactionScope ts(*Base::sFakeComposer);
+        ts.setSize(Base::mFGSurfaceControl, 64, 64);
+        ts.setPosition(Base::mFGSurfaceControl, 64, 64);
+        ts.setCrop_legacy(Base::mFGSurfaceControl, Rect(0, 0, 64, 64));
+    }
+
+    void Test_SurfacePositionLatching() {
+        // By default position can be updated even while
+        // a resize is pending.
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.setSize(Base::mFGSurfaceControl, 32, 32);
+            ts.setPosition(Base::mFGSurfaceControl, 100, 100);
+        }
+
+        // The size should not have updated as we have not provided a new buffer.
+        auto referenceFrame1 = Base::mBaseFrame;
+        referenceFrame1[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 64, 100 + 64};
+        EXPECT_TRUE(framesAreSame(referenceFrame1, Base::sFakeComposer->getLatestFrame()));
+
+        restoreInitialState();
+
+        completeFGResize();
+
+        auto referenceFrame2 = Base::mBaseFrame;
+        referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 32, 100 + 32};
+        referenceFrame2[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f};
+        referenceFrame2[Base::FG_LAYER].mSwapCount++;
+        EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
+    }
+
+    void Test_CropLatching() {
+        // Normally the crop applies immediately even while a resize is pending.
+        {
+            TransactionScope ts(*Base::sFakeComposer);
+            ts.setSize(Base::mFGSurfaceControl, 128, 128);
+            ts.setCrop_legacy(Base::mFGSurfaceControl, Rect(0, 0, 63, 63));
+        }
+
+        auto referenceFrame1 = Base::mBaseFrame;
+        referenceFrame1[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
+        referenceFrame1[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
+        EXPECT_TRUE(framesAreSame(referenceFrame1, Base::sFakeComposer->getLatestFrame()));
+
+        restoreInitialState();
+
+        completeFGResize();
+
+        auto referenceFrame2 = Base::mBaseFrame;
+        referenceFrame2[Base::FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
+        referenceFrame2[Base::FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
+        referenceFrame2[Base::FG_LAYER].mSwapCount++;
+        EXPECT_TRUE(framesAreSame(referenceFrame2, Base::sFakeComposer->getLatestFrame()));
     }
 };
 
-TEST_F(LatchingTest, SurfacePositionLatching) {
-    // By default position can be updated even while
-    // a resize is pending.
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setSize(mFGSurfaceControl, 32, 32);
-        ts.setPosition(mFGSurfaceControl, 100, 100);
-    }
+using LatchingTest_2_1 = LatchingTest<FakeComposerService_2_1>;
 
-    // The size should not have updated as we have not provided a new buffer.
-    auto referenceFrame1 = mBaseFrame;
-    referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 64, 100 + 64};
-    EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
-
-    restoreInitialState();
-
-    // Now we repeat with setGeometryAppliesWithResize
-    // and verify the position DOESN'T latch.
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setGeometryAppliesWithResize(mFGSurfaceControl);
-        ts.setSize(mFGSurfaceControl, 32, 32);
-        ts.setPosition(mFGSurfaceControl, 100, 100);
-    }
-    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
-
-    completeFGResize();
-
-    auto referenceFrame2 = mBaseFrame;
-    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{100, 100, 100 + 32, 100 + 32};
-    referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 32.f, 32.f};
-    referenceFrame2[FG_LAYER].mSwapCount++;
-    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+TEST_F(LatchingTest_2_1, DISABLED_SurfacePositionLatching) {
+    Test_SurfacePositionLatching();
 }
 
-TEST_F(LatchingTest, CropLatching) {
-    // Normally the crop applies immediately even while a resize is pending.
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setSize(mFGSurfaceControl, 128, 128);
-        ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 63, 63));
-    }
-
-    auto referenceFrame1 = mBaseFrame;
-    referenceFrame1[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
-    referenceFrame1[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
-    EXPECT_TRUE(framesAreSame(referenceFrame1, sFakeComposer->getLatestFrame()));
-
-    restoreInitialState();
-
-    {
-        TransactionScope ts(*sFakeComposer);
-        ts.setSize(mFGSurfaceControl, 128, 128);
-        ts.setGeometryAppliesWithResize(mFGSurfaceControl);
-        ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 63, 63));
-    }
-    EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
-
-    completeFGResize();
-
-    auto referenceFrame2 = mBaseFrame;
-    referenceFrame2[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 63, 64 + 63};
-    referenceFrame2[FG_LAYER].mSourceCrop = hwc_frect_t{0.f, 0.f, 63.f, 63.f};
-    referenceFrame2[FG_LAYER].mSwapCount++;
-    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+TEST_F(LatchingTest_2_1, DISABLED_CropLatching) {
+    Test_CropLatching();
 }
 
 } // namespace
@@ -1387,8 +2009,11 @@
 int main(int argc, char** argv) {
     ::testing::InitGoogleTest(&argc, argv);
 
-    sftest::FakeHwcEnvironment* fakeEnvironment = new sftest::FakeHwcEnvironment;
+    auto* fakeEnvironment = new sftest::FakeHwcEnvironment;
     ::testing::AddGlobalTestEnvironment(fakeEnvironment);
     ::testing::InitGoogleMock(&argc, argv);
     return RUN_ALL_TESTS();
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/hwc2/Android.bp b/services/surfaceflinger/tests/hwc2/Android.bp
deleted file mode 100644
index 1c8e396..0000000
--- a/services/surfaceflinger/tests/hwc2/Android.bp
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (C) 2018 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.
-
-cc_test {
-    name: "test-hwc2",
-    defaults: ["surfaceflinger_defaults"],
-    cflags: [
-        "-DEGL_EGLEXT_PROTOTYPES",
-        "-DGL_GLEXT_PROTOTYPES",
-        "-fno-builtin",
-        "-fstack-protector-all",
-        "-g",
-        "-Wextra",
-    ],
-    srcs: [
-        "Hwc2Test.cpp",
-        "Hwc2TestProperties.cpp",
-        "Hwc2TestLayer.cpp",
-        "Hwc2TestLayers.cpp",
-        "Hwc2TestBuffer.cpp",
-        "Hwc2TestClientTarget.cpp",
-        "Hwc2TestVirtualDisplay.cpp",
-        "Hwc2TestPixelComparator.cpp",
-    ],
-    static_libs: [
-        "libadf",
-        "libadfhwc",
-        "libbase",
-        "libmath",
-    ],
-    shared_libs: [
-        "android.hardware.graphics.common@1.1",
-        "libcutils",
-        "libEGL",
-        "libGLESv2",
-        "libgui",
-        "libhardware",
-        "libhwui",
-        "liblog",
-        "libsync",
-        "libui",
-        "libutils",
-    ],
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp b/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
deleted file mode 100644
index 13774b4..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2Test.cpp
+++ /dev/null
@@ -1,4772 +0,0 @@
-/*
- * Copyright (C) 2016 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 <array>
-#include <unordered_set>
-#include <unordered_map>
-#include <gtest/gtest.h>
-#include <dlfcn.h>
-#include <android-base/unique_fd.h>
-#include <hardware/hardware.h>
-#include <sync/sync.h>
-#include <ui/GraphicTypes.h>
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-#include "Hwc2TestLayer.h"
-#include "Hwc2TestLayers.h"
-#include "Hwc2TestClientTarget.h"
-#include "Hwc2TestVirtualDisplay.h"
-
-using android::ui::ColorMode;
-using android::ui::Dataspace;
-
-void hwc2TestHotplugCallback(hwc2_callback_data_t callbackData,
-        hwc2_display_t display, int32_t connected);
-void hwc2TestVsyncCallback(hwc2_callback_data_t callbackData,
-        hwc2_display_t display, int64_t timestamp);
-
-class Hwc2Test : public testing::Test {
-public:
-
-    virtual void SetUp()
-    {
-        hw_module_t const* hwc2Module;
-
-        int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &hwc2Module);
-        ASSERT_GE(err, 0) << "failed to get hwc hardware module: "
-                << strerror(-err);
-
-        /* The following method will fail if you have not run
-         * "adb shell stop" */
-        err = hwc2_open(hwc2Module, &mHwc2Device);
-        ASSERT_GE(err, 0) << "failed to open hwc hardware module: "
-                << strerror(-err);
-
-        populateDisplays();
-    }
-
-    virtual void TearDown()
-    {
-
-        for (auto itr = mLayers.begin(); itr != mLayers.end();) {
-            hwc2_display_t display = itr->first;
-            hwc2_layer_t layer = itr->second;
-            itr++;
-            /* Destroys and removes the layer from mLayers */
-            destroyLayer(display, layer);
-        }
-
-        for (auto itr = mActiveDisplays.begin(); itr != mActiveDisplays.end();) {
-            hwc2_display_t display = *itr;
-            itr++;
-            /* Sets power mode to off and removes the display from
-             * mActiveDisplays */
-            setPowerMode(display, HWC2_POWER_MODE_OFF);
-        }
-
-        for (auto itr = mVirtualDisplays.begin(); itr != mVirtualDisplays.end();) {
-            hwc2_display_t display = *itr;
-            itr++;
-            /* Destroys virtual displays */
-            destroyVirtualDisplay(display);
-        }
-
-        if (mHwc2Device)
-            hwc2_close(mHwc2Device);
-    }
-
-    void registerCallback(hwc2_callback_descriptor_t descriptor,
-            hwc2_callback_data_t callbackData, hwc2_function_pointer_t pointer,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_REGISTER_CALLBACK>(
-                getFunction(HWC2_FUNCTION_REGISTER_CALLBACK));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, descriptor,
-                callbackData, pointer));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to register callback";
-        }
-    }
-
-    void getDisplayType(hwc2_display_t display, hwc2_display_type_t* outType,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_TYPE>(
-                getFunction(HWC2_FUNCTION_GET_DISPLAY_TYPE));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                    reinterpret_cast<int32_t*>(outType)));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display type";
-        }
-    }
-
-    /* If the populateDisplays function is still receiving displays and the
-     * display is connected, the display handle is stored in mDisplays. */
-    void hotplugCallback(hwc2_display_t display, int32_t connected)
-    {
-        std::lock_guard<std::mutex> lock(mHotplugMutex);
-
-        if (mHotplugStatus != Hwc2TestHotplugStatus::Receiving)
-            return;
-
-        if (connected == HWC2_CONNECTION_CONNECTED)
-            mDisplays.insert(display);
-
-        mHotplugCv.notify_all();
-    }
-
-    void createLayer(hwc2_display_t display, hwc2_layer_t* outLayer,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_CREATE_LAYER>(
-                getFunction(HWC2_FUNCTION_CREATE_LAYER));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                outLayer));
-
-        if (err == HWC2_ERROR_NONE)
-            mLayers.insert(std::make_pair(display, *outLayer));
-
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to create layer";
-        }
-    }
-
-    void destroyLayer(hwc2_display_t display, hwc2_layer_t layer,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_DESTROY_LAYER>(
-                getFunction(HWC2_FUNCTION_DESTROY_LAYER));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer));
-
-        if (err == HWC2_ERROR_NONE)
-            mLayers.erase(std::make_pair(display, layer));
-
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to destroy layer "
-                    << layer;
-        }
-    }
-
-    void getDisplayAttribute(hwc2_display_t display, hwc2_config_t config,
-            hwc2_attribute_t attribute, int32_t* outValue,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_ATTRIBUTE>(
-                getFunction(HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, config,
-                attribute, outValue));
-
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display attribute "
-                    << getAttributeName(attribute) << " for config " << config;
-        }
-    }
-
-    void getDisplayConfigs(hwc2_display_t display,
-            std::vector<hwc2_config_t>* outConfigs,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_CONFIGS>(
-                getFunction(HWC2_FUNCTION_GET_DISPLAY_CONFIGS));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        uint32_t numConfigs = 0;
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                &numConfigs, nullptr));
-
-        if (err == HWC2_ERROR_NONE) {
-            outConfigs->resize(numConfigs);
-
-            err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                    &numConfigs, outConfigs->data()));
-        }
-
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get configs for"
-                    " display " << display;
-        }
-    }
-
-    void getActiveConfig(hwc2_display_t display, hwc2_config_t* outConfig,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_GET_ACTIVE_CONFIG>(
-                getFunction(HWC2_FUNCTION_GET_ACTIVE_CONFIG));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                outConfig));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get active config on"
-                    " display " << display;
-        }
-    }
-
-    void setActiveConfig(hwc2_display_t display, hwc2_config_t config,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_ACTIVE_CONFIG>(
-                getFunction(HWC2_FUNCTION_SET_ACTIVE_CONFIG));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, config));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set active config "
-                    << config;
-        }
-    }
-
-    void getDozeSupport(hwc2_display_t display, int32_t* outSupport,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_GET_DOZE_SUPPORT>(
-                getFunction(HWC2_FUNCTION_GET_DOZE_SUPPORT));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                outSupport));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get doze support on"
-                    " display " << display;
-        }
-    }
-
-    void setPowerMode(hwc2_display_t display, hwc2_power_mode_t mode,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_POWER_MODE>(
-                getFunction(HWC2_FUNCTION_SET_POWER_MODE));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                mode));
-        if (outErr) {
-            *outErr = err;
-            if (err != HWC2_ERROR_NONE)
-                return;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set power mode "
-                    << getPowerModeName(mode) << " on display " << display;
-        }
-
-        if (mode == HWC2_POWER_MODE_OFF) {
-            mActiveDisplays.erase(display);
-        } else {
-            mActiveDisplays.insert(display);
-        }
-    }
-
-    void setVsyncEnabled(hwc2_display_t display, hwc2_vsync_t enabled,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_VSYNC_ENABLED>(
-                getFunction(HWC2_FUNCTION_SET_VSYNC_ENABLED));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                enabled));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set vsync enabled "
-                    << getVsyncName(enabled);
-        }
-    }
-
-    void vsyncCallback(hwc2_display_t display, int64_t timestamp)
-    {
-        std::lock_guard<std::mutex> lock(mVsyncMutex);
-        mVsyncDisplay = display;
-        mVsyncTimestamp = timestamp;
-        mVsyncCv.notify_all();
-    }
-
-    void getDisplayName(hwc2_display_t display, std::string* outName,
-                hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_NAME>(
-                getFunction(HWC2_FUNCTION_GET_DISPLAY_NAME));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        uint32_t size = 0;
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, &size,
-                nullptr));
-
-        if (err == HWC2_ERROR_NONE) {
-            std::vector<char> name(size);
-
-            err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, &size,
-                    name.data()));
-
-            outName->assign(name.data());
-        }
-
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display name for "
-                    << display;
-        }
-    }
-
-    void setLayerCompositionType(hwc2_display_t display, hwc2_layer_t layer,
-            hwc2_composition_t composition, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_COMPOSITION_TYPE>(
-                getFunction(HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
-                composition));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer composition"
-                    " type " << getCompositionName(composition);
-        }
-    }
-
-    void setCursorPosition(hwc2_display_t display, hwc2_layer_t layer,
-            int32_t x, int32_t y, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_CURSOR_POSITION>(
-                getFunction(HWC2_FUNCTION_SET_CURSOR_POSITION));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer, x,
-                y));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_TRUE((err == HWC2_ERROR_NONE) ||
-                (err == HWC2_ERROR_BAD_LAYER)) <<
-                "failed to set cursor position";
-        }
-    }
-
-    void setLayerBlendMode(hwc2_display_t display, hwc2_layer_t layer,
-            hwc2_blend_mode_t mode, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_BLEND_MODE>(
-                getFunction(HWC2_FUNCTION_SET_LAYER_BLEND_MODE));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
-                mode));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer blend mode "
-                    << getBlendModeName(mode);
-        }
-    }
-
-    void setLayerBuffer(hwc2_display_t display, hwc2_layer_t layer,
-            buffer_handle_t buffer, int32_t acquireFence,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_BUFFER>(
-                getFunction(HWC2_FUNCTION_SET_LAYER_BUFFER));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
-                buffer, acquireFence));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer buffer";
-        }
-    }
-
-    void setLayerColor(hwc2_display_t display, hwc2_layer_t layer,
-            hwc_color_t color, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_COLOR>(
-                getFunction(HWC2_FUNCTION_SET_LAYER_COLOR));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
-                color));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer color";
-        }
-    }
-
-    void setLayerDataspace(hwc2_display_t display, hwc2_layer_t layer,
-            Dataspace dataspace, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_DATASPACE>(
-                getFunction(HWC2_FUNCTION_SET_LAYER_DATASPACE));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                layer, static_cast<int>(dataspace)));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer dataspace";
-        }
-    }
-
-    void setLayerDisplayFrame(hwc2_display_t display, hwc2_layer_t layer,
-            const hwc_rect_t& displayFrame, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_DISPLAY_FRAME>(
-                getFunction(HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
-                displayFrame));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer display"
-                    " frame";
-        }
-    }
-
-    void setLayerPlaneAlpha(hwc2_display_t display, hwc2_layer_t layer,
-            float alpha, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_PLANE_ALPHA>(
-                getFunction(HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
-                alpha));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer plane alpha "
-                    << alpha;
-        }
-    }
-
-    void setLayerSourceCrop(hwc2_display_t display, hwc2_layer_t layer,
-            const hwc_frect_t& sourceCrop, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_SOURCE_CROP>(
-                getFunction(HWC2_FUNCTION_SET_LAYER_SOURCE_CROP));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
-                sourceCrop));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer source crop";
-        }
-    }
-
-    void setLayerSurfaceDamage(hwc2_display_t display, hwc2_layer_t layer,
-            const hwc_region_t& surfaceDamage, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_SURFACE_DAMAGE>(
-                getFunction(HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
-                surfaceDamage));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer surface"
-                    " damage";
-        }
-    }
-
-    void setLayerTransform(hwc2_display_t display, hwc2_layer_t layer,
-            hwc_transform_t transform, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_TRANSFORM>(
-                getFunction(HWC2_FUNCTION_SET_LAYER_TRANSFORM));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
-                transform));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer transform "
-                    << getTransformName(transform);
-        }
-    }
-
-    void setLayerVisibleRegion(hwc2_display_t display, hwc2_layer_t layer,
-            const hwc_region_t& visibleRegion, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_VISIBLE_REGION>(
-                getFunction(HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
-                visibleRegion));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer visible"
-                    " region";
-        }
-    }
-
-    void setLayerZOrder(hwc2_display_t display, hwc2_layer_t layer,
-            uint32_t zOrder, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_LAYER_Z_ORDER>(
-                getFunction(HWC2_FUNCTION_SET_LAYER_Z_ORDER));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, layer,
-                zOrder));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set layer z order "
-                    << zOrder;
-        }
-    }
-
-    void validateDisplay(hwc2_display_t display, uint32_t* outNumTypes,
-            uint32_t* outNumRequests, hwc2_error_t* outErr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_VALIDATE_DISPLAY>(
-                getFunction(HWC2_FUNCTION_VALIDATE_DISPLAY));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        *outErr = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                outNumTypes, outNumRequests));
-    }
-
-    void validateDisplay(hwc2_display_t display, uint32_t* outNumTypes,
-            uint32_t* outNumRequests, bool* outHasChanges)
-    {
-        hwc2_error_t err = HWC2_ERROR_NONE;
-
-        EXPECT_NO_FATAL_FAILURE(validateDisplay(display, outNumTypes,
-                outNumRequests, &err));
-
-        if (err != HWC2_ERROR_HAS_CHANGES) {
-            *outHasChanges = false;
-            EXPECT_EQ(err, HWC2_ERROR_NONE) << "failed to validate display";
-        } else {
-            *outHasChanges = true;
-        }
-    }
-
-    void getDisplayRequests(hwc2_display_t display,
-            hwc2_display_request_t* outDisplayRequests,
-            std::vector<hwc2_layer_t>* outLayers,
-            std::vector<hwc2_layer_request_t>* outLayerRequests,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_GET_DISPLAY_REQUESTS>(
-                getFunction(HWC2_FUNCTION_GET_DISPLAY_REQUESTS));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        uint32_t numElements = 0;
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                reinterpret_cast<int32_t*>(outDisplayRequests), &numElements,
-                nullptr, nullptr));
-
-        if (err == HWC2_ERROR_NONE && numElements > 0) {
-            outLayers->resize(numElements);
-            outLayerRequests->resize(numElements);
-
-            err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                    reinterpret_cast<int32_t*>(outDisplayRequests), &numElements,
-                    reinterpret_cast<uint64_t*>(outLayers->data()),
-                    reinterpret_cast<int32_t*>(outLayerRequests->data())));
-        }
-
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get display requests";
-        }
-    }
-
-    void handleRequests(hwc2_display_t display,
-            const std::vector<hwc2_layer_t>& layers, uint32_t numRequests,
-            std::set<hwc2_layer_t>* outClearLayers = nullptr,
-            bool* outFlipClientTarget = nullptr)
-    {
-        hwc2_display_request_t displayRequest =
-                static_cast<hwc2_display_request_t>(0);
-        std::vector<hwc2_layer_t> requestedLayers;
-        std::vector<hwc2_layer_request_t> requests;
-
-        ASSERT_NO_FATAL_FAILURE(getDisplayRequests(display, &displayRequest,
-                &requestedLayers, &requests));
-
-        EXPECT_EQ(numRequests, requests.size()) << "validate returned "
-                << numRequests << " requests and get display requests returned "
-                << requests.size() << " requests";
-
-        for (size_t i = 0; i < requests.size(); i++) {
-            hwc2_layer_t requestedLayer = requestedLayers.at(i);
-            hwc2_layer_request_t request = requests.at(i);
-
-            EXPECT_EQ(std::count(layers.begin(), layers.end(), requestedLayer),
-                    1) << "get display requests returned an unknown layer";
-            EXPECT_NE(request, 0) << "returned empty request for layer "
-                    << requestedLayer;
-
-            if (outClearLayers && request
-                    == HWC2_LAYER_REQUEST_CLEAR_CLIENT_TARGET)
-                outClearLayers->insert(requestedLayer);
-        }
-
-        if (outFlipClientTarget)
-            *outFlipClientTarget = displayRequest
-                    & HWC2_DISPLAY_REQUEST_FLIP_CLIENT_TARGET;
-    }
-
-    void getChangedCompositionTypes(hwc2_display_t display,
-            std::vector<hwc2_layer_t>* outLayers,
-            std::vector<hwc2_composition_t>* outTypes,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_GET_CHANGED_COMPOSITION_TYPES>(
-                getFunction(HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        uint32_t numElements = 0;
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                &numElements, nullptr, nullptr));
-
-        if (err == HWC2_ERROR_NONE && numElements > 0) {
-            outLayers->resize(numElements);
-            outTypes->resize(numElements);
-
-            err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                    &numElements, reinterpret_cast<uint64_t*>(outLayers->data()),
-                    reinterpret_cast<int32_t*>(outTypes->data())));
-        }
-
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get changed"
-                    " composition types";
-        }
-    }
-
-    void handleCompositionChanges(hwc2_display_t display,
-            const Hwc2TestLayers& testLayers,
-            const std::vector<hwc2_layer_t>& layers, uint32_t numTypes,
-            std::set<hwc2_layer_t>* outClientLayers = nullptr)
-    {
-        std::vector<hwc2_layer_t> changedLayers;
-        std::vector<hwc2_composition_t> types;
-
-        ASSERT_NO_FATAL_FAILURE(getChangedCompositionTypes(display,
-                &changedLayers, &types));
-
-        EXPECT_EQ(numTypes, types.size()) << "validate returned "
-                << numTypes << " types and get changed composition types"
-                " returned " << types.size() << " types";
-
-        for (size_t i = 0; i < types.size(); i++) {
-
-            auto layer = std::find(layers.begin(), layers.end(),
-                    changedLayers.at(i));
-
-            EXPECT_TRUE(layer != layers.end() || !testLayers.contains(*layer))
-                    << "get changed composition types returned an unknown layer";
-
-            hwc2_composition_t requestedType = testLayers.getComposition(*layer);
-            hwc2_composition_t returnedType = types.at(i);
-
-            EXPECT_NE(returnedType, HWC2_COMPOSITION_INVALID) << "get changed"
-                    " composition types returned invalid composition";
-
-            switch (requestedType) {
-            case HWC2_COMPOSITION_CLIENT:
-                EXPECT_TRUE(false) << getCompositionName(returnedType)
-                        << " cannot be changed";
-                break;
-            case HWC2_COMPOSITION_DEVICE:
-            case HWC2_COMPOSITION_SOLID_COLOR:
-                EXPECT_EQ(returnedType, HWC2_COMPOSITION_CLIENT)
-                        << "composition of type "
-                        << getCompositionName(requestedType)
-                        << " can only be changed to "
-                        << getCompositionName(HWC2_COMPOSITION_CLIENT);
-                break;
-            case HWC2_COMPOSITION_CURSOR:
-            case HWC2_COMPOSITION_SIDEBAND:
-                EXPECT_TRUE(returnedType == HWC2_COMPOSITION_CLIENT
-                        || returnedType == HWC2_COMPOSITION_DEVICE)
-                        << "composition of type "
-                        << getCompositionName(requestedType)
-                        << " can only be changed to "
-                        << getCompositionName(HWC2_COMPOSITION_CLIENT) << " or "
-                        << getCompositionName(HWC2_COMPOSITION_DEVICE);
-                break;
-            default:
-                EXPECT_TRUE(false) << "unknown type "
-                        << getCompositionName(requestedType);
-                break;
-            }
-
-            if (outClientLayers)
-                if (returnedType == HWC2_COMPOSITION_CLIENT)
-                    outClientLayers->insert(*layer);
-        }
-
-        if (outClientLayers) {
-            for (auto layer : layers) {
-                if (testLayers.getComposition(layer) == HWC2_COMPOSITION_CLIENT)
-                    outClientLayers->insert(layer);
-            }
-        }
-    }
-
-    void acceptDisplayChanges(hwc2_display_t display,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_ACCEPT_DISPLAY_CHANGES>(
-                getFunction(HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to accept display changes";
-        }
-    }
-
-    void getClientTargetSupport(hwc2_display_t display, int32_t width,
-            int32_t height, android_pixel_format_t format,
-            Dataspace dataspace, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_GET_CLIENT_TARGET_SUPPORT>(
-                getFunction(HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, width,
-                height, format, static_cast<int>(dataspace)));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get client target"
-                    " support";
-        }
-    }
-
-    void setClientTarget(hwc2_display_t display, buffer_handle_t handle,
-            int32_t acquireFence, Dataspace dataspace,
-            hwc_region_t damage, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_CLIENT_TARGET>(
-                getFunction(HWC2_FUNCTION_SET_CLIENT_TARGET));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, handle,
-                acquireFence, static_cast<int>(dataspace), damage));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set client target";
-        }
-    }
-
-    void presentDisplay(hwc2_display_t display, int32_t* outPresentFence,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_PRESENT_DISPLAY>(
-                getFunction(HWC2_FUNCTION_PRESENT_DISPLAY));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                outPresentFence));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to present display";
-        }
-    }
-
-    void getReleaseFences(hwc2_display_t display,
-            std::vector<hwc2_layer_t>* outLayers,
-            std::vector<int32_t>* outFences, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_GET_RELEASE_FENCES>(
-                getFunction(HWC2_FUNCTION_GET_RELEASE_FENCES));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        uint32_t numElements = 0;
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                &numElements, nullptr, nullptr));
-
-        if (err == HWC2_ERROR_NONE) {
-            outLayers->resize(numElements);
-            outFences->resize(numElements);
-
-            err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                    &numElements, outLayers->data(), outFences->data()));
-        }
-
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get release fences";
-        }
-    }
-
-    void getColorModes(hwc2_display_t display,
-            std::vector<ColorMode>* outColorModes,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_GET_COLOR_MODES>(
-                getFunction(HWC2_FUNCTION_GET_COLOR_MODES));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        uint32_t numColorModes = 0;
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                &numColorModes, nullptr));
-        if (err == HWC2_ERROR_NONE) {
-            outColorModes->resize(numColorModes);
-
-            err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                    &numColorModes,
-                    reinterpret_cast<int32_t*>(outColorModes->data())));
-        }
-
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get color modes for"
-                    " display " << display;
-        }
-    }
-
-    void setColorMode(hwc2_display_t display, ColorMode colorMode,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_COLOR_MODE>(
-                getFunction(HWC2_FUNCTION_SET_COLOR_MODE));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                static_cast<int32_t>(colorMode)));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set color mode "
-                    << static_cast<int>(colorMode);
-        }
-    }
-
-    void getHdrCapabilities(hwc2_display_t display,
-            std::vector<android_hdr_t>* outTypes, float* outMaxLuminance,
-            float* outMaxAverageLuminance, float* outMinLuminance,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_GET_HDR_CAPABILITIES>(
-                getFunction(HWC2_FUNCTION_GET_HDR_CAPABILITIES));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        uint32_t numTypes = 0;
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                &numTypes, nullptr, outMaxLuminance, outMaxAverageLuminance,
-                outMinLuminance));
-
-        if (err == HWC2_ERROR_NONE) {
-            outTypes->resize(numTypes);
-
-            err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, &numTypes,
-                    reinterpret_cast<int32_t*>(outTypes->data()), outMaxLuminance,
-                    outMaxAverageLuminance, outMinLuminance));
-        }
-
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to get hdr capabilities"
-                    " for display " << display;
-        }
-    }
-
-    void setColorTransform(hwc2_display_t display,
-            const std::array<float, 16>& matrix, android_color_transform_t hint,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_COLOR_TRANSFORM>(
-                getFunction(HWC2_FUNCTION_SET_COLOR_TRANSFORM));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display,
-                matrix.data(), hint));
-
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set color transform "
-                    << hint;
-        }
-    }
-
-    void createVirtualDisplay(uint32_t width, uint32_t height,
-            android_pixel_format_t* outFormat, hwc2_display_t* outDisplay,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_CREATE_VIRTUAL_DISPLAY>(
-                getFunction(HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, width, height,
-                reinterpret_cast<int32_t*>(outFormat), outDisplay));
-
-        if (err == HWC2_ERROR_NONE)
-            mVirtualDisplays.insert(*outDisplay);
-
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to create virtual display";
-        }
-    }
-
-    void destroyVirtualDisplay(hwc2_display_t display,
-            hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_DESTROY_VIRTUAL_DISPLAY>(
-                getFunction(HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display));
-
-        if (err == HWC2_ERROR_NONE)
-            mVirtualDisplays.erase(display);
-
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to destroy virtual display";
-        }
-    }
-
-    void getMaxVirtualDisplayCount(uint32_t* outMaxCnt)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_GET_MAX_VIRTUAL_DISPLAY_COUNT>(
-                getFunction(HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        *outMaxCnt = pfn(mHwc2Device);
-    }
-
-    void setOutputBuffer(hwc2_display_t display, buffer_handle_t buffer,
-            int32_t releaseFence, hwc2_error_t* outErr = nullptr)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_SET_OUTPUT_BUFFER>(
-                getFunction(HWC2_FUNCTION_SET_OUTPUT_BUFFER));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        auto err = static_cast<hwc2_error_t>(pfn(mHwc2Device, display, buffer,
-                releaseFence));
-        if (outErr) {
-            *outErr = err;
-        } else {
-            ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to set output buffer";
-        }
-    }
-
-    void dump(std::string* outBuffer)
-    {
-        auto pfn = reinterpret_cast<HWC2_PFN_DUMP>(
-                getFunction(HWC2_FUNCTION_DUMP));
-        ASSERT_TRUE(pfn) << "failed to get function";
-
-        uint32_t size = 0;
-
-        pfn(mHwc2Device, &size, nullptr);
-
-        std::vector<char> buffer(size);
-
-        pfn(mHwc2Device, &size, buffer.data());
-
-        outBuffer->assign(buffer.data());
-    }
-
-    void getBadDisplay(hwc2_display_t* outDisplay)
-    {
-        for (hwc2_display_t display = 0; display < UINT64_MAX; display++) {
-            if (mDisplays.count(display) == 0) {
-                *outDisplay = display;
-                return;
-            }
-        }
-        ASSERT_TRUE(false) << "Unable to find bad display. UINT64_MAX displays"
-                " are registered. This should never happen.";
-    }
-
-    void waitForVsync(hwc2_display_t* outDisplay = nullptr,
-            int64_t* outTimestamp = nullptr)
-    {
-        std::unique_lock<std::mutex> lock(mVsyncMutex);
-        ASSERT_EQ(mVsyncCv.wait_for(lock, std::chrono::seconds(3)),
-                std::cv_status::no_timeout) << "timed out attempting to get"
-                " vsync callback";
-        if (outDisplay)
-            *outDisplay = mVsyncDisplay;
-        if (outTimestamp)
-            *outTimestamp = mVsyncTimestamp;
-    }
-
-    void enableVsync(hwc2_display_t display)
-    {
-        ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, this,
-                reinterpret_cast<hwc2_function_pointer_t>(
-                hwc2TestVsyncCallback)));
-        ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
-    }
-
-    void disableVsync(hwc2_display_t display)
-    {
-        ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
-    }
-
-protected:
-    hwc2_function_pointer_t getFunction(hwc2_function_descriptor_t descriptor)
-    {
-        return mHwc2Device->getFunction(mHwc2Device, descriptor);
-    }
-
-    void getCapabilities(std::vector<hwc2_capability_t>* outCapabilities)
-    {
-        uint32_t num = 0;
-
-        mHwc2Device->getCapabilities(mHwc2Device, &num, nullptr);
-
-        outCapabilities->resize(num);
-
-        mHwc2Device->getCapabilities(mHwc2Device, &num,
-                reinterpret_cast<int32_t*>(outCapabilities->data()));
-    }
-
-    /* Registers a hotplug callback and waits for hotplug callbacks. This
-     * function will have no effect if called more than once. */
-    void populateDisplays()
-    {
-        /* Sets the hotplug status to receiving */
-        {
-            std::lock_guard<std::mutex> lock(mHotplugMutex);
-
-            if (mHotplugStatus != Hwc2TestHotplugStatus::Init)
-                return;
-            mHotplugStatus = Hwc2TestHotplugStatus::Receiving;
-        }
-
-        /* Registers the callback. This function call cannot be locked because
-         * a callback could happen on the same thread */
-        ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_HOTPLUG, this,
-                reinterpret_cast<hwc2_function_pointer_t>(
-                hwc2TestHotplugCallback)));
-
-        /* Waits for hotplug events. If a hotplug event has not come within 1
-         * second, stop waiting. */
-        std::unique_lock<std::mutex> lock(mHotplugMutex);
-
-        while (mHotplugCv.wait_for(lock, std::chrono::seconds(1)) !=
-                std::cv_status::timeout) { }
-
-        /* Sets the hotplug status to done. Future calls will have no effect */
-        mHotplugStatus = Hwc2TestHotplugStatus::Done;
-    }
-
-    /* NOTE: will create min(newlayerCnt, max supported layers) layers */
-    void createLayers(hwc2_display_t display,
-            std::vector<hwc2_layer_t>* outLayers, size_t newLayerCnt)
-    {
-        std::vector<hwc2_layer_t> newLayers;
-        hwc2_layer_t layer;
-        hwc2_error_t err = HWC2_ERROR_NONE;
-
-        for (size_t i = 0; i < newLayerCnt; i++) {
-
-            EXPECT_NO_FATAL_FAILURE(createLayer(display, &layer, &err));
-            if (err == HWC2_ERROR_NO_RESOURCES)
-                break;
-            if (err != HWC2_ERROR_NONE) {
-                newLayers.clear();
-                ASSERT_EQ(err, HWC2_ERROR_NONE) << "failed to create layer";
-            }
-            newLayers.push_back(layer);
-        }
-
-        *outLayers = std::move(newLayers);
-    }
-
-    void destroyLayers(hwc2_display_t display,
-            std::vector<hwc2_layer_t>&& layers)
-    {
-        for (hwc2_layer_t layer : layers) {
-            EXPECT_NO_FATAL_FAILURE(destroyLayer(display, layer));
-        }
-    }
-
-    void getInvalidConfig(hwc2_display_t display, hwc2_config_t* outConfig)
-    {
-        std::vector<hwc2_config_t> configs;
-
-        ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-        hwc2_config_t CONFIG_MAX = UINT32_MAX;
-
-        ASSERT_LE(configs.size() - 1, CONFIG_MAX) << "every config value"
-                " (2^32 values) has been taken which shouldn't happen";
-
-        hwc2_config_t config;
-        for (config = 0; config < CONFIG_MAX; config++) {
-            if (std::count(configs.begin(), configs.end(), config) == 0)
-                break;
-        }
-
-        *outConfig = config;
-    }
-
-    /* Calls a set property function from Hwc2Test to set a property value from
-     * Hwc2TestLayer to hwc2_layer_t on hwc2_display_t */
-    using TestLayerPropertyFunction = void (*)(Hwc2Test* test,
-            hwc2_display_t display, hwc2_layer_t layer,
-            Hwc2TestLayer* testLayer, hwc2_error_t* outErr);
-
-    /* Calls a set property function from Hwc2Test to set property values from
-     * Hwc2TestLayers to hwc2_layer_t on hwc2_display_t */
-    using TestLayerPropertiesFunction = void (*)(Hwc2Test* test,
-            hwc2_display_t display, hwc2_layer_t layer,
-            Hwc2TestLayers* testLayers);
-
-    /* Calls a set property function from Hwc2Test to set a bad property value
-     * on hwc2_layer_t on hwc2_display_t */
-    using TestLayerPropertyBadLayerFunction = void (*)(Hwc2Test* test,
-            hwc2_display_t display, hwc2_layer_t layer,
-            Hwc2TestLayer* testLayer, hwc2_error_t* outErr);
-
-    /* Calls a set property function from Hwc2Test to set a bad property value
-     * on hwc2_layer_t on hwc2_display_t */
-    using TestLayerPropertyBadParameterFunction = void (*)(Hwc2Test* test,
-            hwc2_display_t display, hwc2_layer_t layer, hwc2_error_t* outErr);
-
-    /* Is called after a display is powered on and all layer properties have
-     * been set. It should be used to test functions such as validate, accepting
-     * changes, present, etc. */
-    using TestDisplayLayersFunction = void (*)(Hwc2Test* test,
-            hwc2_display_t display, const std::vector<hwc2_layer_t>& layers,
-            Hwc2TestLayers* testLayers);
-
-    /* It is called on an non validated display */
-    using TestDisplayNonValidatedLayersFunction = void (*)(Hwc2Test* test,
-            hwc2_display_t display, std::vector<hwc2_layer_t>* layers);
-
-    /* Tests client target support on a particular display and config */
-    using TestClientTargetSupportFunction = void (*)(Hwc2Test* test,
-            hwc2_display_t display,
-            const Hwc2TestClientTargetSupport& testClientTargetSupport);
-
-    /* Tests a particular active display config */
-    using TestActiveDisplayConfigFunction = void (*)(Hwc2Test* test,
-            hwc2_display_t display);
-
-    /* Tests a newly created virtual display */
-    using TestCreateVirtualDisplayFunction = void (*)(Hwc2Test* test,
-            hwc2_display_t display, Hwc2TestVirtualDisplay* testVirtualDisplay);
-
-    /* Advances a property of Hwc2TestLayer */
-    using AdvanceProperty = bool (*)(Hwc2TestLayer* testLayer);
-
-    /* Advances properties of Hwc2TestLayers */
-    using AdvanceProperties = bool (*)(Hwc2TestLayers* testLayer);
-
-    /* Advances properties of Hwc2TestClientTargetSupport */
-    using AdvanceClientTargetSupport = bool (*)(
-            Hwc2TestClientTargetSupport* testClientTargetSupport);
-
-    /* For each active display it cycles through each display config and tests
-     * each property value. It creates a layer, sets the property and then
-     * destroys the layer */
-    void setLayerProperty(Hwc2TestCoverage coverage,
-            TestLayerPropertyFunction function, AdvanceProperty advance)
-    {
-        for (auto display : mDisplays) {
-            std::vector<hwc2_config_t> configs;
-
-            ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-            for (auto config : configs) {
-                hwc2_layer_t layer;
-                Area displayArea;
-
-                ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-                ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
-                        &displayArea));
-                Hwc2TestLayer testLayer(coverage, displayArea);
-
-                do {
-                    ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
-                    ASSERT_NO_FATAL_FAILURE(function(this, display, layer,
-                            &testLayer, nullptr));
-
-                    ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
-                } while (advance(&testLayer));
-            }
-        }
-    }
-
-    /* For each active display it cycles through each display config and tests
-     * each property value. It creates a layer, cycles through each property
-     * value and updates the layer property value and then destroys the layer */
-    void setLayerPropertyUpdate(Hwc2TestCoverage coverage,
-            TestLayerPropertyFunction function, AdvanceProperty advance)
-    {
-        for (auto display : mDisplays) {
-            std::vector<hwc2_config_t> configs;
-
-            ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-            for (auto config : configs) {
-                hwc2_layer_t layer;
-                Area displayArea;
-
-                ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-                ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
-                        &displayArea));
-                Hwc2TestLayer testLayer(coverage, displayArea);
-
-                ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
-                do {
-                    ASSERT_NO_FATAL_FAILURE(function(this, display, layer,
-                            &testLayer, nullptr));
-                } while (advance(&testLayer));
-
-                ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
-            }
-        }
-    }
-
-    /* For each active display it cycles through each display config and tests
-     * each property value. It creates multiple layers, calls the
-     * TestLayerPropertiesFunction to set property values and then
-     * destroys the layers */
-    void setLayerProperties(Hwc2TestCoverage coverage, size_t layerCnt,
-            TestLayerPropertiesFunction function, AdvanceProperties advance)
-    {
-        for (auto display : mDisplays) {
-            std::vector<hwc2_config_t> configs;
-
-            ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-            for (auto config : configs) {
-                std::vector<hwc2_layer_t> layers;
-                Area displayArea;
-
-                ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-                ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
-                        &displayArea));
-
-                ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
-                Hwc2TestLayers testLayers(layers, coverage, displayArea);
-
-                do {
-                    for (auto layer : layers) {
-                        EXPECT_NO_FATAL_FAILURE(function(this, display, layer,
-                                &testLayers));
-                    }
-                } while (advance(&testLayers));
-
-                ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers)));
-            }
-        }
-    }
-
-    /* For each active display it cycles through each display config.
-     * 1) It attempts to set a valid property value to bad layer handle.
-     * 2) It creates a layer x and attempts to set a valid property value to
-     *    layer x + 1
-     * 3) It destroys the layer x and attempts to set a valid property value to
-     *    the destroyed layer x.
-     */
-    void setLayerPropertyBadLayer(Hwc2TestCoverage coverage,
-            TestLayerPropertyBadLayerFunction function)
-    {
-        for (auto display : mDisplays) {
-            std::vector<hwc2_config_t> configs;
-
-            ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-            for (auto config : configs) {
-                hwc2_layer_t layer = 0;
-                Area displayArea;
-                hwc2_error_t err = HWC2_ERROR_NONE;
-
-                ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-                ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
-                        &displayArea));
-                Hwc2TestLayer testLayer(coverage, displayArea);
-
-                ASSERT_NO_FATAL_FAILURE(function(this, display, layer,
-                        &testLayer, &err));
-                EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
-                ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
-                ASSERT_NO_FATAL_FAILURE(function(this, display, layer + 1,
-                        &testLayer, &err));
-                EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
-                ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
-
-                ASSERT_NO_FATAL_FAILURE(function(this, display, layer,
-                        &testLayer, &err));
-                EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-            }
-        }
-    }
-
-    /* For each active display it cycles through each display config and tests
-     * each property value. It creates a layer, sets a bad property value and
-     * then destroys the layer */
-    void setLayerPropertyBadParameter(TestLayerPropertyBadParameterFunction function)
-    {
-        for (auto display : mDisplays) {
-            std::vector<hwc2_config_t> configs;
-
-            ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-            for (auto config : configs) {
-                hwc2_layer_t layer;
-                hwc2_error_t err = HWC2_ERROR_NONE;
-
-                ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-
-                ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
-                ASSERT_NO_FATAL_FAILURE(function(this, display, layer, &err));
-                EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong"
-                        " error code";
-
-                ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
-            }
-        }
-    }
-
-    /* For each active display it powers on the display, cycles through each
-     * config and creates a set of layers with a certain amount of coverage.
-     * For each active display, for each config and for each set of layers,
-     * it calls the TestDisplayLayersFunction */
-    void displayLayers(Hwc2TestCoverage coverage, size_t layerCnt,
-            TestDisplayLayersFunction function)
-    {
-        for (auto display : mDisplays) {
-            std::vector<hwc2_config_t> configs;
-
-            ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
-            ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-            for (auto config : configs) {
-                Area displayArea;
-                std::vector<hwc2_layer_t> layers;
-
-                ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-                ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, &displayArea));
-
-                ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
-                Hwc2TestLayers testLayers(layers, coverage, displayArea);
-
-                do {
-                    bool skip;
-
-                    ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers,
-                            &testLayers, &skip));
-                    if (!skip)
-                        EXPECT_NO_FATAL_FAILURE(function(this, display, layers,
-                                &testLayers));
-
-                } while (testLayers.advance());
-
-                ASSERT_NO_FATAL_FAILURE(destroyLayers(display,
-                        std::move(layers)));
-            }
-
-            ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-        }
-    }
-
-    /* For each active display, it calls the
-     * TestDisplayNonValidatedLayersFunction on a variety on non-validated
-     * layer combinations */
-    void displayNonValidatedLayers(size_t layerCnt,
-            TestDisplayNonValidatedLayersFunction function)
-    {
-        for (auto display : mDisplays) {
-            uint32_t numTypes, numRequests;
-            std::vector<hwc2_layer_t> layers;
-            bool hasChanges;
-
-            ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
-            EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
-
-            ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
-
-            EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
-
-            for (auto layer : layers) {
-                ASSERT_NO_FATAL_FAILURE(setLayerCompositionType(display, layer,
-                        HWC2_COMPOSITION_CLIENT));
-            }
-
-            EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
-
-            ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes,
-                    &numRequests, &hasChanges));
-
-            for (auto layer : layers) {
-                ASSERT_NO_FATAL_FAILURE(setLayerCompositionType(display, layer,
-                        HWC2_COMPOSITION_DEVICE));
-            }
-
-            EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
-
-            ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers)));
-
-            EXPECT_NO_FATAL_FAILURE(function(this, display, &layers));
-
-            ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-        }
-    }
-
-    /* Test client target support on each config on each active display */
-    void setClientTargetSupport(Hwc2TestCoverage coverage,
-            TestClientTargetSupportFunction function,
-            AdvanceClientTargetSupport advance)
-    {
-        for (auto display : mDisplays) {
-            std::vector<hwc2_config_t> configs;
-
-            ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-            for (auto config : configs) {
-                Area displayArea;
-
-                ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-                ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
-                        &displayArea));
-                Hwc2TestClientTargetSupport testClientTargetSupport(coverage,
-                        displayArea);
-
-                do {
-                    EXPECT_NO_FATAL_FAILURE(function(this, display,
-                            testClientTargetSupport));
-
-                } while (advance(&testClientTargetSupport));
-            }
-        }
-    }
-
-    /* Cycles through each config on each active display and calls
-     * a TestActiveDisplayConfigFunction */
-    void setActiveDisplayConfig(TestActiveDisplayConfigFunction function)
-    {
-        for (auto display : mDisplays) {
-            std::vector<hwc2_config_t> configs;
-
-            ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-            for (auto config : configs) {
-                ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-
-                EXPECT_NO_FATAL_FAILURE(function(this, display));
-            }
-        }
-    }
-
-    /* Creates a virtual display for testing */
-    void createVirtualDisplay(Hwc2TestCoverage coverage,
-            TestCreateVirtualDisplayFunction function)
-    {
-        Hwc2TestVirtualDisplay testVirtualDisplay(coverage);
-
-        do {
-            hwc2_display_t display;
-            hwc2_error_t err = HWC2_ERROR_NONE;
-
-            const UnsignedArea& dimension =
-                    testVirtualDisplay.getDisplayDimension();
-            android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-
-            ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width,
-                    dimension.height, &desiredFormat, &display, &err));
-
-            EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_NO_RESOURCES
-                    || err == HWC2_ERROR_UNSUPPORTED)
-                    << "returned wrong error code";
-            EXPECT_GE(desiredFormat, 0) << "invalid format";
-
-            if (err != HWC2_ERROR_NONE)
-                continue;
-
-            EXPECT_NO_FATAL_FAILURE(function(this, display,
-                    &testVirtualDisplay));
-
-            ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display));
-
-        } while (testVirtualDisplay.advance());
-    }
-
-
-    void getActiveConfigAttribute(hwc2_display_t display,
-            hwc2_attribute_t attribute, int32_t* outValue)
-    {
-        hwc2_config_t config;
-        ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &config));
-        ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
-                attribute, outValue));
-        ASSERT_GE(*outValue, 0) << "failed to get valid "
-                << getAttributeName(attribute);
-    }
-
-    void getActiveDisplayArea(hwc2_display_t display, Area* displayArea)
-    {
-        ASSERT_NO_FATAL_FAILURE(getActiveConfigAttribute(display,
-                HWC2_ATTRIBUTE_WIDTH, &displayArea->width));
-        ASSERT_NO_FATAL_FAILURE(getActiveConfigAttribute(display,
-                HWC2_ATTRIBUTE_HEIGHT, &displayArea->height));
-    }
-
-    void closeFences(hwc2_display_t display, int32_t presentFence)
-    {
-        std::vector<hwc2_layer_t> layers;
-        std::vector<int32_t> fences;
-        const int msWait = 3000;
-
-        if (presentFence >= 0) {
-            ASSERT_GE(sync_wait(presentFence, msWait), 0);
-            close(presentFence);
-        }
-
-        ASSERT_NO_FATAL_FAILURE(getReleaseFences(display, &layers, &fences));
-        EXPECT_EQ(layers.size(), fences.size());
-
-        for (int32_t fence : fences) {
-            if (fence >= 0) {
-                EXPECT_GE(sync_wait(fence, msWait), 0);
-                close(fence);
-            }
-        }
-    }
-
-    void setLayerProperties(hwc2_display_t display, hwc2_layer_t layer,
-            Hwc2TestLayers* testLayers, bool* outSkip)
-    {
-        hwc2_composition_t composition;
-        buffer_handle_t handle = nullptr;
-        int32_t acquireFence;
-        hwc2_error_t err = HWC2_ERROR_NONE;
-        *outSkip = true;
-
-        if (!testLayers->contains(layer))
-            return;
-
-        composition = testLayers->getComposition(layer);
-
-        /* If the device cannot support a buffer format, then do not continue */
-        if ((composition == HWC2_COMPOSITION_DEVICE
-                || composition == HWC2_COMPOSITION_CURSOR)
-                && testLayers->getBuffer(layer, &handle, &acquireFence) < 0)
-            return;
-
-        EXPECT_NO_FATAL_FAILURE(setLayerCompositionType(display, layer,
-                composition, &err));
-        if (err == HWC2_ERROR_UNSUPPORTED)
-            EXPECT_TRUE(composition != HWC2_COMPOSITION_CLIENT
-                    && composition != HWC2_COMPOSITION_DEVICE);
-
-        const hwc_rect_t cursor = testLayers->getCursorPosition(layer);
-
-        EXPECT_NO_FATAL_FAILURE(setLayerBuffer(display, layer, handle,
-                acquireFence));
-        EXPECT_NO_FATAL_FAILURE(setLayerBlendMode(display, layer,
-                testLayers->getBlendMode(layer)));
-        EXPECT_NO_FATAL_FAILURE(setLayerColor(display, layer,
-                testLayers->getColor(layer)));
-        if (composition == HWC2_COMPOSITION_CURSOR)
-            EXPECT_NO_FATAL_FAILURE(setCursorPosition(display, layer,
-            cursor.left, cursor.top));
-        EXPECT_NO_FATAL_FAILURE(setLayerDataspace(display, layer,
-                testLayers->getDataspace(layer)));
-        EXPECT_NO_FATAL_FAILURE(setLayerDisplayFrame(display, layer,
-                testLayers->getDisplayFrame(layer)));
-        EXPECT_NO_FATAL_FAILURE(setLayerPlaneAlpha(display, layer,
-                testLayers->getPlaneAlpha(layer)));
-        EXPECT_NO_FATAL_FAILURE(setLayerSourceCrop(display, layer,
-                testLayers->getSourceCrop(layer)));
-        EXPECT_NO_FATAL_FAILURE(setLayerSurfaceDamage(display, layer,
-                testLayers->getSurfaceDamage(layer)));
-        EXPECT_NO_FATAL_FAILURE(setLayerTransform(display, layer,
-                testLayers->getTransform(layer)));
-        EXPECT_NO_FATAL_FAILURE(setLayerVisibleRegion(display, layer,
-                testLayers->getVisibleRegion(layer)));
-        EXPECT_NO_FATAL_FAILURE(setLayerZOrder(display, layer,
-                testLayers->getZOrder(layer)));
-
-        *outSkip = false;
-    }
-
-    void setLayerProperties(hwc2_display_t display,
-            const std::vector<hwc2_layer_t>& layers,
-            Hwc2TestLayers* testLayers, bool* outSkip)
-    {
-        for (auto layer : layers) {
-            EXPECT_NO_FATAL_FAILURE(setLayerProperties(display, layer,
-                    testLayers, outSkip));
-            if (*outSkip)
-                return;
-        }
-    }
-
-    void setClientTarget(hwc2_display_t display,
-            Hwc2TestClientTarget* testClientTarget,
-            const Hwc2TestLayers& testLayers,
-            const std::set<hwc2_layer_t>& clientLayers,
-            const std::set<hwc2_layer_t>& clearLayers, bool flipClientTarget,
-            const Area& displayArea)
-    {
-        Dataspace dataspace = Dataspace::UNKNOWN;
-        hwc_region_t damage = { };
-        buffer_handle_t handle;
-        int32_t acquireFence;
-
-        ASSERT_EQ(testClientTarget->getBuffer(testLayers, clientLayers,
-                clearLayers, flipClientTarget, displayArea, &handle,
-                &acquireFence), 0);
-        EXPECT_NO_FATAL_FAILURE(setClientTarget(display, handle, acquireFence,
-                dataspace, damage));
-    }
-
-    void presentDisplays(size_t layerCnt, Hwc2TestCoverage coverage,
-            const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>&
-            coverageExceptions, bool optimize)
-    {
-        for (auto display : mDisplays) {
-            std::vector<hwc2_config_t> configs;
-
-            ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-            ASSERT_NO_FATAL_FAILURE(enableVsync(display));
-
-            ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-            for (auto config : configs) {
-                Area displayArea;
-                std::vector<hwc2_layer_t> layers;
-
-                ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-                ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
-                        &displayArea));
-
-                ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
-                Hwc2TestLayers testLayers(layers, coverage, displayArea,
-                        coverageExceptions);
-
-                if (optimize && !testLayers.optimizeLayouts())
-                    continue;
-
-                std::set<hwc2_layer_t> clientLayers;
-                std::set<hwc2_layer_t> clearLayers;
-                Hwc2TestClientTarget testClientTarget;
-
-                do {
-                    uint32_t numTypes, numRequests;
-                    bool hasChanges, skip;
-                    bool flipClientTarget;
-                    int32_t presentFence;
-
-                    ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers,
-                            &testLayers, &skip));
-                    if (skip)
-                        continue;
-
-                    ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes,
-                            &numRequests, &hasChanges));
-                    if (hasChanges)
-                        EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size()))
-                                << "wrong number of requests";
-
-                    ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display,
-                            testLayers, layers, numTypes, &clientLayers));
-                    ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers,
-                            numRequests, &clearLayers, &flipClientTarget));
-                    ASSERT_NO_FATAL_FAILURE(setClientTarget(display,
-                            &testClientTarget, testLayers, clientLayers,
-                            clearLayers, flipClientTarget, displayArea));
-                    ASSERT_NO_FATAL_FAILURE(acceptDisplayChanges(display));
-
-                    ASSERT_NO_FATAL_FAILURE(waitForVsync());
-
-                    EXPECT_NO_FATAL_FAILURE(presentDisplay(display,
-                            &presentFence));
-
-                    ASSERT_NO_FATAL_FAILURE(closeFences(display, presentFence));
-
-                } while (testLayers.advance());
-
-                ASSERT_NO_FATAL_FAILURE(destroyLayers(display,
-                        std::move(layers)));
-            }
-
-            ASSERT_NO_FATAL_FAILURE(disableVsync(display));
-            ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-        }
-    }
-
-    void createAndPresentVirtualDisplay(size_t layerCnt,
-            Hwc2TestCoverage coverage,
-            const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>&
-            coverageExceptions)
-    {
-        Hwc2TestVirtualDisplay testVirtualDisplay(coverage);
-        hwc2_display_t display;
-        android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-
-        do {
-            // Items dependent on the display dimensions
-            hwc2_error_t err = HWC2_ERROR_NONE;
-            const UnsignedArea& dimension =
-                    testVirtualDisplay.getDisplayDimension();
-            ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width,
-                    dimension.height, &desiredFormat, &display, &err));
-            ASSERT_TRUE(err == HWC2_ERROR_NONE)
-                    << "Cannot allocate virtual display";
-
-            ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-            ASSERT_NO_FATAL_FAILURE(enableVsync(display));
-
-            std::vector<hwc2_config_t> configs;
-            ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-            for (auto config : configs) {
-                ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-
-                Area displayArea;
-                ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display,
-                        &displayArea));
-
-                std::vector<hwc2_layer_t> layers;
-                ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers,
-                        layerCnt));
-                Hwc2TestLayers testLayers(layers, coverage, displayArea,
-                        coverageExceptions);
-
-                /*
-                 * Layouts that do not cover an entire virtual display will
-                 * cause undefined behavior.
-                 * Enable optimizeLayouts to avoid this.
-                 */
-                testLayers.optimizeLayouts();
-                do {
-                    // Items dependent on the testLayers properties
-                    std::set<hwc2_layer_t> clientLayers;
-                    std::set<hwc2_layer_t> clearLayers;
-                    uint32_t numTypes, numRequests;
-                    bool hasChanges, skip;
-                    bool flipClientTarget;
-                    int32_t presentFence;
-                    Hwc2TestClientTarget testClientTarget;
-                    buffer_handle_t outputBufferHandle;
-                    android::base::unique_fd outputBufferReleaseFence;
-
-                    ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers,
-                            &testLayers, &skip));
-
-                    if (skip)
-                        continue;
-
-                    ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes,
-                            &numRequests, &hasChanges));
-
-                    if (hasChanges)
-                        EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size()))
-                                << "wrong number of requests";
-
-                    ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display,
-                            testLayers, layers, numTypes, &clientLayers));
-
-                    ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers,
-                            numRequests, &clearLayers, &flipClientTarget));
-                    ASSERT_NO_FATAL_FAILURE(setClientTarget(display,
-                            &testClientTarget, testLayers, clientLayers,
-                            clearLayers, flipClientTarget, displayArea));
-                    ASSERT_NO_FATAL_FAILURE(acceptDisplayChanges(display));
-
-                    ASSERT_EQ(testVirtualDisplay.getOutputBuffer(
-                            &outputBufferHandle, &outputBufferReleaseFence), 0);
-                    ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display,
-                            outputBufferHandle, outputBufferReleaseFence));
-
-                    EXPECT_NO_FATAL_FAILURE(presentDisplay(display,
-                            &presentFence));
-                    ASSERT_NO_FATAL_FAILURE(closeFences(display, presentFence));
-
-                    ASSERT_EQ(testVirtualDisplay.verifyOutputBuffer(&testLayers,
-                            &layers, &clearLayers), 0);
-
-                    /*
-                     * Upscaling the image causes minor pixel differences.
-                     * Work around this by using some threshold.
-                     *
-                     * Fail test if we are off by more than 1% of our
-                     * pixels.
-                     */
-                    ComparatorResult& comparatorResult = ComparatorResult::get();
-                    int threshold = (dimension.width * dimension.height) / 100;
-                    double diffPercent = (comparatorResult.getDifferentPixelCount() * 100.0) /
-                            (dimension.width * dimension.height);
-
-                    if (comparatorResult.getDifferentPixelCount() != 0)
-                        EXPECT_TRUE(false)
-                                << comparatorResult.getDifferentPixelCount() << " pixels ("
-                                << diffPercent << "%) are different.";
-
-                    if (comparatorResult.getDifferentPixelCount() > threshold) {
-                        EXPECT_TRUE(false)
-                                << "Mismatched pixel count exceeds threshold. "
-                                << "Writing buffers to file.";
-
-                        const ::testing::TestInfo* const test_info =
-                                ::testing::UnitTest::GetInstance()
-                                ->current_test_info();
-
-                        EXPECT_EQ(testVirtualDisplay.writeBuffersToFile(
-                                test_info->name()), 0)
-                                << "Failed to write buffers.";
-                    }
-
-                    ASSERT_LE(comparatorResult.getDifferentPixelCount(), threshold)
-                            << comparatorResult.getDifferentPixelCount() << " pixels ("
-                            << diffPercent << "%) are different. "
-                            << "Exceeds 1% threshold, terminating test. "
-                            << "Test case: " << testLayers.dump();
-
-                } while (testLayers.advance());
-
-                ASSERT_NO_FATAL_FAILURE(destroyLayers(display,
-                        std::move(layers)));
-            }
-            ASSERT_NO_FATAL_FAILURE(disableVsync(display));
-            ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-            ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display));
-        } while (testVirtualDisplay.advance());
-    }
-
-    hwc2_device_t* mHwc2Device = nullptr;
-
-    enum class Hwc2TestHotplugStatus {
-        Init = 1,
-        Receiving,
-        Done,
-    };
-
-    std::mutex mHotplugMutex;
-    std::condition_variable mHotplugCv;
-    Hwc2TestHotplugStatus mHotplugStatus = Hwc2TestHotplugStatus::Init;
-    std::unordered_set<hwc2_display_t> mDisplays;
-
-    /* Store all created layers that have not been destroyed. If an ASSERT_*
-     * fails, then destroy the layers on exit */
-    std::set<std::pair<hwc2_display_t, hwc2_layer_t>> mLayers;
-
-    /* Store the power mode state. If it is not HWC2_POWER_MODE_OFF when
-     * tearing down the test cases, change it to HWC2_POWER_MODE_OFF */
-    std::set<hwc2_display_t> mActiveDisplays;
-
-    /* Store all created virtual displays that have not been destroyed. If an
-     * ASSERT_* fails, then destroy the virtual displays on exit */
-    std::set<hwc2_display_t> mVirtualDisplays;
-
-    std::mutex mVsyncMutex;
-    std::condition_variable mVsyncCv;
-    hwc2_display_t mVsyncDisplay;
-    int64_t mVsyncTimestamp = -1;
-};
-
-void hwc2TestHotplugCallback(hwc2_callback_data_t callbackData,
-        hwc2_display_t display, int32_t connection)
-{
-    if (callbackData)
-        static_cast<Hwc2Test*>(callbackData)->hotplugCallback(display,
-                connection);
-}
-
-void hwc2TestVsyncCallback(hwc2_callback_data_t callbackData,
-        hwc2_display_t display, int64_t timestamp)
-{
-    if (callbackData)
-        static_cast<Hwc2Test*>(callbackData)->vsyncCallback(display,
-                timestamp);
-}
-
-void setBlendMode(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-        Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
-    EXPECT_NO_FATAL_FAILURE(test->setLayerBlendMode(display, layer,
-            testLayer->getBlendMode(), outErr));
-}
-
-void setBuffer(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-        Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
-    buffer_handle_t handle;
-    android::base::unique_fd acquireFence;
-    hwc2_composition_t composition = testLayer->getComposition();
-
-    if (composition == HWC2_COMPOSITION_CLIENT
-            || composition == HWC2_COMPOSITION_SOLID_COLOR
-            || composition == HWC2_COMPOSITION_SIDEBAND)
-        return;
-
-    if (testLayer->getBuffer(&handle, &acquireFence) < 0)
-        return;
-
-    ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, layer,
-            composition));
-    EXPECT_NO_FATAL_FAILURE(test->setLayerBuffer(display, layer,
-            handle, acquireFence, outErr));
-}
-
-void setColor(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-        Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
-    ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display,
-            layer, HWC2_COMPOSITION_SOLID_COLOR));
-    ASSERT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display,
-            layer, testLayer->getPlaneAlpha()));
-    ASSERT_NO_FATAL_FAILURE(test->setLayerBlendMode(display,
-            layer, testLayer->getBlendMode()));
-    EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, layer,
-            testLayer->getColor(), outErr));
-}
-
-void setComposition(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-        Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
-    hwc2_composition_t composition = testLayer->getComposition();
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display, layer,
-            composition, &err));
-    if (outErr) {
-        *outErr = err;
-        return;
-    }
-
-    if (composition != HWC2_COMPOSITION_SIDEBAND) {
-        EXPECT_EQ(err, HWC2_ERROR_NONE) << "returned wrong error code";
-    } else {
-        EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_UNSUPPORTED)
-                 << "returned wrong error code";
-    }
-}
-
-void setCursorPosition(Hwc2Test* test, hwc2_display_t display,
-        hwc2_layer_t layer, Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
-    ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display,
-            layer, HWC2_COMPOSITION_CURSOR));
-
-    const hwc_rect_t cursorPosition = testLayer->getCursorPosition();
-    EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer,
-            cursorPosition.left, cursorPosition.top, outErr));
-}
-
-void setDataspace(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-        Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
-    EXPECT_NO_FATAL_FAILURE(test->setLayerDataspace(display, layer,
-            testLayer->getDataspace(), outErr));
-}
-
-void setDisplayFrame(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-        Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
-    EXPECT_NO_FATAL_FAILURE(test->setLayerDisplayFrame(display, layer,
-            testLayer->getDisplayFrame(), outErr));
-}
-
-void setPlaneAlpha(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-        Hwc2TestLayer* testLayer, hwc2_error_t *outErr)
-{
-    ASSERT_NO_FATAL_FAILURE(test->setLayerBlendMode(display, layer,
-            testLayer->getBlendMode()));
-    EXPECT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display, layer,
-            testLayer->getPlaneAlpha(), outErr));
-}
-
-void setSourceCrop(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-        Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
-    EXPECT_NO_FATAL_FAILURE(test->setLayerSourceCrop(display, layer,
-            testLayer->getSourceCrop(), outErr));
-}
-
-void setSurfaceDamage(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-        Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
-    EXPECT_NO_FATAL_FAILURE(test->setLayerSurfaceDamage(display, layer,
-            testLayer->getSurfaceDamage(), outErr));
-}
-
-void setTransform(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-        Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
-    EXPECT_NO_FATAL_FAILURE(test->setLayerTransform(display, layer,
-            testLayer->getTransform(), outErr));
-}
-
-void setVisibleRegion(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-        Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
-    EXPECT_NO_FATAL_FAILURE(test->setLayerVisibleRegion(display, layer,
-            testLayer->getVisibleRegion(), outErr));
-}
-
-void setZOrder(Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-        Hwc2TestLayer* testLayer, hwc2_error_t* outErr)
-{
-    EXPECT_NO_FATAL_FAILURE(test->setLayerZOrder(display, layer,
-            testLayer->getZOrder(), outErr));
-}
-
-bool advanceBlendMode(Hwc2TestLayer* testLayer)
-{
-    return testLayer->advanceBlendMode();
-}
-
-bool advanceBuffer(Hwc2TestLayer* testLayer)
-{
-    if (testLayer->advanceComposition())
-        return true;
-    return testLayer->advanceBufferArea();
-}
-
-bool advanceColor(Hwc2TestLayer* testLayer)
-{
-    /* Color depends on blend mode so advance blend mode last so color is not
-     * force to update as often */
-    if (testLayer->advancePlaneAlpha())
-        return true;
-    if (testLayer->advanceColor())
-        return true;
-    return testLayer->advanceBlendMode();
-}
-
-bool advanceComposition(Hwc2TestLayer* testLayer)
-{
-    return testLayer->advanceComposition();
-}
-
-bool advanceCursorPosition(Hwc2TestLayer* testLayer)
-{
-    return testLayer->advanceCursorPosition();
-}
-
-bool advanceDataspace(Hwc2TestLayer* testLayer)
-{
-    return testLayer->advanceDataspace();
-}
-
-bool advanceDisplayFrame(Hwc2TestLayer* testLayer)
-{
-    return testLayer->advanceDisplayFrame();
-}
-
-bool advancePlaneAlpha(Hwc2TestLayer* testLayer)
-{
-    return testLayer->advancePlaneAlpha();
-}
-
-bool advanceSourceCrop(Hwc2TestLayer* testLayer)
-{
-    if (testLayer->advanceSourceCrop())
-        return true;
-    return testLayer->advanceBufferArea();
-}
-
-bool advanceSurfaceDamage(Hwc2TestLayer* testLayer)
-{
-    if (testLayer->advanceSurfaceDamage())
-        return true;
-    return testLayer->advanceBufferArea();
-}
-
-bool advanceTransform(Hwc2TestLayer* testLayer)
-{
-    return testLayer->advanceTransform();
-}
-
-bool advanceVisibleRegions(Hwc2TestLayers* testLayers)
-{
-    return testLayers->advanceVisibleRegions();
-}
-
-bool advanceClientTargetSupport(
-        Hwc2TestClientTargetSupport* testClientTargetSupport)
-{
-    return testClientTargetSupport->advance();
-}
-
-static const std::array<hwc2_function_descriptor_t, 42> requiredFunctions = {{
-    HWC2_FUNCTION_ACCEPT_DISPLAY_CHANGES,
-    HWC2_FUNCTION_CREATE_LAYER,
-    HWC2_FUNCTION_CREATE_VIRTUAL_DISPLAY,
-    HWC2_FUNCTION_DESTROY_LAYER,
-    HWC2_FUNCTION_DESTROY_VIRTUAL_DISPLAY,
-    HWC2_FUNCTION_DUMP,
-    HWC2_FUNCTION_GET_ACTIVE_CONFIG,
-    HWC2_FUNCTION_GET_CHANGED_COMPOSITION_TYPES,
-    HWC2_FUNCTION_GET_CLIENT_TARGET_SUPPORT,
-    HWC2_FUNCTION_GET_COLOR_MODES,
-    HWC2_FUNCTION_GET_DISPLAY_ATTRIBUTE,
-    HWC2_FUNCTION_GET_DISPLAY_CONFIGS,
-    HWC2_FUNCTION_GET_DISPLAY_NAME,
-    HWC2_FUNCTION_GET_DISPLAY_REQUESTS,
-    HWC2_FUNCTION_GET_DISPLAY_TYPE,
-    HWC2_FUNCTION_GET_DOZE_SUPPORT,
-    HWC2_FUNCTION_GET_HDR_CAPABILITIES,
-    HWC2_FUNCTION_GET_MAX_VIRTUAL_DISPLAY_COUNT,
-    HWC2_FUNCTION_GET_RELEASE_FENCES,
-    HWC2_FUNCTION_PRESENT_DISPLAY,
-    HWC2_FUNCTION_REGISTER_CALLBACK,
-    HWC2_FUNCTION_SET_ACTIVE_CONFIG,
-    HWC2_FUNCTION_SET_CLIENT_TARGET,
-    HWC2_FUNCTION_SET_COLOR_MODE,
-    HWC2_FUNCTION_SET_COLOR_TRANSFORM,
-    HWC2_FUNCTION_SET_CURSOR_POSITION,
-    HWC2_FUNCTION_SET_LAYER_BLEND_MODE,
-    HWC2_FUNCTION_SET_LAYER_BUFFER,
-    HWC2_FUNCTION_SET_LAYER_COLOR,
-    HWC2_FUNCTION_SET_LAYER_COMPOSITION_TYPE,
-    HWC2_FUNCTION_SET_LAYER_DATASPACE,
-    HWC2_FUNCTION_SET_LAYER_DISPLAY_FRAME,
-    HWC2_FUNCTION_SET_LAYER_PLANE_ALPHA,
-    HWC2_FUNCTION_SET_LAYER_SOURCE_CROP,
-    HWC2_FUNCTION_SET_LAYER_SURFACE_DAMAGE,
-    HWC2_FUNCTION_SET_LAYER_TRANSFORM,
-    HWC2_FUNCTION_SET_LAYER_VISIBLE_REGION,
-    HWC2_FUNCTION_SET_LAYER_Z_ORDER,
-    HWC2_FUNCTION_SET_OUTPUT_BUFFER,
-    HWC2_FUNCTION_SET_POWER_MODE,
-    HWC2_FUNCTION_SET_VSYNC_ENABLED,
-    HWC2_FUNCTION_VALIDATE_DISPLAY,
-}};
-
-/* TESTCASE: Tests that the HWC2 supports all required functions. */
-TEST_F(Hwc2Test, GET_FUNCTION)
-{
-    for (hwc2_function_descriptor_t descriptor : requiredFunctions) {
-        hwc2_function_pointer_t pfn = getFunction(descriptor);
-        EXPECT_TRUE(pfn) << "failed to get function "
-                << getFunctionDescriptorName(descriptor);
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 fails to retrieve and invalid function. */
-TEST_F(Hwc2Test, GET_FUNCTION_invalid_function)
-{
-    hwc2_function_pointer_t pfn = getFunction(HWC2_FUNCTION_INVALID);
-    EXPECT_FALSE(pfn) << "failed to get invalid function";
-}
-
-/* TESTCASE: Tests that the HWC2 does not return an invalid capability. */
-TEST_F(Hwc2Test, GET_CAPABILITIES)
-{
-    std::vector<hwc2_capability_t> capabilities;
-
-    getCapabilities(&capabilities);
-
-    EXPECT_EQ(std::count(capabilities.begin(), capabilities.end(),
-            HWC2_CAPABILITY_INVALID), 0);
-}
-
-static const std::array<hwc2_callback_descriptor_t, 3> callbackDescriptors = {{
-    HWC2_CALLBACK_HOTPLUG,
-    HWC2_CALLBACK_REFRESH,
-    HWC2_CALLBACK_VSYNC,
-}};
-
-/* TESTCASE: Tests that the HWC2 can successfully register all required
- * callback functions. */
-TEST_F(Hwc2Test, REGISTER_CALLBACK)
-{
-    hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
-            const_cast<char*>("data"));
-
-    for (auto descriptor : callbackDescriptors) {
-        ASSERT_NO_FATAL_FAILURE(registerCallback(descriptor, data,
-                []() { return; }));
-    }
-}
-
-/* TESTCASE: Test that the HWC2 fails to register invalid callbacks. */
-TEST_F(Hwc2Test, REGISTER_CALLBACK_bad_parameter)
-{
-    hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
-            const_cast<char*>("data"));
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_INVALID, data,
-            []() { return; }, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 can register a callback with null data. */
-TEST_F(Hwc2Test, REGISTER_CALLBACK_null_data)
-{
-    hwc2_callback_data_t data = nullptr;
-
-    for (auto descriptor : callbackDescriptors) {
-        ASSERT_NO_FATAL_FAILURE(registerCallback(descriptor, data,
-                []() { return; }));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 returns the correct display type for each
- * physical display. */
-TEST_F(Hwc2Test, GET_DISPLAY_TYPE)
-{
-    for (auto display : mDisplays) {
-        hwc2_display_type_t type;
-
-        ASSERT_NO_FATAL_FAILURE(getDisplayType(display, &type));
-        EXPECT_EQ(type, HWC2_DISPLAY_TYPE_PHYSICAL) << "failed to return"
-                " correct display type";
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 returns an error when the display type of a bad
- * display is requested. */
-TEST_F(Hwc2Test, GET_DISPLAY_TYPE_bad_display)
-{
-    hwc2_display_t display;
-    hwc2_display_type_t type;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(getDisplayType(display, &type, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 can create and destroy layers. */
-TEST_F(Hwc2Test, CREATE_DESTROY_LAYER)
-{
-    for (auto display : mDisplays) {
-        hwc2_layer_t layer;
-
-        ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
-        ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot create a layer for a bad display */
-TEST_F(Hwc2Test, CREATE_LAYER_bad_display)
-{
-    hwc2_display_t display;
-    hwc2_layer_t layer;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 will either support a large number of resources
- * or will return no resources. */
-TEST_F(Hwc2Test, CREATE_LAYER_no_resources)
-{
-    const size_t layerCnt = 1000;
-
-    for (auto display : mDisplays) {
-        std::vector<hwc2_layer_t> layers;
-
-        ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
-
-        ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers)));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot destroy a layer for a bad display */
-TEST_F(Hwc2Test, DESTROY_LAYER_bad_display)
-{
-    hwc2_display_t badDisplay;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&badDisplay));
-
-    for (auto display : mDisplays) {
-        hwc2_layer_t layer = 0;
-        hwc2_error_t err = HWC2_ERROR_NONE;
-
-        ASSERT_NO_FATAL_FAILURE(destroyLayer(badDisplay, layer, &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-
-        ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
-        ASSERT_NO_FATAL_FAILURE(destroyLayer(badDisplay, layer, &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-
-        ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot destory a bad layer */
-TEST_F(Hwc2Test, DESTROY_LAYER_bad_layer)
-{
-    for (auto display : mDisplays) {
-        hwc2_layer_t layer;
-        hwc2_error_t err = HWC2_ERROR_NONE;
-
-        ASSERT_NO_FATAL_FAILURE(destroyLayer(display, UINT64_MAX / 2, &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
-        ASSERT_NO_FATAL_FAILURE(destroyLayer(display, 0, &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
-        ASSERT_NO_FATAL_FAILURE(destroyLayer(display, UINT64_MAX - 1, &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
-        ASSERT_NO_FATAL_FAILURE(destroyLayer(display, 1, &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
-        ASSERT_NO_FATAL_FAILURE(destroyLayer(display, UINT64_MAX, &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
-        ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
-        ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer + 1, &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-
-        ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
-
-        ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer, &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_LAYER) << "returned wrong error code";
-    }
-}
-
-static const std::array<hwc2_attribute_t, 2> requiredAttributes = {{
-    HWC2_ATTRIBUTE_WIDTH,
-    HWC2_ATTRIBUTE_HEIGHT,
-}};
-
-static const std::array<hwc2_attribute_t, 3> optionalAttributes = {{
-    HWC2_ATTRIBUTE_VSYNC_PERIOD,
-    HWC2_ATTRIBUTE_DPI_X,
-    HWC2_ATTRIBUTE_DPI_Y,
-}};
-
-/* TESTCASE: Tests that the HWC2 can return display attributes for a valid
- * config. */
-TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE)
-{
-    for (auto display : mDisplays) {
-        std::vector<hwc2_config_t> configs;
-
-        ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-        for (auto config : configs) {
-            int32_t value;
-
-            for (auto attribute : requiredAttributes) {
-                ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
-                        attribute, &value));
-                EXPECT_GE(value, 0) << "missing required attribute "
-                        << getAttributeName(attribute) << " for config "
-                        << config;
-            }
-            for (auto attribute : optionalAttributes) {
-                ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
-                        attribute, &value));
-            }
-        }
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 will return a value of -1 for an invalid
- * attribute */
-TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE_invalid_attribute)
-{
-    const hwc2_attribute_t attribute = HWC2_ATTRIBUTE_INVALID;
-
-    for (auto display : mDisplays) {
-        std::vector<hwc2_config_t> configs;
-
-        ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-        for (auto config : configs) {
-            int32_t value;
-            hwc2_error_t err = HWC2_ERROR_NONE;
-
-            ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
-                    attribute, &value, &err));
-            EXPECT_EQ(value, -1) << "failed to return -1 for an invalid"
-                    " attribute for config " << config;
-        }
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 will fail to get attributes for a bad display */
-TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE_bad_display)
-{
-    hwc2_display_t display;
-    const hwc2_config_t config = 0;
-    int32_t value;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    for (auto attribute : requiredAttributes) {
-        ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config, attribute,
-                &value, &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-    }
-
-    for (auto attribute : optionalAttributes) {
-        ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config, attribute,
-                &value, &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 will fail to get attributes for a bad config */
-TEST_F(Hwc2Test, GET_DISPLAY_ATTRIBUTE_bad_config)
-{
-    for (auto display : mDisplays) {
-        hwc2_config_t config;
-        int32_t value;
-        hwc2_error_t err = HWC2_ERROR_NONE;
-
-        ASSERT_NO_FATAL_FAILURE(getInvalidConfig(display, &config));
-
-        for (auto attribute : requiredAttributes) {
-            ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
-                    attribute, &value, &err));
-            EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code";
-        }
-
-        for (auto attribute : optionalAttributes) {
-            ASSERT_NO_FATAL_FAILURE(getDisplayAttribute(display, config,
-                    attribute, &value, &err));
-            EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code";
-        }
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 will get display configs for active displays */
-TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS)
-{
-    for (auto display : mDisplays) {
-        std::vector<hwc2_config_t> configs;
-
-        ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 will not get display configs for bad displays */
-TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS_bad_display)
-{
-    hwc2_display_t display;
-    std::vector<hwc2_config_t> configs;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs, &err));
-
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-    EXPECT_TRUE(configs.empty()) << "returned configs for bad display";
-}
-
-/* TESTCASE: Tests that the HWC2 will return the same config list multiple
- * times in a row. */
-TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS_same)
-{
-    for (auto display : mDisplays) {
-        std::vector<hwc2_config_t> configs1, configs2;
-
-        ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs1));
-        ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs2));
-
-        EXPECT_TRUE(std::is_permutation(configs1.begin(), configs1.end(),
-                configs2.begin())) << "returned two different config sets";
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 does not return duplicate display configs */
-TEST_F(Hwc2Test, GET_DISPLAY_CONFIGS_duplicate)
-{
-    for (auto display : mDisplays) {
-        std::vector<hwc2_config_t> configs;
-
-        ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-        std::unordered_set<hwc2_config_t> configsSet(configs.begin(),
-                configs.end());
-        EXPECT_EQ(configs.size(), configsSet.size()) << "returned duplicate"
-                " configs";
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 returns the active config for a display */
-TEST_F(Hwc2Test, GET_ACTIVE_CONFIG)
-{
-    for (auto display : mDisplays) {
-        std::vector<hwc2_config_t> configs;
-
-        ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-        for (auto config : configs) {
-            hwc2_config_t activeConfig;
-
-            ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-            ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &activeConfig));
-
-            EXPECT_EQ(activeConfig, config) << "failed to get active config";
-        }
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 does not return an active config for a bad
- * display. */
-TEST_F(Hwc2Test, GET_ACTIVE_CONFIG_bad_display)
-{
-    hwc2_display_t display;
-    hwc2_config_t activeConfig;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &activeConfig, &err));
-
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 either begins with a valid active config
- * or returns an error when getActiveConfig is called. */
-TEST_F(Hwc2Test, GET_ACTIVE_CONFIG_bad_config)
-{
-    for (auto display : mDisplays) {
-        std::vector<hwc2_config_t> configs;
-        hwc2_config_t activeConfig;
-        hwc2_error_t err = HWC2_ERROR_NONE;
-
-        ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-        if (configs.empty())
-            return;
-
-        ASSERT_NO_FATAL_FAILURE(getActiveConfig(display, &activeConfig, &err));
-        if (err == HWC2_ERROR_NONE) {
-            EXPECT_NE(std::count(configs.begin(), configs.end(),
-                    activeConfig), 0) << "active config is not found in "
-                    " configs for display";
-        } else {
-            EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code";
-        }
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 can set every display config as an active
- * config */
-TEST_F(Hwc2Test, SET_ACTIVE_CONFIG)
-{
-    for (auto display : mDisplays) {
-        std::vector<hwc2_config_t> configs;
-
-        ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-        for (auto config : configs) {
-            EXPECT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-        }
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an active config for a bad display */
-TEST_F(Hwc2Test, SET_ACTIVE_CONFIG_bad_display)
-{
-    hwc2_display_t display;
-    const hwc2_config_t config = 0;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an invalid active config */
-TEST_F(Hwc2Test, SET_ACTIVE_CONFIG_bad_config)
-{
-    for (auto display : mDisplays) {
-        hwc2_config_t config;
-        hwc2_error_t err = HWC2_ERROR_NONE;
-
-        ASSERT_NO_FATAL_FAILURE(getInvalidConfig(display, &config));
-
-        ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config, &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_CONFIG) << "returned wrong error code";
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 returns a valid value for getDozeSupport. */
-TEST_F(Hwc2Test, GET_DOZE_SUPPORT)
-{
-    for (auto display : mDisplays) {
-        int32_t support = -1;
-
-        ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support));
-
-        EXPECT_TRUE(support == 0 || support == 1) << "invalid doze support value";
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get doze support for a bad display. */
-TEST_F(Hwc2Test, GET_DOZE_SUPPORT_bad_display)
-{
-    hwc2_display_t display;
-    int32_t support = -1;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support, &err));
-
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 can set all supported power modes */
-TEST_F(Hwc2Test, SET_POWER_MODE)
-{
-    for (auto display : mDisplays) {
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-
-        int32_t support = -1;
-        ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support));
-        if (support != 1)
-            return;
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE));
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display,
-                HWC2_POWER_MODE_DOZE_SUSPEND));
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a power mode for a bad display. */
-TEST_F(Hwc2Test, SET_POWER_MODE_bad_display)
-{
-    hwc2_display_t display;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-
-    ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-
-    int32_t support = -1;
-    ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support, &err));
-    if (support != 1)
-        return;
-
-    ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-
-    ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE_SUSPEND,
-            &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an invalid power mode value. */
-TEST_F(Hwc2Test, SET_POWER_MODE_bad_parameter)
-{
-    for (auto display : mDisplays) {
-        hwc2_power_mode_t mode = static_cast<hwc2_power_mode_t>(
-                HWC2_POWER_MODE_DOZE_SUSPEND + 1);
-        hwc2_error_t err = HWC2_ERROR_NONE;
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, mode, &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code "
-                << mode;
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 will return unsupported if it does not support
- * an optional power mode. */
-TEST_F(Hwc2Test, SET_POWER_MODE_unsupported)
-{
-    for (auto display : mDisplays) {
-        int32_t support = -1;
-        hwc2_error_t err = HWC2_ERROR_NONE;
-
-        ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support, &err));
-        if (support == 1)
-            return;
-
-        ASSERT_EQ(support, 0) << "invalid doze support value";
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE,
-                &err));
-        EXPECT_EQ(err, HWC2_ERROR_UNSUPPORTED) << "returned wrong error code";
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display,
-                HWC2_POWER_MODE_DOZE_SUSPEND, &err));
-        EXPECT_EQ(err, HWC2_ERROR_UNSUPPORTED) <<  "returned wrong error code";
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 can set the same power mode multiple times. */
-TEST_F(Hwc2Test, SET_POWER_MODE_stress)
-{
-    for (auto display : mDisplays) {
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-
-        int32_t support = -1;
-        ASSERT_NO_FATAL_FAILURE(getDozeSupport(display, &support));
-        if (support != 1)
-            return;
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE));
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_DOZE));
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display,
-                HWC2_POWER_MODE_DOZE_SUSPEND));
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display,
-                HWC2_POWER_MODE_DOZE_SUSPEND));
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 can enable and disable vsync on active
- * displays */
-TEST_F(Hwc2Test, SET_VSYNC_ENABLED)
-{
-    for (auto display : mDisplays) {
-        hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
-                const_cast<char*>("data"));
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
-        ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data,
-                []() { return; }));
-
-        ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
-
-        ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 issues a valid vsync callback. */
-TEST_F(Hwc2Test, SET_VSYNC_ENABLED_callback)
-{
-    for (auto display : mDisplays) {
-        hwc2_display_t receivedDisplay;
-        int64_t receivedTimestamp;
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
-        ASSERT_NO_FATAL_FAILURE(enableVsync(display));
-
-        ASSERT_NO_FATAL_FAILURE(waitForVsync(&receivedDisplay,
-                &receivedTimestamp));
-
-        EXPECT_EQ(receivedDisplay, display) << "failed to get correct display";
-        EXPECT_GE(receivedTimestamp, 0) << "failed to get valid timestamp";
-
-        ASSERT_NO_FATAL_FAILURE(disableVsync(display));
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot enable a vsync for a bad display */
-TEST_F(Hwc2Test, SET_VSYNC_ENABLED_bad_display)
-{
-    hwc2_display_t display;
-    hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
-            const_cast<char*>("data"));
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data,
-            []() { return; }));
-
-    ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-
-    ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot enable an invalid vsync value */
-TEST_F(Hwc2Test, SET_VSYNC_ENABLED_bad_parameter)
-{
-    for (auto display : mDisplays) {
-        hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
-                const_cast<char*>("data"));
-        hwc2_error_t err = HWC2_ERROR_NONE;
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
-        ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data,
-                []() { return; }));
-
-        ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_INVALID,
-                &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 can enable and disable a vsync value multiple
- * times. */
-TEST_F(Hwc2Test, SET_VSYNC_ENABLED_stress)
-{
-    for (auto display : mDisplays) {
-        hwc2_callback_data_t data = reinterpret_cast<hwc2_callback_data_t>(
-                const_cast<char*>("data"));
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
-        ASSERT_NO_FATAL_FAILURE(registerCallback(HWC2_CALLBACK_VSYNC, data,
-                []() { return; }));
-
-        ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
-
-        ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
-        ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
-
-        ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
-        ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 can set a vsync enable value when the display
- * is off and no callback is registered. */
-TEST_F(Hwc2Test, SET_VSYNC_ENABLED_no_callback_no_power)
-{
-    const uint secs = 1;
-
-    for (auto display : mDisplays) {
-        ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
-
-        sleep(secs);
-
-        ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 can set a vsync enable value when no callback
- * is registered. */
-TEST_F(Hwc2Test, SET_VSYNC_ENABLED_no_callback)
-{
-    const uint secs = 1;
-
-    for (auto display : mDisplays) {
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
-        ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_ENABLE));
-
-        sleep(secs);
-
-        ASSERT_NO_FATAL_FAILURE(setVsyncEnabled(display, HWC2_VSYNC_DISABLE));
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 returns a display name for each display */
-TEST_F(Hwc2Test, GET_DISPLAY_NAME)
-{
-    for (auto display : mDisplays) {
-        std::string name;
-
-        ASSERT_NO_FATAL_FAILURE(getDisplayName(display, &name));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 does not return a display name for a bad
- * display */
-TEST_F(Hwc2Test, GET_DISPLAY_NAME_bad_display)
-{
-    hwc2_display_t display;
-    std::string name;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(getDisplayName(display, &name, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 can set basic composition types. */
-TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
-            setComposition, advanceComposition));
-}
-
-/* TESTCASE: Tests that the HWC2 can update a basic composition type on a
- * layer. */
-TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE_update)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
-            setComposition, advanceComposition));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a composition type for a bad layer */
-TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE_bad_layer)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
-            setComposition));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a bad composition type */
-TEST_F(Hwc2Test, SET_LAYER_COMPOSITION_TYPE_bad_parameter)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadParameter(
-            [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-                    hwc2_error_t* outErr) {
-
-                ASSERT_NO_FATAL_FAILURE(test->setLayerCompositionType(display,
-                        layer, HWC2_COMPOSITION_INVALID, outErr));
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the cursor position of a layer. */
-TEST_F(Hwc2Test, SET_CURSOR_POSITION)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
-            ::setCursorPosition, advanceCursorPosition));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the cursor position of a layer. */
-TEST_F(Hwc2Test, SET_CURSOR_POSITION_update)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
-            ::setCursorPosition, advanceCursorPosition));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the cursor position of a layer when the
- * composition type has not been set to HWC2_COMPOSITION_CURSOR. */
-TEST_F(Hwc2Test, SET_CURSOR_POSITION_composition_type_unset)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
-            [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-                    Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
-                const hwc_rect_t cursorPosition = testLayer->getCursorPosition();
-                EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display, layer,
-                        cursorPosition.left, cursorPosition.top, outErr));
-            },
-
-            advanceCursorPosition));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the cursor position of a bad
- * display. */
-TEST_F(Hwc2Test, SET_CURSOR_POSITION_bad_display)
-{
-    hwc2_display_t display;
-    hwc2_layer_t layer = 0;
-    int32_t x = 0, y = 0;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(setCursorPosition(display, layer, x, y, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the cursor position of a bad layer. */
-TEST_F(Hwc2Test, SET_CURSOR_POSITION_bad_layer)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
-            [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer,
-                    Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
-
-                const hwc_rect_t cursorPosition = testLayer->getCursorPosition();
-                EXPECT_NO_FATAL_FAILURE(test->setCursorPosition(display,
-                        badLayer, cursorPosition.left, cursorPosition.top,
-                        outErr));
-            }
-   ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set a blend mode value of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
-            setBlendMode, advanceBlendMode));
-}
-
-/* TESTCASE: Tests that the HWC2 can update a blend mode value of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE_update)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
-            setBlendMode, advanceBlendMode));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a blend mode for a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE_bad_layer)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
-            setBlendMode));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an invalid blend mode. */
-TEST_F(Hwc2Test, SET_LAYER_BLEND_MODE_bad_parameter)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadParameter(
-            [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-                    hwc2_error_t* outErr) {
-
-                ASSERT_NO_FATAL_FAILURE(test->setLayerBlendMode(display,
-                        layer, HWC2_BLEND_MODE_INVALID, outErr));
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the buffer of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_BUFFER)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
-            setBuffer, advanceBuffer));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the buffer of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_BUFFER_update)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
-            setBuffer, advanceBuffer));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the buffer of a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_BUFFER_bad_layer)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
-            [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer,
-                    Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
-
-                buffer_handle_t handle = nullptr;
-                android::base::unique_fd acquireFence;
-
-                /* If there is not available buffer for the given buffer
-                 * properties, it should not fail this test case */
-                if (testLayer->getBuffer(&handle, &acquireFence) == 0) {
-                    *outErr = HWC2_ERROR_BAD_LAYER;
-                    return;
-                }
-
-                ASSERT_NO_FATAL_FAILURE(test->setLayerBuffer(display, badLayer,
-                        handle, acquireFence, outErr));
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set an invalid buffer for a layer. */
-TEST_F(Hwc2Test, SET_LAYER_BUFFER_bad_parameter)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadParameter(
-            [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-                    hwc2_error_t* outErr) {
-
-                buffer_handle_t handle = nullptr;
-                int32_t acquireFence = -1;
-
-                ASSERT_NO_FATAL_FAILURE(test->setLayerBuffer(display, layer,
-                        handle, acquireFence, outErr));
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the color of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_COLOR)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
-            setColor, advanceColor));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the color of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_COLOR_update)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
-            setColor, advanceColor));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the color of a layer when the
- * composition type has not been set to HWC2_COMPOSITION_SOLID_COLOR. */
-TEST_F(Hwc2Test, SET_LAYER_COLOR_composition_type_unset)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Basic,
-            [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-                    Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
-
-                EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, layer,
-                        testLayer->getColor(), outErr));
-            },
-
-            advanceColor));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the color of a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_COLOR_bad_layer)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
-            [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer,
-                    Hwc2TestLayer* testLayer, hwc2_error_t* outErr) {
-
-                EXPECT_NO_FATAL_FAILURE(test->setLayerColor(display, badLayer,
-                        testLayer->getColor(), outErr));
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the dataspace of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_DATASPACE)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
-            setDataspace, advanceDataspace));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the dataspace of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_DATASPACE_update)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
-            setDataspace, advanceDataspace));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a dataspace for a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_DATASPACE_bad_layer)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
-            setDataspace));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the display frame of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_DISPLAY_FRAME)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
-            setDisplayFrame, advanceDisplayFrame));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the display frame of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_DISPLAY_FRAME_update)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
-            setDisplayFrame, advanceDisplayFrame));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the display frame of a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_DISPLAY_FRAME_bad_layer)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
-            setDisplayFrame));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the plane alpha of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_PLANE_ALPHA)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
-            setPlaneAlpha, advancePlaneAlpha));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the plane alpha of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_PLANE_ALPHA_update)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
-            setPlaneAlpha, advancePlaneAlpha));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a plane alpha for a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_PLANE_ALPHA_bad_layer)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
-            [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t badLayer,
-                    Hwc2TestLayer* testLayer, hwc2_error_t *outErr) {
-
-                    EXPECT_NO_FATAL_FAILURE(test->setLayerPlaneAlpha(display,
-                            badLayer, testLayer->getPlaneAlpha(), outErr));
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the source crop of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_SOURCE_CROP)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
-            setSourceCrop, advanceSourceCrop));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the source crop of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_SOURCE_CROP_update)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
-            setSourceCrop, advanceSourceCrop));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the source crop of a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_SOURCE_CROP_bad_layer)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
-            setSourceCrop));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the surface damage of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_SURFACE_DAMAGE)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
-            setSurfaceDamage, advanceSurfaceDamage));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the surface damage of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_SURFACE_DAMAGE_update)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
-            setSurfaceDamage, advanceSurfaceDamage));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the surface damage of a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_SURFACE_DAMAGE_bad_layer)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
-            setSurfaceDamage));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the transform value of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_TRANSFORM)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperty(Hwc2TestCoverage::Complete,
-            setTransform, advanceTransform));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the transform value of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_TRANSFORM_update)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyUpdate(Hwc2TestCoverage::Complete,
-            setTransform, advanceTransform));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the transform for a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_TRANSFORM_bad_layer)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
-            setTransform));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the visible region of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_VISIBLE_REGION)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperties(Hwc2TestCoverage::Basic, 5,
-            [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-                    Hwc2TestLayers* testLayers) {
-
-                EXPECT_NO_FATAL_FAILURE(test->setLayerVisibleRegion(display,
-                        layer, testLayers->getVisibleRegion(layer)));
-            },
-
-            advanceVisibleRegions));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the visible region of a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_VISIBLE_REGION_bad_layer)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
-            setVisibleRegion));
-}
-
-/* TESTCASE: Tests that the HWC2 can set the z order of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_Z_ORDER)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerProperties(Hwc2TestCoverage::Complete, 10,
-            [] (Hwc2Test* test, hwc2_display_t display, hwc2_layer_t layer,
-                    Hwc2TestLayers* testLayers) {
-
-                EXPECT_NO_FATAL_FAILURE(test->setLayerZOrder(display, layer,
-                        testLayers->getZOrder(layer)));
-            },
-
-            /* TestLayer z orders are set during the construction of TestLayers
-             * and cannot be updated. There is no need (or ability) to cycle
-             * through additional z order configurations. */
-            [] (Hwc2TestLayers* /*testLayers*/) {
-                return false;
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 can update the z order of a layer. */
-TEST_F(Hwc2Test, SET_LAYER_Z_ORDER_update)
-{
-    const std::vector<uint32_t> zOrders = { static_cast<uint32_t>(0),
-            static_cast<uint32_t>(1), static_cast<uint32_t>(UINT32_MAX / 4),
-            static_cast<uint32_t>(UINT32_MAX / 2),
-            static_cast<uint32_t>(UINT32_MAX) };
-
-    for (auto display : mDisplays) {
-        std::vector<hwc2_config_t> configs;
-
-        ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-        for (auto config : configs) {
-            hwc2_layer_t layer;
-
-            ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-
-            ASSERT_NO_FATAL_FAILURE(createLayer(display, &layer));
-
-            for (uint32_t zOrder : zOrders) {
-                EXPECT_NO_FATAL_FAILURE(setLayerZOrder(display, layer, zOrder));
-            }
-
-            ASSERT_NO_FATAL_FAILURE(destroyLayer(display, layer));
-        }
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the z order of a bad layer. */
-TEST_F(Hwc2Test, SET_LAYER_Z_ORDER_bad_layer)
-{
-    ASSERT_NO_FATAL_FAILURE(setLayerPropertyBadLayer(Hwc2TestCoverage::Default,
-            setZOrder));
-}
-
-/* TESTCASE: Tests that the HWC2 can display a layer with basic property
- * coverage */
-TEST_F(Hwc2Test, VALIDATE_DISPLAY_basic)
-{
-    ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1,
-            [] (Hwc2Test* test, hwc2_display_t display,
-                    const std::vector<hwc2_layer_t>& layers,
-                    Hwc2TestLayers* /*testLayers*/) {
-
-                uint32_t numTypes, numRequests;
-                bool hasChanges = false;
-
-                EXPECT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
-                        &numRequests, &hasChanges));
-                if (hasChanges)
-                    EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size()))
-                            << "wrong number of requests";
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 can display 5 layers with default coverage. */
-TEST_F(Hwc2Test, VALIDATE_DISPLAY_default_5)
-{
-    ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Default, 5,
-            [] (Hwc2Test* test, hwc2_display_t display,
-                    const std::vector<hwc2_layer_t>& layers,
-                    Hwc2TestLayers* /*testLayers*/) {
-
-                uint32_t numTypes, numRequests;
-                bool hasChanges = false;
-
-                EXPECT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
-                        &numRequests, &hasChanges));
-                if (hasChanges)
-                    EXPECT_LE(numTypes, static_cast<uint32_t>(layers.size()))
-                            << "wrong number of requests";
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot validate a bad display */
-TEST_F(Hwc2Test, VALIDATE_DISPLAY_bad_display)
-{
-    hwc2_display_t display;
-    uint32_t numTypes, numRequests;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes, &numRequests,
-            &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 can get display requests after validating a
- * basic layer. */
-TEST_F(Hwc2Test, GET_DISPLAY_REQUESTS_basic)
-{
-    ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1,
-            [] (Hwc2Test* test, hwc2_display_t display,
-                    const std::vector<hwc2_layer_t>& layers,
-                    Hwc2TestLayers* /*testLayers*/) {
-
-                uint32_t numTypes, numRequests;
-                bool hasChanges = false;
-
-                ASSERT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
-                        &numRequests, &hasChanges));
-                if (hasChanges)
-                    EXPECT_LE(numTypes, layers.size())
-                            << "wrong number of requests";
-
-                EXPECT_NO_FATAL_FAILURE(test->handleRequests(display, layers,
-                        numRequests));
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get display requests from a bad display */
-TEST_F(Hwc2Test, GET_DISPLAY_REQUESTS_bad_display)
-{
-    hwc2_display_t display;
-    hwc2_display_request_t displayRequests;
-    std::vector<hwc2_layer_t> layers;
-    std::vector<hwc2_layer_request_t> layerRequests;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    EXPECT_NO_FATAL_FAILURE(getDisplayRequests(display, &displayRequests,
-            &layers, &layerRequests, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get display requests from an non
- * validated display. */
-TEST_F(Hwc2Test, GET_DISPLAY_REQUESTS_not_validated)
-{
-    ASSERT_NO_FATAL_FAILURE(displayNonValidatedLayers(5,
-            [] (Hwc2Test* test, hwc2_display_t display,
-                    std::vector<hwc2_layer_t>* layers) {
-
-                hwc2_display_request_t displayRequests;
-                std::vector<hwc2_layer_request_t> layerRequests;
-                hwc2_error_t err = HWC2_ERROR_NONE;
-
-                ASSERT_NO_FATAL_FAILURE(test->getDisplayRequests(display,
-                        &displayRequests, layers, &layerRequests, &err));
-                EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED)
-                        << "returned wrong error code";
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 can get changed composition types after
- * validating a basic layer. */
-TEST_F(Hwc2Test, GET_CHANGED_COMPOSITION_TYPES_basic)
-{
-    ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1,
-            [] (Hwc2Test* test, hwc2_display_t display,
-                    const std::vector<hwc2_layer_t>& layers,
-                    Hwc2TestLayers* testLayers) {
-
-                uint32_t numTypes, numRequests;
-                bool hasChanges = false;
-
-                ASSERT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
-                        &numRequests, &hasChanges));
-                if (hasChanges)
-                    EXPECT_LE(numTypes, layers.size())
-                            << "wrong number of requests";
-
-                EXPECT_NO_FATAL_FAILURE(test->handleCompositionChanges(display,
-                        *testLayers, layers, numTypes));
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get changed composition types from a bad
- * display */
-TEST_F(Hwc2Test, GET_CHANGED_COMPOSITION_TYPES_bad_display)
-{
-    hwc2_display_t display;
-    std::vector<hwc2_layer_t> layers;
-    std::vector<hwc2_composition_t> types;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    EXPECT_NO_FATAL_FAILURE(getChangedCompositionTypes(display, &layers,
-            &types, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get changed composition types from an non
- * validated display. */
-TEST_F(Hwc2Test, GET_CHANGED_COMPOSITION_TYPES_not_validated)
-{
-    ASSERT_NO_FATAL_FAILURE(displayNonValidatedLayers(5,
-            [] (Hwc2Test* test, hwc2_display_t display,
-                    std::vector<hwc2_layer_t>* layers) {
-
-                std::vector<hwc2_composition_t> types;
-                hwc2_error_t err = HWC2_ERROR_NONE;
-
-                ASSERT_NO_FATAL_FAILURE(test->getChangedCompositionTypes(
-                        display, layers, &types, &err));
-                EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED)
-                        << "returned wrong error code";
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 can accept display changes after validating a
- * basic layer. */
-TEST_F(Hwc2Test, ACCEPT_DISPLAY_CHANGES_basic)
-{
-    ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Basic, 1,
-            [] (Hwc2Test* test, hwc2_display_t display,
-                    const std::vector<hwc2_layer_t>& layers,
-                    Hwc2TestLayers* testLayers) {
-
-                uint32_t numTypes, numRequests;
-                bool hasChanges = false;
-
-                ASSERT_NO_FATAL_FAILURE(test->validateDisplay(display, &numTypes,
-                        &numRequests, &hasChanges));
-                if (hasChanges)
-                    EXPECT_LE(numTypes, layers.size())
-                            << "wrong number of requests";
-
-                ASSERT_NO_FATAL_FAILURE(test->handleCompositionChanges(display,
-                        *testLayers, layers, numTypes));
-
-                EXPECT_NO_FATAL_FAILURE(test->acceptDisplayChanges(display));
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot accept display changes from a bad
- * display */
-TEST_F(Hwc2Test, ACCEPT_DISPLAY_CHANGES_bad_display)
-{
-    hwc2_display_t display;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    EXPECT_NO_FATAL_FAILURE(acceptDisplayChanges(display, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot accept display changes from an non
- * validated display. */
-TEST_F(Hwc2Test, ACCEPT_DISPLAY_CHANGES_not_validated)
-{
-    ASSERT_NO_FATAL_FAILURE(displayNonValidatedLayers(5,
-            [] (Hwc2Test* test, hwc2_display_t display,
-                    std::vector<hwc2_layer_t>* /*layers*/) {
-
-                hwc2_error_t err = HWC2_ERROR_NONE;
-
-                ASSERT_NO_FATAL_FAILURE(test->acceptDisplayChanges(display, &err));
-                EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED)
-                        << "returned wrong error code";
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 supports client target with required values */
-TEST_F(Hwc2Test, GET_CLIENT_TARGET_SUPPORT)
-{
-    ASSERT_NO_FATAL_FAILURE(setClientTargetSupport(Hwc2TestCoverage::Default,
-            [] (Hwc2Test* test, hwc2_display_t display,
-                    const Hwc2TestClientTargetSupport& testClientTargetSupport) {
-
-                const Area bufferArea = testClientTargetSupport.getBufferArea();
-                const android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888;
-
-                ASSERT_NO_FATAL_FAILURE(test->getClientTargetSupport(display,
-                        bufferArea.width, bufferArea.height, format,
-                        testClientTargetSupport.getDataspace()));
-            },
-
-            advanceClientTargetSupport));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get client target support for a bad
- * display. */
-TEST_F(Hwc2Test, GET_CLIENT_TARGET_SUPPORT_bad_display)
-{
-    ASSERT_NO_FATAL_FAILURE(setClientTargetSupport(Hwc2TestCoverage::Default,
-            [] (Hwc2Test* test, hwc2_display_t /*display*/,
-                    const Hwc2TestClientTargetSupport& testClientTargetSupport) {
-
-                const Area bufferArea = testClientTargetSupport.getBufferArea();
-                const android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888;
-                hwc2_display_t badDisplay;
-                hwc2_error_t err = HWC2_ERROR_NONE;
-
-                ASSERT_NO_FATAL_FAILURE(test->getBadDisplay(&badDisplay));
-
-                ASSERT_NO_FATAL_FAILURE(test->getClientTargetSupport(badDisplay,
-                        bufferArea.width, bufferArea.height, format,
-                        testClientTargetSupport.getDataspace(), &err));
-                EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-            },
-
-            advanceClientTargetSupport));
-}
-
-/* TESTCASE: Tests that the HWC2 either supports or returns error unsupported
- * for a variety of client target values. */
-TEST_F(Hwc2Test, GET_CLIENT_TARGET_SUPPORT_unsupported)
-{
-    ASSERT_NO_FATAL_FAILURE(setClientTargetSupport(Hwc2TestCoverage::Complete,
-            [] (Hwc2Test* test, hwc2_display_t display,
-                    const Hwc2TestClientTargetSupport& testClientTargetSupport) {
-
-                const Area bufferArea = testClientTargetSupport.getBufferArea();
-                const android_pixel_format_t format = HAL_PIXEL_FORMAT_RGBA_8888;
-                hwc2_error_t err = HWC2_ERROR_NONE;
-
-                ASSERT_NO_FATAL_FAILURE(test->getClientTargetSupport(display,
-                        bufferArea.width, bufferArea.height, format,
-                        testClientTargetSupport.getDataspace(), &err));
-                EXPECT_TRUE(err == HWC2_ERROR_NONE
-                        || err == HWC2_ERROR_UNSUPPORTED)
-                        << "returned wrong error code";
-            },
-
-            advanceClientTargetSupport));
-}
-
-/* TESTCASE: Tests that the HWC2 can set a client target buffer for a basic
- * layer. */
-TEST_F(Hwc2Test, SET_CLIENT_TARGET_basic)
-{
-    const Dataspace dataspace = Dataspace::UNKNOWN;
-    const hwc_region_t damage = { };
-    const size_t layerCnt = 1;
-
-    for (auto display : mDisplays) {
-        std::vector<hwc2_config_t> configs;
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_ON));
-
-        ASSERT_NO_FATAL_FAILURE(getDisplayConfigs(display, &configs));
-
-        for (auto config : configs) {
-            Area displayArea;
-            std::vector<hwc2_layer_t> layers;
-
-            ASSERT_NO_FATAL_FAILURE(setActiveConfig(display, config));
-            ASSERT_NO_FATAL_FAILURE(getActiveDisplayArea(display, &displayArea));
-
-            ASSERT_NO_FATAL_FAILURE(createLayers(display, &layers, layerCnt));
-            Hwc2TestLayers testLayers(layers, Hwc2TestCoverage::Basic,
-                    displayArea);
-
-            if (!testLayers.optimizeLayouts())
-                continue;
-
-            Hwc2TestClientTarget testClientTarget;
-
-            do {
-                std::set<hwc2_layer_t> clientLayers;
-                std::set<hwc2_layer_t> clearLayers;
-                uint32_t numTypes, numRequests;
-                bool hasChanges, skip;
-                bool flipClientTarget;
-                buffer_handle_t handle;
-                int32_t acquireFence;
-
-                ASSERT_NO_FATAL_FAILURE(setLayerProperties(display, layers,
-                        &testLayers, &skip));
-                if (skip)
-                    continue;
-
-                ASSERT_NO_FATAL_FAILURE(validateDisplay(display, &numTypes,
-                        &numRequests, &hasChanges));
-                if (hasChanges)
-                    EXPECT_LE(numTypes, layers.size())
-                            << "wrong number of requests";
-
-                ASSERT_NO_FATAL_FAILURE(handleCompositionChanges(display,
-                        testLayers, layers, numTypes, &clientLayers));
-                ASSERT_NO_FATAL_FAILURE(handleRequests(display, layers,
-                        numRequests, &clearLayers, &flipClientTarget));
-                ASSERT_EQ(testClientTarget.getBuffer(testLayers, clientLayers,
-                        clearLayers, flipClientTarget, displayArea, &handle,
-                        &acquireFence), 0);
-                EXPECT_NO_FATAL_FAILURE(setClientTarget(display, handle,
-                        acquireFence, dataspace, damage));
-
-                if (acquireFence >= 0)
-                    close(acquireFence);
-
-            } while (testLayers.advance());
-
-            ASSERT_NO_FATAL_FAILURE(destroyLayers(display, std::move(layers)));
-        }
-
-        ASSERT_NO_FATAL_FAILURE(setPowerMode(display, HWC2_POWER_MODE_OFF));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a client target for a bad display. */
-TEST_F(Hwc2Test, SET_CLIENT_TARGET_bad_display)
-{
-    hwc2_display_t display;
-    std::vector<hwc2_layer_t> layers;
-    const Area displayArea = {0, 0};
-    Hwc2TestLayers testLayers(layers, Hwc2TestCoverage::Default, displayArea);
-    std::set<hwc2_layer_t> clientLayers;
-    std::set<hwc2_layer_t> flipClientTargetLayers;
-    bool flipClientTarget = true;
-    const Dataspace dataspace = Dataspace::UNKNOWN;
-    const hwc_region_t damage = { };
-    buffer_handle_t handle;
-    int32_t acquireFence;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    Hwc2TestClientTarget testClientTarget;
-
-    ASSERT_EQ(testClientTarget.getBuffer(testLayers, clientLayers,
-            flipClientTargetLayers, flipClientTarget, displayArea, &handle,
-            &acquireFence), 0);
-
-    EXPECT_NO_FATAL_FAILURE(setClientTarget(display, handle, acquireFence,
-            dataspace, damage, &err));
-
-    if (acquireFence >= 0)
-        close(acquireFence);
-
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 default layer. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_default_1)
-{
-    const size_t layerCnt = 1;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
-    bool optimize = false;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 default layers. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_default_2)
-{
-    const size_t layerCnt = 2;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
-    bool optimize = false;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 3 default layers. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_default_3)
-{
-    const size_t layerCnt = 3;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
-    bool optimize = false;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 4 default layers. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_default_4)
-{
-    const size_t layerCnt = 4;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
-    bool optimize = false;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 5 default layers. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_default_5)
-{
-    const size_t layerCnt = 5;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
-    bool optimize = false;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 6 default layers. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_default_6)
-{
-    const size_t layerCnt = 6;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
-    bool optimize = false;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * blend mode. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_blend_mode_1)
-{
-    const size_t layerCnt = 1;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Complete},
-            {Hwc2TestPropertyName::Transform, Hwc2TestCoverage::Basic},
-            {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Basic}};
-    bool optimize = false;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
- * blend mode. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_blend_mode_2)
-{
-    const size_t layerCnt = 2;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Complete},
-            {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Basic}};
-    bool optimize = false;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * buffer. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_buffer_1)
-{
-    const size_t layerCnt = 1;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::BufferArea, Hwc2TestCoverage::Complete}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * color. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_color_1)
-{
-    const size_t layerCnt = 1;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete},
-            {Hwc2TestPropertyName::Color, Hwc2TestCoverage::Complete}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
- * color. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_color_2)
-{
-    const size_t layerCnt = 2;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete},
-            {Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Basic},
-            {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Basic},
-            {Hwc2TestPropertyName::Color, Hwc2TestCoverage::Basic}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * composition. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_composition_1)
-{
-    const size_t layerCnt = 1;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * cursor. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_cursor_1)
-{
-    const size_t layerCnt = 1;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete},
-            {Hwc2TestPropertyName::CursorPosition, Hwc2TestCoverage::Complete}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
- * cursor. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_cursor_2)
-{
-    const size_t layerCnt = 2;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::Composition, Hwc2TestCoverage::Complete},
-            {Hwc2TestPropertyName::CursorPosition, Hwc2TestCoverage::Complete},
-            {Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Basic}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * dataspace. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_dataspace_1)
-{
-    const size_t layerCnt = 1;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::Dataspace, Hwc2TestCoverage::Complete}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * display frame. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_1)
-{
-    const size_t layerCnt = 1;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
- * display frame. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_2)
-{
-    const size_t layerCnt = 2;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 3 layers with complete coverage of
- * display frame. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_3)
-{
-    const size_t layerCnt = 3;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 4 layers with complete coverage of
- * display frame. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_display_frame_4)
-{
-    const size_t layerCnt = 4;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * plane alpha. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_plane_alpha_1)
-{
-    const size_t layerCnt = 1;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Basic},
-            {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Complete}};
-    bool optimize = false;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
- * plane alpha. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_plane_alpha_2)
-{
-    const size_t layerCnt = 2;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::BlendMode, Hwc2TestCoverage::Basic},
-            {Hwc2TestPropertyName::PlaneAlpha, Hwc2TestCoverage::Complete}};
-    bool optimize = false;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * source crop. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_source_crop_1)
-{
-    const size_t layerCnt = 1;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete},
-            {Hwc2TestPropertyName::SourceCrop, Hwc2TestCoverage::Complete}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
- * source crop. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_source_crop_2)
-{
-    const size_t layerCnt = 2;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Complete},
-            {Hwc2TestPropertyName::SourceCrop, Hwc2TestCoverage::Complete}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * surface damage. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_surface_damage_1)
-{
-    const size_t layerCnt = 1;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::SurfaceDamage, Hwc2TestCoverage::Complete}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * transform. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_transform_1)
-{
-    const size_t layerCnt = 1;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::Transform, Hwc2TestCoverage::Complete}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with complete coverage of
- * transform. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_transform_2)
-{
-    const size_t layerCnt = 2;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions =
-            {{Hwc2TestPropertyName::Transform, Hwc2TestCoverage::Complete},
-            {Hwc2TestPropertyName::DisplayFrame, Hwc2TestCoverage::Basic}};
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with complete coverage of
- * basic. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_basic_1)
-{
-    const size_t layerCnt = 1;
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Basic;
-    std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage> exceptions;
-    bool optimize = true;
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplays(layerCnt, coverage, exceptions,
-            optimize));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot present a bad display.  */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_bad_display)
-{
-    hwc2_display_t display;
-    int32_t presentFence;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(presentDisplay(display, &presentFence, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot present an unvalidated display. */
-TEST_F(Hwc2Test, PRESENT_DISPLAY_not_validated)
-{
-    ASSERT_NO_FATAL_FAILURE(displayLayers(Hwc2TestCoverage::Default, 1,
-            [] (Hwc2Test* test, hwc2_display_t display,
-                    const std::vector<hwc2_layer_t>& /*layers*/,
-                    Hwc2TestLayers* /*testLayers*/) {
-
-                int32_t presentFence;
-                hwc2_error_t err = HWC2_ERROR_NONE;
-
-                ASSERT_NO_FATAL_FAILURE(test->setPowerMode(display,
-                        HWC2_POWER_MODE_ON));
-                ASSERT_NO_FATAL_FAILURE(test->enableVsync(display));
-
-                ASSERT_NO_FATAL_FAILURE(test->waitForVsync());
-
-                ASSERT_NO_FATAL_FAILURE(test->presentDisplay(display,
-                        &presentFence, &err));
-                EXPECT_EQ(err, HWC2_ERROR_NOT_VALIDATED)
-                        << "returned wrong error code";
-
-                ASSERT_NO_FATAL_FAILURE(test->disableVsync(display));
-                ASSERT_NO_FATAL_FAILURE(test->setPowerMode(display,
-                        HWC2_POWER_MODE_OFF));
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get release fences from a bad display. */
-TEST_F(Hwc2Test, GET_RELEASE_FENCES_bad_display)
-{
-    hwc2_display_t display;
-    std::vector<hwc2_layer_t> layers;
-    std::vector<int32_t> fences;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(getReleaseFences(display, &layers, &fences, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-static const std::array<ColorMode, 9> androidColorModes = {{
-    ColorMode::NATIVE,
-    ColorMode::STANDARD_BT601_625,
-    ColorMode::STANDARD_BT601_625_UNADJUSTED,
-    ColorMode::STANDARD_BT601_525,
-    ColorMode::STANDARD_BT601_525_UNADJUSTED,
-    ColorMode::STANDARD_BT709,
-    ColorMode::DCI_P3,
-    ColorMode::SRGB,
-    ColorMode::ADOBE_RGB,
-}};
-
-/* TESTCASE: Tests that the HWC2 can get the color modes for a display. The
- * display must support ColorMode::NATIVE */
-TEST_F(Hwc2Test, GET_COLOR_MODES)
-{
-    ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
-            [] (Hwc2Test* test, hwc2_display_t display) {
-
-                std::vector<ColorMode> colorModes;
-
-                ASSERT_NO_FATAL_FAILURE(test->getColorModes(display,
-                        &colorModes));
-
-                EXPECT_NE(std::count(colorModes.begin(), colorModes.end(),
-                        ColorMode::NATIVE), 0) << "all displays"
-                        " must support ColorMode::NATIVE";
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get color modes from a bad display. */
-TEST_F(Hwc2Test, GET_COLOR_MODES_bad_display)
-{
-    hwc2_display_t display;
-    std::vector<ColorMode> colorModes;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(getColorModes(display, &colorModes, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 can set the required color mode on a display. */
-TEST_F(Hwc2Test, SET_COLOR_MODES)
-{
-    ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
-            [] (Hwc2Test* test, hwc2_display_t display) {
-
-                const ColorMode colorMode = ColorMode::NATIVE;
-
-                EXPECT_NO_FATAL_FAILURE(test->setColorMode(display, colorMode));
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set a color mode on a bad display. */
-TEST_F(Hwc2Test, SET_COLOR_MODES_bad_display)
-{
-    hwc2_display_t display;
-    const ColorMode colorMode = ColorMode::NATIVE;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(setColorMode(display, colorMode, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an invalid color mode. */
-TEST_F(Hwc2Test, SET_COLOR_MODES_bad_parameter)
-{
-    ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
-            [] (Hwc2Test* test, hwc2_display_t display) {
-
-                const ColorMode colorMode = static_cast<ColorMode>(-1);
-                hwc2_error_t err = HWC2_ERROR_NONE;
-
-                ASSERT_NO_FATAL_FAILURE(test->setColorMode(display, colorMode,
-                        &err));
-                EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER)
-                        << "returned wrong error code";
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 either supports or returns error unsupported
- * for all valid color modes. */
-TEST_F(Hwc2Test, SET_COLOR_MODES_unsupported)
-{
-    ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
-            [] (Hwc2Test* test, hwc2_display_t display) {
-
-                for (auto colorMode : androidColorModes) {
-                    hwc2_error_t err = HWC2_ERROR_NONE;
-
-                    ASSERT_NO_FATAL_FAILURE(test->setColorMode(display,
-                            colorMode, &err));
-
-                    EXPECT_TRUE(err == HWC2_ERROR_NONE
-                            || err == HWC2_ERROR_UNSUPPORTED)
-                            << "returned wrong error code";
-                }
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 gets the HDR capabilities for a display and
- * test if they are valid. */
-TEST_F(Hwc2Test, GET_HDR_CAPABILITIES)
-{
-    ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
-            [] (Hwc2Test* test, hwc2_display_t display) {
-
-                std::vector<android_hdr_t> hdrCapabilities;
-                float maxLuminance, maxAverageLuminance, minLuminance;
-
-                EXPECT_NO_FATAL_FAILURE(test->getHdrCapabilities(display,
-                        &hdrCapabilities, &maxLuminance, &maxAverageLuminance,
-                        &minLuminance));
-
-                if (hdrCapabilities.empty())
-                    return;
-
-                EXPECT_GE(maxLuminance, maxAverageLuminance);
-                EXPECT_GE(maxAverageLuminance, minLuminance);
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot get hdr capabilities from a bad display */
-TEST_F(Hwc2Test, GET_HDR_CAPABILITIES_bad_display)
-{
-    hwc2_display_t display;
-    std::vector<android_hdr_t> hdrCapabilities;
-    float maxLuminance, maxAverageLuminance, minLuminance;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(getHdrCapabilities(display, &hdrCapabilities,
-            &maxLuminance, &maxAverageLuminance, &minLuminance, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-static const std::array<float, 16> identityMatrix = {{
-    1.0,  0.0,  0.0,  0.0,
-    0.0,  1.0,  0.0,  0.0,
-    0.0,  0.0,  1.0,  0.0,
-    0.0,  0.0,  0.0,  1.0,
-}};
-
-/* Values for the color transform matrices were precomputed using the source code
- * in surfaceflinger/Effects/Daltonizer.cpp. */
-
-static const std::array<const std::array<float, 16>, 5> exampleMatrices = {{
-    identityMatrix,
-    /* Converts RGB color to the XYZ space */
-    {{ 0.4124, 0.2126, 0.0193, 0,
-       0.3576, 0.7152, 0.1192, 0,
-       0.1805, 0.0722, 0.9505, 0,
-       0     , 0     , 0     , 1 }},
-    /* Protanomaly */
-    {{ 0.068493,  0.931506,  0,  0,
-       0.068493,  0.931507,  0,  0,
-       0.013626, -0.013626,  1,  0,
-       0,         0,         0,  1 }},
-    /* Deuteranomaly */
-    {{ 0.288299, 0.711701,  0,  0,
-       0.052709, 0.947291,  0,  0,
-      -0.257912, 0.257912,  1,  0,
-       0,        0,         0,  1 }},
-    /* Tritanomaly */
-    {{ 1, -0.805712, 0.805712,  0,
-       0,  0.378838, 0.621162,  0,
-       0,  0.104823, 0.895177,  0,
-       0,  0,        0,         1 }},
-}};
-
-/* TESTCASE: Tests that the HWC2 can set the identity color transform */
-TEST_F(Hwc2Test, SET_COLOR_TRANSFORM)
-{
-    ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
-            [] (Hwc2Test* test, hwc2_display_t display) {
-
-                EXPECT_NO_FATAL_FAILURE(test->setColorTransform(display,
-                        identityMatrix, HAL_COLOR_TRANSFORM_IDENTITY));
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set the color transform for a bad
- * display. */
-TEST_F(Hwc2Test, SET_COLOR_TRANSFORM_bad_display)
-{
-    hwc2_display_t display;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(setColorTransform(display, identityMatrix,
-            HAL_COLOR_TRANSFORM_IDENTITY, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an invalid color transform. */
-TEST_F(Hwc2Test, SET_COLOR_TRANSFORM_bad_parameter)
-{
-    ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
-            [] (Hwc2Test* test, hwc2_display_t display) {
-
-                const android_color_transform_t hint =
-                        static_cast<android_color_transform_t>(-1);
-                hwc2_error_t err = HWC2_ERROR_NONE;
-
-                ASSERT_NO_FATAL_FAILURE(test->setColorTransform(display,
-                        identityMatrix, hint, &err));
-                EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER)
-                        << "returned wrong error code";
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 can set an arbitrary color matrix. */
-TEST_F(Hwc2Test, SET_COLOR_TRANSFORM_arbitrary_matrix)
-{
-    ASSERT_NO_FATAL_FAILURE(setActiveDisplayConfig(
-            [] (Hwc2Test* test, hwc2_display_t display) {
-
-                const android_color_transform_t hint =
-                        HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
-
-                for (const std::array<float, 16>& matrix : exampleMatrices) {
-                    EXPECT_NO_FATAL_FAILURE(test->setColorTransform(display,
-                            matrix, hint));
-                }
-            }
-    ));
-}
-
-/* TESTCASE: Tests that the HWC2 create an destory virtual displays. */
-TEST_F(Hwc2Test, CREATE_DESTROY_VIRTUAL_DISPLAY)
-{
-    ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Complete,
-            [] (Hwc2Test* /*test*/, hwc2_display_t /*display*/,
-                    Hwc2TestVirtualDisplay* /*testVirtualDisplay*/) { }));
-}
-
-/* TESTCASE: Tests that the HWC2 can create and destroy multiple virtual
- * displays. */
-TEST_F(Hwc2Test, CREATE_DESTROY_VIRTUAL_DISPLAY_multiple)
-{
-    Hwc2TestVirtualDisplay testVirtualDisplay(Hwc2TestCoverage::Complete);
-    std::vector<hwc2_display_t> displays;
-
-    do {
-        const UnsignedArea& dimension =
-                testVirtualDisplay.getDisplayDimension();
-        android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-        hwc2_display_t display;
-        hwc2_error_t err = HWC2_ERROR_NONE;
-
-        ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(dimension.width,
-                dimension.height, &desiredFormat, &display, &err));
-
-        EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_NO_RESOURCES
-                || err == HWC2_ERROR_UNSUPPORTED) << "returned wrong error code";
-        EXPECT_GE(desiredFormat, 0) << "invalid format";
-
-        if (err == HWC2_ERROR_NONE)
-            displays.push_back(display);
-
-    } while (testVirtualDisplay.advance());
-
-    for (hwc2_display_t display : displays) {
-        EXPECT_NO_FATAL_FAILURE(destroyVirtualDisplay(display));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 cannot destroy a bad virtual displays.  */
-TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_display)
-{
-    hwc2_display_t display;
-    hwc2_error_t err = HWC2_ERROR_NONE;
-
-    ASSERT_NO_FATAL_FAILURE(getBadDisplay(&display));
-
-    ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err));
-    EXPECT_EQ(err, HWC2_ERROR_BAD_DISPLAY) << "returned wrong error code";
-}
-
-/* TESTCASE: Tests that the HWC2 cannot destroy a physical display. */
-TEST_F(Hwc2Test, DESTROY_VIRTUAL_DISPLAY_bad_parameter)
-{
-    hwc2_error_t err = HWC2_ERROR_NONE;
-    for (auto display : mDisplays) {
-        ASSERT_NO_FATAL_FAILURE(destroyVirtualDisplay(display, &err));
-        EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER) << "returned wrong error code";
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 can get the max virtual display count. */
-TEST_F(Hwc2Test, GET_MAX_VIRTUAL_DISPLAY_COUNT)
-{
-    uint32_t maxCnt;
-
-    ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt));
-}
-
-/* TESTCASE: Tests that the HWC2 returns the same max virtual display count for
- * each call. */
-TEST_F(Hwc2Test, GET_MAX_VIRTUAL_DISPLAY_COUNT_duplicate)
-{
-    uint32_t maxCnt1, maxCnt2;
-
-    ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt1));
-    ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt2));
-
-    EXPECT_EQ(maxCnt1, maxCnt2) << "returned two different max virtual display"
-            " counts";
-}
-
-/* TESTCASE: Tests that the HWC2 can create the max number of virtual displays
- * that it reports. */
-TEST_F(Hwc2Test, GET_MAX_VIRTUAL_DISPLAY_COUNT_create_max)
-{
-    std::vector<hwc2_display_t> displays;
-    uint32_t maxCnt;
-
-    ASSERT_NO_FATAL_FAILURE(getMaxVirtualDisplayCount(&maxCnt));
-
-    while (displays.size() < maxCnt) {
-        uint32_t width = 1920, height = 1080;
-        android_pixel_format_t desiredFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-        hwc2_display_t display;
-        hwc2_error_t err = HWC2_ERROR_NONE;
-
-        ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(width, height,
-                    &desiredFormat, &display, &err));
-
-        EXPECT_TRUE(err == HWC2_ERROR_NONE || err == HWC2_ERROR_UNSUPPORTED)
-                << "returned wrong error code";
-        if (err != HWC2_ERROR_NONE)
-            break;
-
-        displays.push_back(display);
-    }
-
-    for (hwc2_display_t display : displays) {
-        EXPECT_NO_FATAL_FAILURE(destroyVirtualDisplay(display));
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 can set an output buffer for a virtual
- * display. */
-TEST_F(Hwc2Test, SET_OUTPUT_BUFFER)
-{
-    ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Complete,
-            [] (Hwc2Test* test, hwc2_display_t display,
-                    Hwc2TestVirtualDisplay* testVirtualDisplay) {
-
-                buffer_handle_t handle;
-                android::base::unique_fd acquireFence;
-
-                if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) >= 0)
-                    EXPECT_NO_FATAL_FAILURE(test->setOutputBuffer(display,
-                            handle, acquireFence));
-            }));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an output buffer for a bad display */
-TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_bad_display)
-{
-    ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Default,
-            [] (Hwc2Test* test, hwc2_display_t /*display*/,
-                    Hwc2TestVirtualDisplay* testVirtualDisplay) {
-
-                hwc2_display_t badDisplay;
-                buffer_handle_t handle;
-                android::base::unique_fd acquireFence;
-                hwc2_error_t err = HWC2_ERROR_NONE;
-
-                ASSERT_NO_FATAL_FAILURE(test->getBadDisplay(&badDisplay));
-
-                if (testVirtualDisplay->getOutputBuffer(&handle, &acquireFence) < 0)
-                    return;
-
-                ASSERT_NO_FATAL_FAILURE(test->setOutputBuffer(badDisplay,
-                        handle, acquireFence, &err));
-                EXPECT_TRUE(err == HWC2_ERROR_BAD_DISPLAY)
-                        << "returned wrong error code";
-            }));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an invalid output buffer. */
-TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_bad_parameter)
-{
-    ASSERT_NO_FATAL_FAILURE(createVirtualDisplay(Hwc2TestCoverage::Default,
-            [] (Hwc2Test* test, hwc2_display_t display,
-                    Hwc2TestVirtualDisplay* /*testVirtualDisplay*/) {
-
-                const buffer_handle_t handle = nullptr;
-                uint32_t releaseFence = -1;
-                hwc2_error_t err = HWC2_ERROR_NONE;
-
-                ASSERT_NO_FATAL_FAILURE(test->setOutputBuffer(display, handle,
-                        releaseFence, &err));
-                EXPECT_EQ(err, HWC2_ERROR_BAD_PARAMETER)
-                        << "returned wrong error code";
-            }));
-}
-
-/* TESTCASE: Tests that the HWC2 cannot set an output buffer for non virtual
- * display */
-TEST_F(Hwc2Test, SET_OUTPUT_BUFFER_unsupported)
-{
-    for (auto display : mDisplays) {
-        Hwc2TestVirtualDisplay testVirtualDisplay(Hwc2TestCoverage::Complete);
-
-        do {
-            buffer_handle_t handle;
-            android::base::unique_fd acquireFence;
-            hwc2_error_t err = HWC2_ERROR_NONE;
-
-            if (testVirtualDisplay.getOutputBuffer(&handle, &acquireFence) < 0)
-                continue;
-
-            ASSERT_NO_FATAL_FAILURE(setOutputBuffer(display, handle,
-                    acquireFence, &err));
-            EXPECT_EQ(err, HWC2_ERROR_UNSUPPORTED) << "returned wrong error code";
-
-        } while (testVirtualDisplay.advance());
-    }
-}
-
-/* TESTCASE: Tests that the HWC2 can dump debug information. */
-TEST_F(Hwc2Test, DUMP)
-{
-    std::string buffer;
-
-    ASSERT_NO_FATAL_FAILURE(dump(&buffer));
-}
-
-/*
- * TODO(b/64724708): Hwc2TestPropertyName::BufferArea MUST be default for all
- * virtual display tests as we don't handle this case correctly.
- *
- * Only default dataspace is supported in our drawing code.
- */
-const std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>
-        virtualDisplayExceptions =
-        {{Hwc2TestPropertyName::BufferArea, Hwc2TestCoverage::Default},
-        {Hwc2TestPropertyName::Dataspace, Hwc2TestCoverage::Default}};
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with default coverage on a
- * virtual display. */
-TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_1)
-{
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    const size_t layerCnt = 1;
-    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
-            virtualDisplayExceptions));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 1 layer with basic coverage on a
- * virtual display. */
-TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_basic_1)
-{
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Basic;
-    const size_t layerCnt = 1;
-    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
-            virtualDisplayExceptions));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 2 layers with default coverage on a
- * virtual display. */
-TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_2)
-{
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    const size_t layerCnt = 2;
-    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
-            virtualDisplayExceptions));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 3 layers with default coverage on a
- * virtual display. */
-TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_3)
-{
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    const size_t layerCnt = 3;
-    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
-            virtualDisplayExceptions));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 4 layers with default coverage on a
- * virtual display. */
-TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_4)
-{
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    const size_t layerCnt = 4;
-    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
-            virtualDisplayExceptions));
-}
-
-/* TESTCASE: Tests that the HWC2 can present 5 layers with default coverage on a
- * virtual display. */
-TEST_F(Hwc2Test, PRESENT_VIRTUAL_DISPLAY_default_5)
-{
-    Hwc2TestCoverage coverage = Hwc2TestCoverage::Default;
-    const size_t layerCnt = 5;
-    ASSERT_NO_FATAL_FAILURE(createAndPresentVirtualDisplay(layerCnt, coverage,
-            virtualDisplayExceptions));
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
deleted file mode 100644
index 6484562..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.cpp
+++ /dev/null
@@ -1,791 +0,0 @@
-/*
- * Copyright (C) 2016 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 <mutex>
-#include <array>
-#include <sstream>
-#include <algorithm>
-
-#include <gui/Surface.h>
-#include <gui/BufferItemConsumer.h>
-
-#include <ui/GraphicBuffer.h>
-#include <android/hardware/graphics/common/1.0/types.h>
-#include <math/vec4.h>
-
-#include <GLES3/gl3.h>
-#include <SkImageEncoder.h>
-#include <SkStream.h>
-#include "Hwc2TestBuffer.h"
-#include "Hwc2TestLayers.h"
-
-using namespace android;
-using android::hardware::graphics::common::V1_0::BufferUsage;
-
-/* Returns a fence from egl */
-typedef void (*FenceCallback)(int32_t fence, void* callbackArgs);
-
-/* Returns fence to fence generator */
-static void setFence(int32_t fence, void* fenceGenerator);
-
-
-/* Used to receive the surfaces and fences from egl. The egl buffers are thrown
- * away. The fences are sent to the requester via a callback */
-class Hwc2TestSurfaceManager {
-public:
-    /* Listens for a new frame, detaches the buffer and returns the fence
-     * through saved callback. */
-    class BufferListener : public ConsumerBase::FrameAvailableListener {
-    public:
-        BufferListener(sp<IGraphicBufferConsumer> consumer,
-                FenceCallback callback, void* callbackArgs)
-            : mConsumer(consumer),
-              mCallback(callback),
-              mCallbackArgs(callbackArgs) { }
-
-        void onFrameAvailable(const BufferItem& /*item*/)
-        {
-            BufferItem item;
-
-            if (mConsumer->acquireBuffer(&item, 0))
-                return;
-            if (mConsumer->detachBuffer(item.mSlot))
-                return;
-
-            mCallback(item.mFence->dup(), mCallbackArgs);
-        }
-
-    private:
-        sp<IGraphicBufferConsumer> mConsumer;
-        FenceCallback mCallback;
-        void* mCallbackArgs;
-    };
-
-    /* Creates a buffer listener that waits on a new frame from the buffer
-     * queue. */
-    void initialize(const Area& bufferArea, android_pixel_format_t format,
-            FenceCallback callback, void* callbackArgs)
-    {
-        sp<IGraphicBufferProducer> producer;
-        sp<IGraphicBufferConsumer> consumer;
-        BufferQueue::createBufferQueue(&producer, &consumer);
-
-        consumer->setDefaultBufferSize(bufferArea.width, bufferArea.height);
-        consumer->setDefaultBufferFormat(format);
-
-        mBufferItemConsumer = new BufferItemConsumer(consumer, 0);
-
-        mListener = new BufferListener(consumer, callback, callbackArgs);
-        mBufferItemConsumer->setFrameAvailableListener(mListener);
-
-        mSurface = new Surface(producer, true);
-    }
-
-    /* Used by Egl manager. The surface is never displayed. */
-    sp<Surface> getSurface() const
-    {
-        return mSurface;
-    }
-
-private:
-    sp<BufferItemConsumer> mBufferItemConsumer;
-    sp<BufferListener> mListener;
-    /* Used by Egl manager. The surface is never displayed */
-    sp<Surface> mSurface;
-};
-
-
-/* Used to generate valid fences. It is not possible to create a dummy sync
- * fence for testing. Egl can generate buffers along with a valid fence.
- * The buffer cannot be guaranteed to be the same format across all devices so
- * a CPU filled buffer is used instead. The Egl fence is used along with the
- * CPU filled buffer. */
-class Hwc2TestEglManager {
-public:
-    Hwc2TestEglManager()
-        : mEglDisplay(EGL_NO_DISPLAY),
-          mEglSurface(EGL_NO_SURFACE),
-          mEglContext(EGL_NO_CONTEXT) { }
-
-    ~Hwc2TestEglManager()
-    {
-        cleanup();
-    }
-
-    int initialize(sp<Surface> surface)
-    {
-        mSurface = surface;
-
-        mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-        if (mEglDisplay == EGL_NO_DISPLAY) return false;
-
-        EGLint major;
-        EGLint minor;
-        if (!eglInitialize(mEglDisplay, &major, &minor)) {
-            ALOGW("Could not initialize EGL");
-            return false;
-        }
-
-        /* We're going to use a 1x1 pbuffer surface later on
-         * The configuration distance doesn't really matter for what we're
-         * trying to do */
-        EGLint configAttrs[] = {
-                EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-                EGL_RED_SIZE, 8,
-                EGL_GREEN_SIZE, 8,
-                EGL_BLUE_SIZE, 8,
-                EGL_ALPHA_SIZE, 0,
-                EGL_DEPTH_SIZE, 24,
-                EGL_STENCIL_SIZE, 0,
-                EGL_NONE
-        };
-
-        EGLConfig configs[1];
-        EGLint configCnt;
-        if (!eglChooseConfig(mEglDisplay, configAttrs, configs, 1,
-                &configCnt)) {
-            ALOGW("Could not select EGL configuration");
-            eglReleaseThread();
-            eglTerminate(mEglDisplay);
-            return false;
-        }
-
-        if (configCnt <= 0) {
-            ALOGW("Could not find EGL configuration");
-            eglReleaseThread();
-            eglTerminate(mEglDisplay);
-            return false;
-        }
-
-        /* These objects are initialized below but the default "null" values are
-         * used to cleanup properly at any point in the initialization sequence */
-        EGLint attrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
-        mEglContext = eglCreateContext(mEglDisplay, configs[0], EGL_NO_CONTEXT,
-                attrs);
-        if (mEglContext == EGL_NO_CONTEXT) {
-            ALOGW("Could not create EGL context");
-            cleanup();
-            return false;
-        }
-
-        EGLint surfaceAttrs[] = { EGL_NONE };
-        mEglSurface = eglCreateWindowSurface(mEglDisplay, configs[0],
-                mSurface.get(), surfaceAttrs);
-        if (mEglSurface == EGL_NO_SURFACE) {
-            ALOGW("Could not create EGL surface");
-            cleanup();
-            return false;
-        }
-
-        if (!eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
-            ALOGW("Could not change current EGL context");
-            cleanup();
-            return false;
-        }
-
-        return true;
-    }
-
-    void makeCurrent() const
-    {
-        eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext);
-    }
-
-    void present() const
-    {
-        eglSwapBuffers(mEglDisplay, mEglSurface);
-    }
-
-private:
-    void cleanup()
-    {
-        if (mEglDisplay == EGL_NO_DISPLAY)
-            return;
-        if (mEglSurface != EGL_NO_SURFACE)
-            eglDestroySurface(mEglDisplay, mEglSurface);
-        if (mEglContext != EGL_NO_CONTEXT)
-            eglDestroyContext(mEglDisplay, mEglContext);
-
-        eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
-                EGL_NO_CONTEXT);
-        eglReleaseThread();
-        eglTerminate(mEglDisplay);
-    }
-
-    sp<Surface> mSurface;
-    EGLDisplay mEglDisplay;
-    EGLSurface mEglSurface;
-    EGLContext mEglContext;
-};
-
-
-static const std::array<vec2, 4> triangles = {{
-    {  1.0f,  1.0f },
-    { -1.0f,  1.0f },
-    {  1.0f, -1.0f },
-    { -1.0f, -1.0f },
-}};
-
-class Hwc2TestFenceGenerator {
-public:
-
-    Hwc2TestFenceGenerator()
-    {
-        mSurfaceManager.initialize({1, 1}, HAL_PIXEL_FORMAT_RGBA_8888,
-                setFence, this);
-
-        if (!mEglManager.initialize(mSurfaceManager.getSurface()))
-            return;
-
-        mEglManager.makeCurrent();
-
-        glClearColor(0.0, 0.0, 0.0, 1.0);
-        glEnableVertexAttribArray(0);
-    }
-
-    ~Hwc2TestFenceGenerator()
-    {
-        if (mFence >= 0)
-            close(mFence);
-        mFence = -1;
-
-        mEglManager.makeCurrent();
-    }
-
-    /* It is not possible to simply generate a fence. The easiest way is to
-     * generate a buffer using egl and use the associated fence. The buffer
-     * cannot be guaranteed to be a certain format across all devices using this
-     * method. Instead the buffer is generated using the CPU */
-    int32_t get()
-    {
-        if (mFence >= 0) {
-            return dup(mFence);
-        }
-
-        std::unique_lock<std::mutex> lock(mMutex);
-
-        /* If the pending is still set to false and times out, we cannot recover.
-         * Set an error and return */
-        while (mPending != false) {
-            if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout)
-                return -ETIME;
-        }
-
-        /* Generate a fence. The fence will be returned through the setFence
-         * callback */
-        mEglManager.makeCurrent();
-
-        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, triangles.data());
-        glClear(GL_COLOR_BUFFER_BIT);
-
-        mEglManager.present();
-
-        /* Wait for the setFence callback */
-        while (mPending != true) {
-            if (mCv.wait_for(lock, std::chrono::seconds(2)) == std::cv_status::timeout)
-                return -ETIME;
-        }
-
-        mPending = false;
-
-        return dup(mFence);
-    }
-
-    /* Callback that sets the fence */
-    void set(int32_t fence)
-    {
-        mFence = fence;
-        mPending = true;
-
-        mCv.notify_all();
-    }
-
-private:
-
-    Hwc2TestSurfaceManager mSurfaceManager;
-    Hwc2TestEglManager mEglManager;
-
-    std::mutex mMutex;
-    std::condition_variable mCv;
-
-    int32_t mFence = -1;
-    bool mPending = false;
-};
-
-
-static void setFence(int32_t fence, void* fenceGenerator)
-{
-    static_cast<Hwc2TestFenceGenerator*>(fenceGenerator)->set(fence);
-}
-
-
-/* Sets the pixel of a buffer given the location, format, stride and color.
- * Currently only supports RGBA_8888 */
-static void setColor(int32_t x, int32_t y,
-        android_pixel_format_t format, uint32_t stride, uint8_t* img, uint8_t r,
-        uint8_t g, uint8_t b, uint8_t a)
-{
-       switch (format) {
-       case HAL_PIXEL_FORMAT_RGBA_8888:
-           img[(y * stride + x) * 4 + 0] = r;
-           img[(y * stride + x) * 4 + 1] = g;
-           img[(y * stride + x) * 4 + 2] = b;
-           img[(y * stride + x) * 4 + 3] = a;
-           break;
-       default:
-           break;
-       }
-}
-
-Hwc2TestBuffer::Hwc2TestBuffer()
-    : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
-
-Hwc2TestBuffer::~Hwc2TestBuffer() = default;
-
-/* When the buffer changes sizes, save the new size and invalidate the current
- * buffer */
-void Hwc2TestBuffer::updateBufferArea(const Area& bufferArea)
-{
-    if (mBufferArea.width == bufferArea.width
-            && mBufferArea.height == bufferArea.height)
-        return;
-
-    mBufferArea.width = bufferArea.width;
-    mBufferArea.height = bufferArea.height;
-
-    mValidBuffer = false;
-}
-
-/* Returns a valid buffer handle and fence. The handle is filled using the CPU
- * to ensure the correct format across all devices. The fence is created using
- * egl. */
-int Hwc2TestBuffer::get(buffer_handle_t* outHandle, int32_t* outFence)
-{
-    if (mBufferArea.width == -1 || mBufferArea.height == -1)
-        return -EINVAL;
-
-    /* If the current buffer is valid, the previous buffer can be reused.
-     * Otherwise, create new buffer */
-    if (!mValidBuffer) {
-        int ret = generateBuffer();
-        if (ret)
-            return ret;
-    }
-
-    *outFence = mFenceGenerator->get();
-    *outHandle = mHandle;
-
-    mValidBuffer = true;
-
-    return 0;
-}
-
-/* CPU fills a buffer to guarantee the correct buffer format across all
- * devices */
-int Hwc2TestBuffer::generateBuffer()
-{
-    /* Create new graphic buffer with correct dimensions */
-    mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
-            mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-            BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
-
-    int ret = mGraphicBuffer->initCheck();
-    if (ret) {
-        return ret;
-    }
-    if (!mGraphicBuffer->handle) {
-        return -EINVAL;
-    }
-
-    /* Locks the buffer for writing */
-    uint8_t* img;
-    mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
-            (void**)(&img));
-
-    uint32_t stride = mGraphicBuffer->getStride();
-
-    /* Iterate from the top row of the buffer to the bottom row */
-    for (int32_t y = 0; y < mBufferArea.height; y++) {
-
-        /* Will be used as R, G and B values for pixel colors */
-        uint8_t max = 255;
-        uint8_t min = 0;
-
-        /* Divide the rows into 3 sections. The first section will contain
-         * the lighest colors. The last section will contain the darkest
-         * colors. */
-        if (y < mBufferArea.height * 1.0 / 3.0) {
-            min = 255 / 2;
-        } else if (y >= mBufferArea.height * 2.0 / 3.0) {
-            max = 255 / 2;
-        }
-
-        /* Divide the columns into 3 sections. The first section is red,
-         * the second is green and the third is blue */
-        int32_t x = 0;
-        for (; x < mBufferArea.width / 3; x++) {
-            setColor(x, y, mFormat, stride, img, max, min, min, 255);
-        }
-
-        for (; x < mBufferArea.width * 2 / 3; x++) {
-            setColor(x, y, mFormat, stride, img, min, max, min, 255);
-        }
-
-        for (; x < mBufferArea.width; x++) {
-            setColor(x, y, mFormat, stride, img, min, min, max, 255);
-        }
-    }
-
-    /* Unlock the buffer for reading */
-    mGraphicBuffer->unlock();
-
-    mHandle = mGraphicBuffer->handle;
-
-    return 0;
-}
-
-
-Hwc2TestClientTargetBuffer::Hwc2TestClientTargetBuffer()
-    : mFenceGenerator(new Hwc2TestFenceGenerator()) { }
-
-Hwc2TestClientTargetBuffer::~Hwc2TestClientTargetBuffer() { }
-
-/* Generates a buffer from layersToDraw.
- * Takes into account the individual layer properties such as
- * transform, blend mode, source crop, etc. */
-static void compositeBufferFromLayers(
-        const android::sp<android::GraphicBuffer>& graphicBuffer,
-        android_pixel_format_t format, const Area& bufferArea,
-        const Hwc2TestLayers* testLayers,
-        const std::set<hwc2_layer_t>* layersToDraw,
-        const std::set<hwc2_layer_t>* clearLayers)
-{
-    /* Locks the buffer for writing */
-    uint8_t* img;
-    graphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
-            (void**)(&img));
-
-    uint32_t stride = graphicBuffer->getStride();
-
-    float bWDiv3 = bufferArea.width / 3;
-    float bW2Div3 = bufferArea.width * 2 / 3;
-    float bHDiv3 = bufferArea.height / 3;
-    float bH2Div3 = bufferArea.height * 2 / 3;
-
-    /* Cycle through every pixel in the buffer and determine what color it
-     * should be. */
-    for (int32_t y = 0; y < bufferArea.height; y++) {
-        for (int32_t x = 0; x < bufferArea.width; x++) {
-
-            uint8_t r = 0, g = 0, b = 0;
-            float a = 0.0f;
-
-            /* Cycle through each layer from back to front and
-             * update the pixel color. */
-            for (auto layer = layersToDraw->rbegin();
-                    layer != layersToDraw->rend(); ++layer) {
-
-                const hwc_rect_t df = testLayers->getDisplayFrame(*layer);
-
-                float dfL = df.left;
-                float dfT = df.top;
-                float dfR = df.right;
-                float dfB = df.bottom;
-
-                /* If the pixel location falls outside of the layer display
-                 * frame, skip the layer. */
-                if (x < dfL || x >= dfR || y < dfT || y >= dfB)
-                    continue;
-
-                /* If the device has requested the layer be clear, clear
-                 * the pixel and continue. */
-                if (clearLayers->count(*layer) != 0) {
-                    r = 0;
-                    g = 0;
-                    b = 0;
-                    a = 0.0f;
-                    continue;
-                }
-
-                float planeAlpha = testLayers->getPlaneAlpha(*layer);
-
-                /* If the layer is a solid color, fill the color and
-                 * continue. */
-                if (testLayers->getComposition(*layer)
-                        == HWC2_COMPOSITION_SOLID_COLOR) {
-                    const auto color = testLayers->getColor(*layer);
-                    r = color.r;
-                    g = color.g;
-                    b = color.b;
-                    a = color.a * planeAlpha;
-                    continue;
-                }
-
-                float xPos = x;
-                float yPos = y;
-
-                hwc_transform_t transform = testLayers->getTransform(*layer);
-
-                float dfW = dfR - dfL;
-                float dfH = dfB - dfT;
-
-                /* If a layer has a transform, find which location on the
-                 * layer will end up in the current pixel location. We
-                 * can calculate the color of the current pixel using that
-                 * location. */
-                if (transform > 0) {
-                    /* Change origin to be the center of the layer. */
-                    xPos = xPos - dfL - dfW / 2.0;
-                    yPos = yPos - dfT - dfH / 2.0;
-
-                    /* Flip Horizontal by reflecting across the y axis. */
-                    if (transform & HWC_TRANSFORM_FLIP_H)
-                        xPos = -xPos;
-
-                    /* Flip vertical by reflecting across the x axis. */
-                    if (transform & HWC_TRANSFORM_FLIP_V)
-                        yPos = -yPos;
-
-                    /* Rotate 90 by using a basic linear algebra rotation
-                     * and scaling the result so the display frame remains
-                     * the same. For example, a buffer of size 100x50 should
-                     * rotate 90 degress but remain the same dimension
-                     * (100x50) at the end of the transformation. */
-                    if (transform & HWC_TRANSFORM_ROT_90) {
-                        float tmp = xPos;
-                        xPos = yPos * dfW / dfH;
-                        yPos = -tmp * dfH / dfW;
-                    }
-
-                    /* Change origin back to the top left corner of the
-                     * layer. */
-                    xPos = xPos + dfL + dfW / 2.0;
-                    yPos = yPos + dfT + dfH / 2.0;
-                }
-
-                hwc_frect_t sc = testLayers->getSourceCrop(*layer);
-                float scL = sc.left, scT = sc.top;
-
-                float dfWDivScW = dfW / (sc.right - scL);
-                float dfHDivScH = dfH / (sc.bottom - scT);
-
-                float max = 255, min = 0;
-
-                /* Choose the pixel color. Similar to generateBuffer,
-                 * each layer will be divided into 3x3 colors. Because
-                 * both the source crop and display frame must be taken into
-                 * account, the formulas are more complicated.
-                 *
-                 * If the source crop and display frame were not taken into
-                 * account, we would simply divide the buffer into three
-                 * sections by height. Each section would get one color.
-                 * For example the formula for the first section would be:
-                 *
-                 * if (yPos < bufferArea.height / 3)
-                 *        //Select first section color
-                 *
-                 * However the pixel color is chosen based on the source
-                 * crop and displayed based on the display frame.
-                 *
-                 * If the display frame top was 0 and the source crop height
-                 * and display frame height were the same. The only factor
-                 * would be the source crop top. To calculate the new
-                 * section boundary, the section boundary would be moved up
-                 * by the height of the source crop top. The formula would
-                 * be:
-                 * if (yPos < (bufferArea.height / 3 - sourceCrop.top)
-                 *        //Select first section color
-                 *
-                 * If the display frame top could also vary but source crop
-                 * and display frame heights were the same, the formula
-                 * would be:
-                 * if (yPos < (bufferArea.height / 3 - sourceCrop.top
-                 *              + displayFrameTop)
-                 *        //Select first section color
-                 *
-                 * If the heights were not the same, the conversion between
-                 * the source crop and display frame dimensions must be
-                 * taken into account. The formula would be:
-                 * if (yPos < ((bufferArea.height / 3) - sourceCrop.top)
-                 *              * displayFrameHeight / sourceCropHeight
-                 *              + displayFrameTop)
-                 *        //Select first section color
-                 */
-                if (yPos < ((bHDiv3) - scT) * dfHDivScH + dfT) {
-                    min = 255 / 2;
-                } else if (yPos >= ((bH2Div3) - scT) * dfHDivScH + dfT) {
-                    max = 255 / 2;
-                }
-
-                uint8_t rCur = min, gCur = min, bCur = min;
-                float aCur = 1.0f;
-
-                /* This further divides the color sections from 3 to 3x3.
-                 * The math behind it follows the same logic as the previous
-                 * comment */
-                if (xPos < ((bWDiv3) - scL) * (dfWDivScW) + dfL) {
-                    rCur = max;
-                } else if (xPos < ((bW2Div3) - scL) * (dfWDivScW) + dfL) {
-                    gCur = max;
-                } else {
-                    bCur = max;
-                }
-
-
-                /* Blend the pixel color with the previous layers' pixel
-                 * colors using the plane alpha and blend mode. The final
-                 * pixel color is chosen using the plane alpha and blend
-                 * mode formulas found in hwcomposer2.h */
-                hwc2_blend_mode_t blendMode = testLayers->getBlendMode(*layer);
-
-                if (blendMode == HWC2_BLEND_MODE_PREMULTIPLIED) {
-                    rCur *= planeAlpha;
-                    gCur *= planeAlpha;
-                    bCur *= planeAlpha;
-                }
-
-                aCur *= planeAlpha;
-
-                if (blendMode == HWC2_BLEND_MODE_PREMULTIPLIED) {
-                    r = rCur + r * (1.0 - aCur);
-                    g = gCur + g * (1.0 - aCur);
-                    b = bCur + b * (1.0 - aCur);
-                    a = aCur + a * (1.0 - aCur);
-                } else if (blendMode == HWC2_BLEND_MODE_COVERAGE) {
-                    r = rCur * aCur + r * (1.0 - aCur);
-                    g = gCur * aCur + g * (1.0 - aCur);
-                    b = bCur * aCur + b * (1.0 - aCur);
-                    a = aCur * aCur + a * (1.0 - aCur);
-                } else {
-                    r = rCur;
-                    g = gCur;
-                    b = bCur;
-                    a = aCur;
-                }
-            }
-
-            /* Set the pixel color */
-            setColor(x, y, format, stride, img, r, g, b, a * 255);
-        }
-    }
-
-    graphicBuffer->unlock();
-}
-
-/* Generates a client target buffer using the layers assigned for client
- * composition. Takes into account the individual layer properties such as
- * transform, blend mode, source crop, etc. */
-int Hwc2TestClientTargetBuffer::get(buffer_handle_t* outHandle,
-        int32_t* outFence, const Area& bufferArea,
-        const Hwc2TestLayers* testLayers,
-        const std::set<hwc2_layer_t>* clientLayers,
-        const std::set<hwc2_layer_t>* clearLayers)
-{
-    /* Create new graphic buffer with correct dimensions */
-    mGraphicBuffer = new GraphicBuffer(bufferArea.width, bufferArea.height,
-            mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
-            BufferUsage::COMPOSER_OVERLAY, "hwc2_test_buffer");
-
-    int ret = mGraphicBuffer->initCheck();
-    if (ret)
-        return ret;
-
-    if (!mGraphicBuffer->handle)
-        return -EINVAL;
-
-    compositeBufferFromLayers(mGraphicBuffer, mFormat, bufferArea, testLayers,
-            clientLayers, clearLayers);
-
-    *outFence = mFenceGenerator->get();
-    *outHandle = mGraphicBuffer->handle;
-
-    return 0;
-}
-
-void Hwc2TestVirtualBuffer::updateBufferArea(const Area& bufferArea)
-{
-    mBufferArea.width = bufferArea.width;
-    mBufferArea.height = bufferArea.height;
-}
-
-bool Hwc2TestVirtualBuffer::writeBufferToFile(std::string path)
-{
-    SkFILEWStream file(path.c_str());
-    const SkImageInfo info = SkImageInfo::Make(mBufferArea.width,
-            mBufferArea.height, SkColorType::kRGBA_8888_SkColorType,
-            SkAlphaType::kPremul_SkAlphaType);
-
-    uint8_t* img;
-    mGraphicBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_WRITE_OFTEN),
-            (void**)(&img));
-
-    SkPixmap pixmap(info, img, mGraphicBuffer->getStride());
-    bool result = file.isValid() && SkEncodeImage(&file, pixmap,
-            SkEncodedImageFormat::kPNG, 100);
-
-    mGraphicBuffer->unlock();
-    return result;
-}
-
-/* Generates a buffer that holds the expected result of compositing all of our
- * layers */
-int Hwc2TestExpectedBuffer::generateExpectedBuffer(
-        const Hwc2TestLayers* testLayers,
-        const std::vector<hwc2_layer_t>* allLayers,
-        const std::set<hwc2_layer_t>* clearLayers)
-{
-    mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
-            mFormat, BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
-            "hwc2_test_buffer");
-
-    int ret = mGraphicBuffer->initCheck();
-    if (ret)
-        return ret;
-
-    if (!mGraphicBuffer->handle)
-        return -EINVAL;
-
-    const std::set<hwc2_layer_t> allLayerSet(allLayers->begin(),
-            allLayers->end());
-
-    compositeBufferFromLayers(mGraphicBuffer, mFormat, mBufferArea, testLayers,
-            &allLayerSet, clearLayers);
-
-    return 0;
-}
-
-int Hwc2TestOutputBuffer::getOutputBuffer(buffer_handle_t* outHandle,
-        int32_t* outFence)
-{
-    if (mBufferArea.width == -1 || mBufferArea.height == -1)
-        return -EINVAL;
-
-    mGraphicBuffer = new GraphicBuffer(mBufferArea.width, mBufferArea.height,
-            mFormat, BufferUsage::CPU_READ_OFTEN |
-            BufferUsage::GPU_RENDER_TARGET, "hwc2_test_buffer");
-
-    int ret = mGraphicBuffer->initCheck();
-    if (ret)
-        return ret;
-
-    if (!mGraphicBuffer->handle)
-        return -EINVAL;
-
-    *outFence = -1;
-    *outHandle = mGraphicBuffer->handle;
-
-    return 0;
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
deleted file mode 100644
index fd54fef..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestBuffer.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef _HWC2_TEST_BUFFER_H
-#define _HWC2_TEST_BUFFER_H
-
-#include <android-base/unique_fd.h>
-#include <set>
-
-#include <hardware/hwcomposer2.h>
-
-#include <ui/GraphicBuffer.h>
-
-#include "Hwc2TestProperties.h"
-
-class Hwc2TestFenceGenerator;
-class Hwc2TestLayers;
-
-class Hwc2TestBuffer {
-public:
-    Hwc2TestBuffer();
-    ~Hwc2TestBuffer();
-
-    void updateBufferArea(const Area& bufferArea);
-
-    int  get(buffer_handle_t* outHandle, int32_t* outFence);
-
-protected:
-    int generateBuffer();
-
-    android::sp<android::GraphicBuffer> mGraphicBuffer;
-
-    std::unique_ptr<Hwc2TestFenceGenerator> mFenceGenerator;
-
-    Area mBufferArea = {-1, -1};
-    const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-
-    bool mValidBuffer = false;
-    buffer_handle_t mHandle = nullptr;
-};
-
-
-class Hwc2TestClientTargetBuffer {
-public:
-    Hwc2TestClientTargetBuffer();
-    ~Hwc2TestClientTargetBuffer();
-
-    int  get(buffer_handle_t* outHandle, int32_t* outFence,
-            const Area& bufferArea, const Hwc2TestLayers* testLayers,
-            const std::set<hwc2_layer_t>* clientLayers,
-            const std::set<hwc2_layer_t>* clearLayers);
-
-protected:
-    android::sp<android::GraphicBuffer> mGraphicBuffer;
-
-    std::unique_ptr<Hwc2TestFenceGenerator> mFenceGenerator;
-
-    const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-};
-
-
-class Hwc2TestVirtualBuffer {
-public:
-    void updateBufferArea(const Area& bufferArea);
-
-    bool writeBufferToFile(std::string path);
-
-    android::sp<android::GraphicBuffer>& graphicBuffer()
-    {
-        return mGraphicBuffer;
-    }
-
-protected:
-    android::sp<android::GraphicBuffer> mGraphicBuffer;
-
-    Area mBufferArea = {-1, -1};
-
-    const android_pixel_format_t mFormat = HAL_PIXEL_FORMAT_RGBA_8888;
-};
-
-
-class Hwc2TestExpectedBuffer : public Hwc2TestVirtualBuffer {
-public:
-    int generateExpectedBuffer(const Hwc2TestLayers* testLayers,
-            const std::vector<hwc2_layer_t>* allLayers,
-            const std::set<hwc2_layer_t>* clearLayers);
-};
-
-
-class Hwc2TestOutputBuffer : public Hwc2TestVirtualBuffer {
-public:
-    int getOutputBuffer(buffer_handle_t* outHandle, int32_t* outFence);
-};
-
-#endif /* ifndef _HWC2_TEST_BUFFER_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp
deleted file mode 100644
index 14c60a7..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2016 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 <sstream>
-
-#include <ui/Rect.h>
-
-#include "Hwc2TestClientTarget.h"
-
-int Hwc2TestClientTarget::getBuffer(const Hwc2TestLayers& testLayers,
-        const std::set<hwc2_layer_t>& clientLayers,
-        const std::set<hwc2_layer_t>& clearLayers, bool flipClientTarget,
-        const Area& displayArea, buffer_handle_t* outHandle,
-        int32_t* outAcquireFence)
-{
-    if (!flipClientTarget) {
-        bool needsClientTarget = false;
-
-        for (auto clientLayer : clientLayers) {
-            if (testLayers.getVisibleRegion(clientLayer).numRects > 0) {
-                needsClientTarget = true;
-                break;
-            }
-        }
-
-        if (!needsClientTarget) {
-           *outHandle = nullptr;
-           *outAcquireFence = -1;
-           return 0;
-        }
-    }
-
-    return mBuffer.get(outHandle, outAcquireFence, displayArea,
-            &testLayers, &clientLayers, &clearLayers);
-}
-
-
-Hwc2TestClientTargetSupport::Hwc2TestClientTargetSupport(
-        Hwc2TestCoverage coverage, const Area& displayArea)
-    : mBufferArea(coverage, displayArea),
-      mDataspace(coverage),
-      mSurfaceDamage(coverage)
-{
-    mBufferArea.setDependent(&mSurfaceDamage);
-}
-
-std::string Hwc2TestClientTargetSupport::dump() const
-{
-    std::stringstream dmp;
-
-    dmp << "client target: \n";
-
-    for (auto property : properties) {
-        dmp << property->dump();
-    }
-
-    return dmp.str();
-}
-
-void Hwc2TestClientTargetSupport::reset()
-{
-    for (auto property : properties) {
-        property->reset();
-    }
-}
-
-bool Hwc2TestClientTargetSupport::advance()
-{
-    for (auto property : properties) {
-        if (property->advance())
-            return true;
-    }
-    return false;
-}
-
-Area Hwc2TestClientTargetSupport::getBufferArea() const
-{
-    return mBufferArea.get();
-}
-
-android::ui::Dataspace Hwc2TestClientTargetSupport::getDataspace() const
-{
-    return mDataspace.get();
-}
-
-const hwc_region_t Hwc2TestClientTargetSupport::getSurfaceDamage() const
-{
-    return mSurfaceDamage.get();
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h b/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h
deleted file mode 100644
index 6f4090f..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestClientTarget.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef _HWC2_TEST_CLIENT_TARGET_H
-#define _HWC2_TEST_CLIENT_TARGET_H
-
-#include <set>
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-#include "Hwc2TestProperties.h"
-#include "Hwc2TestLayers.h"
-
-/* Generates client target buffers from client composition layers */
-class Hwc2TestClientTarget {
-public:
-    int getBuffer(const Hwc2TestLayers& layers,
-            const std::set<hwc2_layer_t>& clientLayers,
-            const std::set<hwc2_layer_t>& clearLayers,
-            bool clearClientTarget, const Area& displayArea,
-            buffer_handle_t* outHandle, int32_t* outAcquireFence);
-
-private:
-    Hwc2TestClientTargetBuffer mBuffer;
-};
-
-/* Generates valid client targets to test which ones the device will support */
-class Hwc2TestClientTargetSupport {
-public:
-    Hwc2TestClientTargetSupport(Hwc2TestCoverage coverage,
-            const Area& displayArea);
-
-    std::string dump() const;
-
-    void reset();
-    bool advance();
-
-    Area getBufferArea() const;
-    android::ui::Dataspace getDataspace() const;
-    const hwc_region_t getSurfaceDamage() const;
-
-private:
-    std::array<Hwc2TestContainer*, 3> properties = {{
-        &mDataspace, &mSurfaceDamage, &mBufferArea
-    }};
-
-    Hwc2TestBufferArea mBufferArea;
-    Hwc2TestDataspace mDataspace;
-    Hwc2TestSurfaceDamage mSurfaceDamage;
-};
-
-#endif /* ifndef _HWC2_TEST_CLIENT_TARGET_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp
deleted file mode 100644
index c1c9cc8..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.cpp
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright (C) 2016 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 <sstream>
-
-#include "Hwc2TestLayer.h"
-
-Hwc2TestCoverage getCoverage(Hwc2TestPropertyName property,
-        Hwc2TestCoverage coverage, const std::unordered_map<Hwc2TestPropertyName,
-        Hwc2TestCoverage>& coverageExceptions) {
-    auto exception = coverageExceptions.find(property);
-    return (exception != coverageExceptions.end())? exception->second : coverage;
-}
-
-Hwc2TestLayer::Hwc2TestLayer(Hwc2TestCoverage coverage,
-        const Area& displayArea)
-    : Hwc2TestLayer(coverage, displayArea,
-            std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>()) { }
-
-Hwc2TestLayer::Hwc2TestLayer(Hwc2TestCoverage coverage,
-        const Area& displayArea, const std::unordered_map<Hwc2TestPropertyName,
-        Hwc2TestCoverage>& coverageExceptions)
-    : mBlendMode(getCoverage(Hwc2TestPropertyName::BlendMode, coverage,
-           coverageExceptions)),
-      mBufferArea(getCoverage(Hwc2TestPropertyName::BufferArea, coverage,
-           coverageExceptions), displayArea),
-      mColor(getCoverage(Hwc2TestPropertyName::Color, coverage,
-           coverageExceptions)),
-      mComposition(getCoverage(Hwc2TestPropertyName::Composition, coverage,
-           coverageExceptions)),
-      mDataspace(getCoverage(Hwc2TestPropertyName::Dataspace, coverage,
-           coverageExceptions)),
-      mDisplayFrame(getCoverage(Hwc2TestPropertyName::DisplayFrame, coverage,
-           coverageExceptions), displayArea),
-      mPlaneAlpha(getCoverage(Hwc2TestPropertyName::PlaneAlpha, coverage,
-           coverageExceptions)),
-      mSourceCrop(getCoverage(Hwc2TestPropertyName::SourceCrop, coverage,
-           coverageExceptions)),
-      mSurfaceDamage(getCoverage(Hwc2TestPropertyName::SurfaceDamage, coverage,
-           coverageExceptions)),
-      mTransform(getCoverage(Hwc2TestPropertyName::Transform, coverage,
-           coverageExceptions))
-{
-    mBufferArea.setDependent(&mBuffer);
-    mBufferArea.setDependent(&mSourceCrop);
-    mBufferArea.setDependent(&mSurfaceDamage);
-    mBlendMode.setDependent(&mColor);
-}
-
-std::string Hwc2TestLayer::dump() const
-{
-    std::stringstream dmp;
-
-    dmp << "layer: \n";
-
-    for (auto property : mProperties) {
-        dmp << property->dump();
-    }
-
-    dmp << mVisibleRegion.dump();
-    dmp << "\tz order: " << mZOrder << "\n";
-
-    return dmp.str();
-}
-
-int Hwc2TestLayer::getBuffer(buffer_handle_t* outHandle,
-        android::base::unique_fd* outAcquireFence)
-{
-    int32_t acquireFence;
-    int ret = mBuffer.get(outHandle, &acquireFence);
-    outAcquireFence->reset(acquireFence);
-    return ret;
-}
-
-int Hwc2TestLayer::getBuffer(buffer_handle_t* outHandle,
-        int32_t* outAcquireFence)
-{
-    return mBuffer.get(outHandle, outAcquireFence);
-}
-
-void Hwc2TestLayer::setZOrder(uint32_t zOrder)
-{
-    mZOrder = zOrder;
-}
-
-void Hwc2TestLayer::setVisibleRegion(const android::Region& region)
-{
-    return mVisibleRegion.set(region);
-}
-
-void Hwc2TestLayer::reset()
-{
-    mVisibleRegion.release();
-
-    for (auto property : mProperties) {
-        property->reset();
-    }
-}
-
-bool Hwc2TestLayer::advance()
-{
-    for (auto property : mProperties) {
-        if (property->isSupported(mComposition.get()))
-            if (property->advance())
-                return true;
-    }
-    return false;
-}
-
-hwc2_blend_mode_t Hwc2TestLayer::getBlendMode() const
-{
-    return mBlendMode.get();
-}
-
-Area Hwc2TestLayer::getBufferArea() const
-{
-    return mBufferArea.get();
-}
-
-hwc_color_t Hwc2TestLayer::getColor() const
-{
-    return mColor.get();
-}
-
-hwc2_composition_t Hwc2TestLayer::getComposition() const
-{
-    return mComposition.get();
-}
-
-/* The cursor position corresponds to {displayFrame.left, displayFrame.top} */
-hwc_rect_t Hwc2TestLayer::getCursorPosition() const
-{
-    return mDisplayFrame.get();
-}
-
-android::ui::Dataspace Hwc2TestLayer::getDataspace() const
-{
-    return mDataspace.get();
-}
-
-hwc_rect_t Hwc2TestLayer::getDisplayFrame() const
-{
-    return mDisplayFrame.get();
-}
-
-float Hwc2TestLayer::getPlaneAlpha() const
-{
-    return mPlaneAlpha.get();
-}
-
-hwc_frect_t Hwc2TestLayer::getSourceCrop() const
-{
-    return mSourceCrop.get();
-}
-
-hwc_region_t Hwc2TestLayer::getSurfaceDamage() const
-{
-    return mSurfaceDamage.get();
-}
-
-hwc_transform_t Hwc2TestLayer::getTransform() const
-{
-    return mTransform.get();
-}
-
-hwc_region_t Hwc2TestLayer::getVisibleRegion() const
-{
-    return mVisibleRegion.get();
-}
-
-uint32_t Hwc2TestLayer::getZOrder() const
-{
-    return mZOrder;
-}
-
-bool Hwc2TestLayer::advanceBlendMode()
-{
-    return mBlendMode.advance();
-}
-
-bool Hwc2TestLayer::advanceBufferArea()
-{
-    return mBufferArea.advance();
-}
-
-bool Hwc2TestLayer::advanceColor()
-{
-    return mColor.advance();
-}
-
-bool Hwc2TestLayer::advanceComposition()
-{
-    return mComposition.advance();
-}
-
-bool Hwc2TestLayer::advanceCursorPosition()
-{
-    return mDisplayFrame.advance();
-}
-
-bool Hwc2TestLayer::advanceDataspace()
-{
-    return mDataspace.advance();
-}
-
-bool Hwc2TestLayer::advanceDisplayFrame()
-{
-    return mDisplayFrame.advance();
-}
-
-bool Hwc2TestLayer::advancePlaneAlpha()
-{
-    return mPlaneAlpha.advance();
-}
-
-bool Hwc2TestLayer::advanceSourceCrop()
-{
-    return mSourceCrop.advance();
-}
-
-bool Hwc2TestLayer::advanceSurfaceDamage()
-{
-    return mSurfaceDamage.advance();
-}
-
-bool Hwc2TestLayer::advanceTransform()
-{
-    return mTransform.advance();
-}
-
-bool Hwc2TestLayer::advanceVisibleRegion()
-{
-    if (mPlaneAlpha.advance())
-        return true;
-    return mDisplayFrame.advance();
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h
deleted file mode 100644
index 29ae521..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayer.h
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef _HWC2_TEST_LAYER_H
-#define _HWC2_TEST_LAYER_H
-
-#include <android-base/unique_fd.h>
-#include <unordered_map>
-
-#include "Hwc2TestBuffer.h"
-#include "Hwc2TestProperties.h"
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-class Hwc2TestLayer {
-public:
-    Hwc2TestLayer(Hwc2TestCoverage coverage, const Area& displayArea);
-
-    Hwc2TestLayer(Hwc2TestCoverage coverage, const Area& displayArea,
-            const std::unordered_map<Hwc2TestPropertyName,
-            Hwc2TestCoverage>& coverage_exceptions);
-
-    std::string dump() const;
-
-    int getBuffer(buffer_handle_t* outHandle,
-            android::base::unique_fd* outAcquireFence);
-    int getBuffer(buffer_handle_t* outHandle, int32_t* outAcquireFence);
-
-    void setZOrder(uint32_t zOrder);
-    void setVisibleRegion(const android::Region& region);
-
-    void reset();
-    bool advance();
-
-    hwc2_blend_mode_t      getBlendMode() const;
-    Area                   getBufferArea() const;
-    hwc_color_t            getColor() const;
-    hwc2_composition_t     getComposition() const;
-    hwc_rect_t             getCursorPosition() const;
-    android::ui::Dataspace     getDataspace() const;
-    hwc_rect_t             getDisplayFrame() const;
-    float                  getPlaneAlpha() const;
-    hwc_frect_t            getSourceCrop() const;
-    hwc_region_t           getSurfaceDamage() const;
-    hwc_transform_t        getTransform() const;
-    hwc_region_t           getVisibleRegion() const;
-    uint32_t               getZOrder() const;
-
-    bool advanceBlendMode();
-    bool advanceBufferArea();
-    bool advanceColor();
-    bool advanceComposition();
-    bool advanceCursorPosition();
-    bool advanceDataspace();
-    bool advanceDisplayFrame();
-    bool advancePlaneAlpha();
-    bool advanceSourceCrop();
-    bool advanceSurfaceDamage();
-    bool advanceTransform();
-    bool advanceVisibleRegion();
-
-private:
-    std::array<Hwc2TestContainer*, 10> mProperties = {{
-        &mTransform, &mColor, &mDataspace, &mPlaneAlpha, &mSourceCrop,
-        &mSurfaceDamage, &mBlendMode, &mBufferArea, &mDisplayFrame,
-        &mComposition
-    }};
-
-    Hwc2TestBuffer mBuffer;
-
-    Hwc2TestBlendMode mBlendMode;
-    Hwc2TestBufferArea mBufferArea;
-    Hwc2TestColor mColor;
-    Hwc2TestComposition mComposition;
-    Hwc2TestDataspace mDataspace;
-    Hwc2TestDisplayFrame mDisplayFrame;
-    Hwc2TestPlaneAlpha mPlaneAlpha;
-    Hwc2TestSourceCrop mSourceCrop;
-    Hwc2TestSurfaceDamage mSurfaceDamage;
-    Hwc2TestTransform mTransform;
-    Hwc2TestVisibleRegion mVisibleRegion;
-
-    uint32_t mZOrder = UINT32_MAX;
-};
-
-#endif /* ifndef _HWC2_TEST_LAYER_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
deleted file mode 100644
index 90127a1..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.cpp
+++ /dev/null
@@ -1,281 +0,0 @@
-/* * Copyright (C) 2016 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 <sstream>
-#include <gtest/gtest.h>
-
-#include "Hwc2TestLayers.h"
-
-Hwc2TestLayers::Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers,
-        Hwc2TestCoverage coverage, const Area& displayArea)
-    : Hwc2TestLayers(layers, coverage, displayArea,
-            std::unordered_map<Hwc2TestPropertyName, Hwc2TestCoverage>()) { }
-
-Hwc2TestLayers::Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers,
-        Hwc2TestCoverage coverage, const Area& displayArea,
-        const std::unordered_map<Hwc2TestPropertyName,
-        Hwc2TestCoverage>& coverageExceptions)
-    : mDisplayArea(displayArea)
-{
-    for (auto layer : layers) {
-        mTestLayers.emplace(std::piecewise_construct,
-                std::forward_as_tuple(layer),
-                std::forward_as_tuple(coverage, displayArea, coverageExceptions));
-    }
-
-    /* Iterate over the layers in order and assign z orders in the same order.
-     * This allows us to iterate over z orders in the same way when computing
-     * visible regions */
-    uint32_t nextZOrder = layers.size();
-
-    for (auto& testLayer : mTestLayers) {
-        testLayer.second.setZOrder(nextZOrder--);
-    }
-
-    setVisibleRegions();
-}
-
-std::string Hwc2TestLayers::dump() const
-{
-    std::stringstream dmp;
-    for (auto& testLayer : mTestLayers) {
-        dmp << testLayer.second.dump();
-    }
-    return dmp.str();
-}
-
-void Hwc2TestLayers::reset()
-{
-    for (auto& testLayer : mTestLayers) {
-        testLayer.second.reset();
-    }
-
-    setVisibleRegions();
-}
-
-bool Hwc2TestLayers::advance()
-{
-    auto itr = mTestLayers.begin();
-    bool optimized;
-
-    while (itr != mTestLayers.end()) {
-        if (itr->second.advance()) {
-            optimized = setVisibleRegions();
-            if (!mOptimize || optimized)
-                return true;
-            itr = mTestLayers.begin();
-        } else {
-            itr->second.reset();
-            ++itr;
-        }
-    }
-    return false;
-}
-
-bool Hwc2TestLayers::advanceVisibleRegions()
-{
-    auto itr = mTestLayers.begin();
-    bool optimized;
-
-    while (itr != mTestLayers.end()) {
-        if (itr->second.advanceVisibleRegion()) {
-            optimized = setVisibleRegions();
-            if (!mOptimize || optimized)
-                return true;
-            itr = mTestLayers.begin();
-        } else {
-            itr->second.reset();
-            ++itr;
-        }
-    }
-    return false;
-}
-
-/* Removes layouts that do not cover the entire display.
- * Also removes layouts where a layer is completely blocked from view.
- */
-bool Hwc2TestLayers::optimizeLayouts()
-{
-    mOptimize = true;
-
-    if (setVisibleRegions())
-        return true;
-    return advance();
-}
-
-bool Hwc2TestLayers::contains(hwc2_layer_t layer) const
-{
-    return mTestLayers.count(layer) != 0;
-}
-
-int Hwc2TestLayers::getBuffer(hwc2_layer_t layer, buffer_handle_t* outHandle,
-        int32_t* outAcquireFence)
-{
-    if (mTestLayers.count(layer) == 0) {
-        []() { GTEST_FAIL(); }();
-    }
-    return mTestLayers.at(layer).getBuffer(outHandle, outAcquireFence);
-}
-
-hwc2_blend_mode_t Hwc2TestLayers::getBlendMode(hwc2_layer_t layer) const
-{
-    if (mTestLayers.count(layer) == 0) {
-        []() { GTEST_FAIL(); }();
-    }
-    return mTestLayers.at(layer).getBlendMode();
-}
-
-Area Hwc2TestLayers::getBufferArea(hwc2_layer_t layer) const
-{
-    auto testLayer = mTestLayers.find(layer);
-    if (testLayer == mTestLayers.end())
-        [] () { GTEST_FAIL(); }();
-    return testLayer->second.getBufferArea();
-}
-
-hwc_color_t Hwc2TestLayers::getColor(hwc2_layer_t layer) const
-{
-    if (mTestLayers.count(layer) == 0) {
-        []() { GTEST_FAIL(); }();
-    }
-    return mTestLayers.at(layer).getColor();
-}
-
-hwc2_composition_t Hwc2TestLayers::getComposition(hwc2_layer_t layer) const
-{
-    if (mTestLayers.count(layer) == 0) {
-        []() { GTEST_FAIL(); }();
-    }
-    return mTestLayers.at(layer).getComposition();
-}
-
-hwc_rect_t Hwc2TestLayers::getCursorPosition(hwc2_layer_t layer) const
-{
-    if (mTestLayers.count(layer) == 0) {
-        []() { GTEST_FAIL(); }();
-    }
-    return mTestLayers.at(layer).getCursorPosition();
-}
-
-android::ui::Dataspace Hwc2TestLayers::getDataspace(hwc2_layer_t layer) const
-{
-    if (mTestLayers.count(layer) == 0) {
-        []() { GTEST_FAIL(); }();
-    }
-    return mTestLayers.at(layer).getDataspace();
-}
-
-hwc_rect_t Hwc2TestLayers::getDisplayFrame(hwc2_layer_t layer) const
-{
-    if (mTestLayers.count(layer) == 0) {
-        []() { GTEST_FAIL(); }();
-    }
-    return mTestLayers.at(layer).getDisplayFrame();
-}
-
-float Hwc2TestLayers::getPlaneAlpha(hwc2_layer_t layer) const
-{
-    if (mTestLayers.count(layer) == 0) {
-        []() { GTEST_FAIL(); }();
-    }
-    return mTestLayers.at(layer).getPlaneAlpha();
-}
-
-hwc_frect_t Hwc2TestLayers::getSourceCrop(hwc2_layer_t layer) const
-{
-    if (mTestLayers.count(layer) == 0) {
-        []() { GTEST_FAIL(); }();
-    }
-    return mTestLayers.at(layer).getSourceCrop();
-}
-
-hwc_region_t Hwc2TestLayers::getSurfaceDamage(hwc2_layer_t layer) const
-{
-    if (mTestLayers.count(layer) == 0) {
-        []() { GTEST_FAIL(); }();
-    }
-    return mTestLayers.at(layer).getSurfaceDamage();
-}
-
-hwc_transform_t Hwc2TestLayers::getTransform(hwc2_layer_t layer) const
-{
-    if (mTestLayers.count(layer) == 0) {
-        []() { GTEST_FAIL(); }();
-    }
-    return mTestLayers.at(layer).getTransform();
-}
-
-hwc_region_t Hwc2TestLayers::getVisibleRegion(hwc2_layer_t layer) const
-{
-    if (mTestLayers.count(layer) == 0) {
-        []() { GTEST_FAIL(); }();
-    }
-    return mTestLayers.at(layer).getVisibleRegion();
-}
-
-uint32_t Hwc2TestLayers::getZOrder(hwc2_layer_t layer) const
-{
-    if (mTestLayers.count(layer) == 0) {
-        []() { GTEST_FAIL(); }();
-    }
-    return mTestLayers.at(layer).getZOrder();
-}
-
-/* Sets the visible regions for a display. Returns false if the layers do not
- * cover the entire display or if a layer is not visible */
-bool Hwc2TestLayers::setVisibleRegions()
-{
-    /* The region of the display that is covered by layers above the current
-     * layer */
-    android::Region aboveOpaqueLayers;
-
-    bool optimized = true;
-
-    /* Iterate over test layers from max z order to min z order. */
-    for (auto& testLayer : mTestLayers) {
-        android::Region visibleRegion;
-
-        /* Set the visible region of this layer */
-        const hwc_rect_t displayFrame = testLayer.second.getDisplayFrame();
-
-        visibleRegion.set(android::Rect(displayFrame.left, displayFrame.top,
-                displayFrame.right, displayFrame.bottom));
-
-        /* Remove the area covered by opaque layers above this layer
-         * from this layer's visible region */
-        visibleRegion.subtractSelf(aboveOpaqueLayers);
-
-        testLayer.second.setVisibleRegion(visibleRegion);
-
-        /* If a layer is not visible, return false */
-        if (visibleRegion.isEmpty())
-            optimized = false;
-
-        /* If this layer is opaque, store the region it covers */
-        if (testLayer.second.getPlaneAlpha() == 1.0f)
-            aboveOpaqueLayers.orSelf(visibleRegion);
-    }
-
-    /* If the opaque region does not cover the entire display return false */
-    if (!aboveOpaqueLayers.isRect())
-        return false;
-
-    const auto rect = aboveOpaqueLayers.begin();
-    if (rect->left != 0 || rect->top != 0 || rect->right != mDisplayArea.width
-            || rect->bottom != mDisplayArea.height)
-        return false;
-
-    return optimized;
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h b/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h
deleted file mode 100644
index 909dd48..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestLayers.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef _HWC2_TEST_LAYERS_H
-#define _HWC2_TEST_LAYERS_H
-
-#include <map>
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-#include "Hwc2TestProperties.h"
-#include "Hwc2TestLayer.h"
-
-class Hwc2TestLayers {
-public:
-    Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers,
-            Hwc2TestCoverage coverage, const Area& displayArea);
-
-    Hwc2TestLayers(const std::vector<hwc2_layer_t>& layers,
-            Hwc2TestCoverage coverage, const Area& displayArea,
-            const std::unordered_map<Hwc2TestPropertyName,
-            Hwc2TestCoverage>& coverageExceptions);
-
-    std::string dump() const;
-
-    void reset();
-
-    bool advance();
-    bool advanceVisibleRegions();
-
-    /* Test cases with multiple layers and property values can take quite some
-     * time to run. A significant amount of time can be spent on test cases
-     * where one layer is changing property values but is not visible. To
-     * decrease runtime, this function can be called. Removes layouts where a
-     * layer is completely blocked from view. It also removes layouts that do
-     * not cover the entire display.*/
-    bool optimizeLayouts();
-
-    bool contains(hwc2_layer_t layer) const;
-
-    int  getBuffer(hwc2_layer_t layer, buffer_handle_t* outHandle,
-            int32_t* outAcquireFence);
-
-    hwc2_blend_mode_t      getBlendMode(hwc2_layer_t layer) const;
-    Area                   getBufferArea(hwc2_layer_t layer) const;
-    hwc_color_t            getColor(hwc2_layer_t layer) const;
-    hwc2_composition_t     getComposition(hwc2_layer_t layer) const;
-    hwc_rect_t             getCursorPosition(hwc2_layer_t layer) const;
-    android::ui::Dataspace     getDataspace(hwc2_layer_t layer) const;
-    hwc_rect_t             getDisplayFrame(hwc2_layer_t layer) const;
-    android_pixel_format_t getFormat(hwc2_layer_t layer) const;
-    float                  getPlaneAlpha(hwc2_layer_t layer) const;
-    hwc_frect_t            getSourceCrop(hwc2_layer_t layer) const;
-    hwc_region_t           getSurfaceDamage(hwc2_layer_t layer) const;
-    hwc_transform_t        getTransform(hwc2_layer_t layer) const;
-    hwc_region_t           getVisibleRegion(hwc2_layer_t layer) const;
-    uint32_t               getZOrder(hwc2_layer_t layer) const;
-
-private:
-    bool setVisibleRegions();
-
-    std::map<hwc2_layer_t, Hwc2TestLayer> mTestLayers;
-
-    Area mDisplayArea;
-
-    bool mOptimize = false;
-};
-
-#endif /* ifndef _HWC2_TEST_LAYERS_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
deleted file mode 100644
index 904b927..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2017 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 <sstream>
-#include <android/hardware/graphics/common/1.0/types.h>
-
-#include "Hwc2TestPixelComparator.h"
-
-using android::hardware::graphics::common::V1_0::BufferUsage;
-
-uint32_t ComparatorResult::getPixel(int32_t x, int32_t y, uint32_t stride,
-        uint8_t* img) const
-{
-    uint32_t r = img[(y * stride + x) * 4 + 0];
-    uint32_t g = img[(y * stride + x) * 4 + 1];
-    uint32_t b = img[(y * stride + x) * 4 + 2];
-    uint32_t a = img[(y * stride + x) * 4 + 3];
-
-    uint32_t pixel = 0;
-    pixel |= r;
-    pixel |= g << 8;
-    pixel |= b << 16;
-    pixel |= a << 24;
-    return pixel;
-}
-
-void ComparatorResult::CompareBuffers(
-        android::sp<android::GraphicBuffer>& resultBuffer,
-        android::sp<android::GraphicBuffer>& expectedBuffer)
-{
-    uint8_t* resultBufferImg;
-    uint8_t* expectedBufferImg;
-    resultBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN),
-            (void**)(&resultBufferImg));
-
-    expectedBuffer->lock(static_cast<uint32_t>(BufferUsage::CPU_READ_OFTEN),
-            (void**)(&expectedBufferImg));
-    mComparisons.clear();
-    int32_t mDifferentPixelCount = 0;
-    int32_t mBlankPixelCount = 0;
-
-    for (uint32_t y = 0; y < resultBuffer->getHeight(); y++) {
-        for (uint32_t x = 0; x < resultBuffer->getWidth(); x++) {
-            uint32_t result = getPixel(x, y, resultBuffer->getStride(),
-                    resultBufferImg);
-            uint32_t expected = getPixel(x, y, expectedBuffer->getStride(),
-                    expectedBufferImg);
-
-            if (result == 0)
-                mBlankPixelCount++;
-
-            if (result != expected)
-                mDifferentPixelCount++;
-
-            mComparisons.emplace_back(std::make_tuple(x, y, result, expected));
-        }
-    }
-    resultBuffer->unlock();
-    expectedBuffer->unlock();
-}
-
-std::string ComparatorResult::pixelDiff(uint32_t x, uint32_t y,
-        uint32_t resultPixel, uint32_t expectedPixel) const
-{
-    uint32_t resultAlpha = (resultPixel >> 24) & 0xFF;
-    uint32_t resultBlue = (resultPixel >> 16) & 0xFF;
-    uint32_t resultGreen = (resultPixel >> 8) & 0xFF;
-    uint32_t resultRed = resultPixel & 0xFF;
-
-    uint32_t expectedAlpha = (expectedPixel >> 24) & 0xFF;
-    uint32_t expectedBlue = (expectedPixel >> 16) & 0xFF;
-    uint32_t expectedGreen = (expectedPixel >> 8) & 0xFF;
-    uint32_t expectedRed = expectedPixel & 0xFF;
-
-    std::ostringstream stream;
-
-    stream << "x: " << x << " y: " << y << std::endl;
-    stream << std::hex;
-    stream << "Result pixel:   " << resultRed << "|" << resultGreen << "|"
-           << resultBlue << "|" << resultAlpha << std::endl;
-
-    stream << "Expected pixel: " << expectedRed << "|" << expectedGreen << "|"
-           << expectedBlue << "|" << expectedAlpha << std::endl;
-
-    return stream.str();
-}
-
-std::string ComparatorResult::dumpComparison() const
-{
-    std::ostringstream stream;
-    stream << "Number of different pixels: " << mDifferentPixelCount;
-
-    for (const auto& comparison : mComparisons) {
-        if (std::get<2>(comparison) != std::get<3>(comparison))
-            stream << pixelDiff(std::get<0>(comparison),
-                    std::get<1>(comparison), std::get<2>(comparison),
-                    std::get<3>(comparison));
-    }
-    return stream.str();
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h b/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h
deleted file mode 100644
index 55fa936..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestPixelComparator.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-#ifndef _HWC2_TEST_PIXEL_COMPARATOR_H
-#define _HWC2_TEST_PIXEL_COMPARATOR_H
-
-#include <ui/GraphicBuffer.h>
-#include <cstdint>
-#include <string>
-#include <utility>
-#include <vector>
-
-class ComparatorResult {
-public:
-    static ComparatorResult& get()
-    {
-        static ComparatorResult instance;
-        return instance;
-    }
-
-    void CompareBuffers(android::sp<android::GraphicBuffer>& resultBuffer,
-            android::sp<android::GraphicBuffer>& expectedBuffer);
-
-    std::string dumpComparison() const;
-
-    ComparatorResult(const ComparatorResult&) = delete;
-    ComparatorResult(ComparatorResult&&) = delete;
-    ComparatorResult& operator=(ComparatorResult const&) = delete;
-    ComparatorResult& operator=(ComparatorResult&&) = delete;
-
-    int32_t getDifferentPixelCount() const { return mDifferentPixelCount; }
-    int32_t getBlankPixelCount() const { return mBlankPixelCount; }
-
-private:
-    ComparatorResult() = default;
-    uint32_t getPixel(int32_t x, int32_t y, uint32_t stride, uint8_t* img) const;
-    std::string pixelDiff(uint32_t x, uint32_t y, uint32_t resultPixel,
-            uint32_t expectedPixel) const;
-
-    int32_t mDifferentPixelCount;
-    int32_t mBlankPixelCount;
-    /* std::tuple<X coordinate, Y coordinate, resultPixel, expectedPixel> */
-    std::vector<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t>>
-            mComparisons;
-};
-
-#endif /* ifndef _HWC2_TEST_PIXEL_COMPARATOR_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
deleted file mode 100644
index c5b92d0..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.cpp
+++ /dev/null
@@ -1,782 +0,0 @@
-/*
- * Copyright (C) 2016 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 <sstream>
-#include <cutils/log.h>
-#include <ui/Rect.h>
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-#include "Hwc2TestBuffer.h"
-#include "Hwc2TestProperties.h"
-
-Hwc2TestBufferArea::Hwc2TestBufferArea(Hwc2TestCoverage coverage,
-        const Area& displayArea)
-    : Hwc2TestProperty(mBufferAreas, mCompositionSupport),
-      mScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteScalars:
-            (coverage == Hwc2TestCoverage::Basic)? mBasicScalars:
-            mDefaultScalars),
-      mDisplayArea(displayArea)
-{
-    update();
-}
-
-std::string Hwc2TestBufferArea::dump() const
-{
-    std::stringstream dmp;
-    const Area& curr = get();
-    dmp << "\tbuffer area: width " << curr.width << ", height " << curr.height
-            << "\n";
-    return dmp.str();
-}
-
-void Hwc2TestBufferArea::setDependent(Hwc2TestBuffer* buffer)
-{
-    mBuffer = buffer;
-    if (buffer) {
-        buffer->updateBufferArea(get());
-    }
-}
-
-void Hwc2TestBufferArea::setDependent(Hwc2TestSourceCrop* sourceCrop)
-{
-    mSourceCrop = sourceCrop;
-    if (mSourceCrop) {
-        mSourceCrop->updateBufferArea(get());
-    }
-}
-
-void Hwc2TestBufferArea::setDependent(Hwc2TestSurfaceDamage* surfaceDamage)
-{
-    mSurfaceDamage = surfaceDamage;
-    if (mSurfaceDamage) {
-        mSurfaceDamage->updateBufferArea(get());
-    }
-}
-
-void Hwc2TestBufferArea::update()
-{
-    mBufferAreas.clear();
-
-    if (mDisplayArea.width == 0 && mDisplayArea.height == 0) {
-        mBufferAreas.push_back({0, 0});
-        return;
-    }
-
-    for (auto scalar : mScalars) {
-        mBufferAreas.push_back({static_cast<int32_t>(scalar * mDisplayArea.width),
-                static_cast<int32_t>(scalar * mDisplayArea.height)});
-    }
-
-    updateDependents();
-}
-
-void Hwc2TestBufferArea::updateDependents()
-{
-    const Area& curr = get();
-
-    if (mBuffer)
-        mBuffer->updateBufferArea(curr);
-    if (mSourceCrop)
-        mSourceCrop->updateBufferArea(curr);
-    if (mSurfaceDamage)
-        mSurfaceDamage->updateBufferArea(curr);
-}
-
-const std::vector<float> Hwc2TestBufferArea::mDefaultScalars = {
-    1.0f,
-};
-
-const std::vector<float> Hwc2TestBufferArea::mBasicScalars = {
-    1.0f, 0.5f,
-};
-
-const std::vector<float> Hwc2TestBufferArea::mCompleteScalars = {
-    1.0f, 0.75f, 0.5f
-};
-
-
-Hwc2TestBlendMode::Hwc2TestBlendMode(Hwc2TestCoverage coverage)
-    : Hwc2TestProperty(coverage, mCompleteBlendModes, mBasicBlendModes,
-            mDefaultBlendModes, mCompositionSupport) { }
-
-std::string Hwc2TestBlendMode::dump() const
-{
-    std::stringstream dmp;
-    dmp << "\tblend mode: " << getBlendModeName(get()) << "\n";
-    return dmp.str();
-}
-
-void Hwc2TestBlendMode::setDependent(Hwc2TestColor* color)
-{
-    mColor = color;
-    updateDependents();
-}
-
-void Hwc2TestBlendMode::updateDependents()
-{
-    if (mColor)
-        mColor->updateBlendMode(get());
-}
-
-const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mDefaultBlendModes = {
-    HWC2_BLEND_MODE_NONE,
-};
-
-const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mBasicBlendModes = {
-    HWC2_BLEND_MODE_NONE,
-    HWC2_BLEND_MODE_PREMULTIPLIED,
-};
-
-const std::vector<hwc2_blend_mode_t> Hwc2TestBlendMode::mCompleteBlendModes = {
-    HWC2_BLEND_MODE_NONE,
-    HWC2_BLEND_MODE_PREMULTIPLIED,
-    HWC2_BLEND_MODE_COVERAGE,
-};
-
-
-Hwc2TestColor::Hwc2TestColor(Hwc2TestCoverage coverage,
-        hwc2_blend_mode_t blendMode)
-    : Hwc2TestProperty(mColors, mCompositionSupport),
-      mBaseColors((coverage == Hwc2TestCoverage::Complete)? mCompleteBaseColors:
-            (coverage == Hwc2TestCoverage::Basic)? mBasicBaseColors:
-            mDefaultBaseColors),
-      mBlendMode(blendMode)
-{
-    update();
-}
-
-std::string Hwc2TestColor::dump() const
-{
-    std::stringstream dmp;
-    const hwc_color_t& color = get();
-    dmp << "\tcolor: r " << std::to_string(color.r) << ", g "
-            << std::to_string(color.g) << ", b " << std::to_string(color.b)
-            << ", a " << std::to_string(color.a) << "\n";
-    return dmp.str();
-}
-
-void Hwc2TestColor::updateBlendMode(hwc2_blend_mode_t blendMode)
-{
-    mBlendMode = blendMode;
-    update();
-}
-
-void Hwc2TestColor::update()
-{
-    if (mBlendMode != HWC2_BLEND_MODE_PREMULTIPLIED) {
-        mColors = mBaseColors;
-        return;
-    }
-
-    mColors.clear();
-
-    for (const hwc_color_t& baseColor : mBaseColors) {
-        if (baseColor.a >= baseColor.r && baseColor.a >= baseColor.g
-                && baseColor.a >= baseColor.b) {
-            mColors.push_back(baseColor);
-        }
-    }
-
-}
-
-const std::vector<hwc_color_t> Hwc2TestColor::mDefaultBaseColors = {
-    {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX},
-};
-
-const std::vector<hwc_color_t> Hwc2TestColor::mBasicBaseColors = {
-    {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX},
-    {        0,         0,         0,         0},
-};
-
-const std::vector<hwc_color_t> Hwc2TestColor::mCompleteBaseColors = {
-    {UINT8_MAX, UINT8_MAX, UINT8_MAX, UINT8_MAX},
-    {UINT8_MAX, UINT8_MAX, UINT8_MAX,         0},
-    {UINT8_MAX, UINT8_MAX,         0, UINT8_MAX},
-    {UINT8_MAX, UINT8_MAX,         0,         0},
-    {UINT8_MAX,         0, UINT8_MAX, UINT8_MAX},
-    {UINT8_MAX,         0, UINT8_MAX,         0},
-    {UINT8_MAX,         0,         0, UINT8_MAX},
-    {UINT8_MAX,         0,         0,         0},
-    {        0, UINT8_MAX, UINT8_MAX, UINT8_MAX},
-    {        0, UINT8_MAX, UINT8_MAX,         0},
-    {        0, UINT8_MAX,         0, UINT8_MAX},
-    {        0, UINT8_MAX,         0,         0},
-    {        0,         0, UINT8_MAX, UINT8_MAX},
-    {        0,         0, UINT8_MAX,         0},
-    {        0,         0,         0, UINT8_MAX},
-    {        0,         0,         0,         0},
-};
-
-
-Hwc2TestComposition::Hwc2TestComposition(Hwc2TestCoverage coverage)
-    : Hwc2TestProperty(coverage, mCompleteCompositions, mBasicCompositions,
-            mDefaultCompositions, mCompositionSupport) { }
-
-std::string Hwc2TestComposition::dump() const
-{
-    std::stringstream dmp;
-    dmp << "\tcomposition: " << getCompositionName(get()) << "\n";
-    return dmp.str();
-}
-
-const std::vector<hwc2_composition_t> Hwc2TestComposition::mDefaultCompositions = {
-    HWC2_COMPOSITION_DEVICE,
-};
-
-const std::vector<hwc2_composition_t> Hwc2TestComposition::mBasicCompositions = {
-    HWC2_COMPOSITION_CLIENT,
-    HWC2_COMPOSITION_DEVICE,
-};
-
-const std::vector<hwc2_composition_t> Hwc2TestComposition::mCompleteCompositions = {
-    HWC2_COMPOSITION_CLIENT,
-    HWC2_COMPOSITION_DEVICE,
-    HWC2_COMPOSITION_SOLID_COLOR,
-    HWC2_COMPOSITION_CURSOR,
-    HWC2_COMPOSITION_SIDEBAND,
-};
-
-
-Hwc2TestDataspace::Hwc2TestDataspace(Hwc2TestCoverage coverage)
-    : Hwc2TestProperty(coverage, completeDataspaces, basicDataspaces,
-            defaultDataspaces, mCompositionSupport) { }
-
-std::string Hwc2TestDataspace::dump() const
-{
-    std::stringstream dmp;
-    dmp << "\tdataspace: " << static_cast<int32_t>(get()) << "\n";
-    return dmp.str();
-}
-
-const std::vector<android::ui::Dataspace> Hwc2TestDataspace::defaultDataspaces = {
-    android::ui::Dataspace::UNKNOWN,
-};
-
-const std::vector<android::ui::Dataspace> Hwc2TestDataspace::basicDataspaces = {
-    android::ui::Dataspace::UNKNOWN,
-    android::ui::Dataspace::V0_SRGB,
-};
-
-const std::vector<android::ui::Dataspace> Hwc2TestDataspace::completeDataspaces = {
-    android::ui::Dataspace::UNKNOWN,
-    android::ui::Dataspace::ARBITRARY,
-    android::ui::Dataspace::STANDARD_SHIFT,
-    android::ui::Dataspace::STANDARD_MASK,
-    android::ui::Dataspace::STANDARD_UNSPECIFIED,
-    android::ui::Dataspace::STANDARD_BT709,
-    android::ui::Dataspace::STANDARD_BT601_625,
-    android::ui::Dataspace::STANDARD_BT601_625_UNADJUSTED,
-    android::ui::Dataspace::STANDARD_BT601_525,
-    android::ui::Dataspace::STANDARD_BT601_525_UNADJUSTED,
-    android::ui::Dataspace::STANDARD_BT2020,
-    android::ui::Dataspace::STANDARD_BT2020_CONSTANT_LUMINANCE,
-    android::ui::Dataspace::STANDARD_BT470M,
-    android::ui::Dataspace::STANDARD_FILM,
-    android::ui::Dataspace::TRANSFER_SHIFT,
-    android::ui::Dataspace::TRANSFER_MASK,
-    android::ui::Dataspace::TRANSFER_UNSPECIFIED,
-    android::ui::Dataspace::TRANSFER_LINEAR,
-    android::ui::Dataspace::TRANSFER_SRGB,
-    android::ui::Dataspace::TRANSFER_SMPTE_170M,
-    android::ui::Dataspace::TRANSFER_GAMMA2_2,
-    android::ui::Dataspace::TRANSFER_GAMMA2_8,
-    android::ui::Dataspace::TRANSFER_ST2084,
-    android::ui::Dataspace::TRANSFER_HLG,
-    android::ui::Dataspace::RANGE_SHIFT,
-    android::ui::Dataspace::RANGE_MASK,
-    android::ui::Dataspace::RANGE_UNSPECIFIED,
-    android::ui::Dataspace::RANGE_FULL,
-    android::ui::Dataspace::RANGE_LIMITED,
-    android::ui::Dataspace::SRGB_LINEAR,
-    android::ui::Dataspace::V0_SRGB_LINEAR,
-    android::ui::Dataspace::SRGB,
-    android::ui::Dataspace::V0_SRGB,
-    android::ui::Dataspace::JFIF,
-    android::ui::Dataspace::V0_JFIF,
-    android::ui::Dataspace::BT601_625,
-    android::ui::Dataspace::V0_BT601_625,
-    android::ui::Dataspace::BT601_525,
-    android::ui::Dataspace::V0_BT601_525,
-    android::ui::Dataspace::BT709,
-    android::ui::Dataspace::V0_BT709,
-    android::ui::Dataspace::DEPTH,
-};
-
-
-Hwc2TestDisplayDimension::Hwc2TestDisplayDimension(Hwc2TestCoverage coverage)
-    : Hwc2TestProperty(
-            (coverage == Hwc2TestCoverage::Complete)? mCompleteDisplayDimensions:
-            (coverage == Hwc2TestCoverage::Basic)? mBasicDisplayDimensions:
-            mDefaultDisplayDimensions, mCompositionSupport) { }
-
-std::string Hwc2TestDisplayDimension::dump() const
-{
-    std::stringstream dmp;
-    const UnsignedArea& curr = get();
-    dmp << "\tdisplay dimension: " << curr.width<< " x " << curr.height<< "\n";
-    return dmp.str();
-}
-
-void Hwc2TestDisplayDimension::setDependent(Hwc2TestVirtualBuffer* buffer)
-{
-    mBuffers.insert(buffer);
-    updateDependents();
-}
-
-void Hwc2TestDisplayDimension::updateDependents()
-{
-    const UnsignedArea& curr = get();
-
-    for (Hwc2TestVirtualBuffer* buffer : mBuffers)
-        buffer->updateBufferArea({static_cast<int32_t>(curr.width),
-                static_cast<int32_t>(curr.height)});
-}
-
-const std::vector<UnsignedArea>
-        Hwc2TestDisplayDimension::mDefaultDisplayDimensions = {
-    {1920, 1080},
-};
-
-const std::vector<UnsignedArea>
-        Hwc2TestDisplayDimension::mBasicDisplayDimensions = {
-    {640, 480},
-    {1280, 720},
-    {1920, 1080},
-    {1920, 1200},
-};
-
-const std::vector<UnsignedArea>
-        Hwc2TestDisplayDimension::mCompleteDisplayDimensions = {
-    {320, 240},
-    {480, 320},
-    {640, 480},
-    {1280, 720},
-    {1920, 1080},
-    {1920, 1200},
-    {2560, 1440},
-    {2560, 1600},
-    {3840, 2160},
-    {4096, 2160},
-};
-
-
-Hwc2TestDisplayFrame::Hwc2TestDisplayFrame(Hwc2TestCoverage coverage,
-        const Area& displayArea)
-    : Hwc2TestProperty(mDisplayFrames, mCompositionSupport),
-      mFrectScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteFrectScalars:
-            (coverage == Hwc2TestCoverage::Basic)? mBasicFrectScalars:
-            mDefaultFrectScalars),
-      mDisplayArea(displayArea)
-{
-    update();
-}
-
-std::string Hwc2TestDisplayFrame::dump() const
-{
-    std::stringstream dmp;
-    const hwc_rect_t& displayFrame = get();
-    dmp << "\tdisplay frame: left " << displayFrame.left << ", top "
-            << displayFrame.top << ", right " << displayFrame.right
-            << ", bottom " << displayFrame.bottom << "\n";
-    return dmp.str();
-}
-
-void Hwc2TestDisplayFrame::update()
-{
-    mDisplayFrames.clear();
-
-    if (mDisplayArea.width == 0 && mDisplayArea.height == 0) {
-        mDisplayFrames.push_back({0, 0, 0, 0});
-        return;
-    }
-
-    for (const auto& frectScalar : mFrectScalars) {
-        mDisplayFrames.push_back({
-                static_cast<int>(frectScalar.left * mDisplayArea.width),
-                static_cast<int>(frectScalar.top * mDisplayArea.height),
-                static_cast<int>(frectScalar.right * mDisplayArea.width),
-                static_cast<int>(frectScalar.bottom * mDisplayArea.height)});
-    }
-}
-
-const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mDefaultFrectScalars = {
-    {0.0, 0.0, 1.0, 1.0},
-};
-
-const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mBasicFrectScalars = {
-    {0.0, 0.0, 1.0, 1.0},
-    {0.0, 0.0, 1.0, 0.05},
-    {0.0, 0.95, 1.0, 1.0},
-};
-
-const std::vector<hwc_frect_t> Hwc2TestDisplayFrame::mCompleteFrectScalars = {
-    {0.0, 0.0, 1.0, 1.0},
-    {0.0, 0.05, 1.0, 0.95},
-    {0.0, 0.05, 1.0, 1.0},
-    {0.0, 0.0, 1.0, 0.05},
-    {0.0, 0.95, 1.0, 1.0},
-    {0.25, 0.0, 0.75, 0.35},
-    {0.25, 0.25, 0.75, 0.75},
-};
-
-
-Hwc2TestPlaneAlpha::Hwc2TestPlaneAlpha(Hwc2TestCoverage coverage)
-    : Hwc2TestProperty(coverage, mCompletePlaneAlphas, mBasicPlaneAlphas,
-            mDefaultPlaneAlphas, mCompositionSupport) { }
-
-std::string Hwc2TestPlaneAlpha::dump() const
-{
-    std::stringstream dmp;
-    dmp << "\tplane alpha: " << get() << "\n";
-    return dmp.str();
-}
-
-const std::vector<float> Hwc2TestPlaneAlpha::mDefaultPlaneAlphas = {
-    1.0f,
-};
-
-const std::vector<float> Hwc2TestPlaneAlpha::mBasicPlaneAlphas = {
-    1.0f, 0.0f,
-};
-
-const std::vector<float> Hwc2TestPlaneAlpha::mCompletePlaneAlphas = {
-    1.0f, 0.75f, 0.5f, 0.25f, 0.0f,
-};
-
-
-Hwc2TestSourceCrop::Hwc2TestSourceCrop(Hwc2TestCoverage coverage,
-        const Area& bufferArea)
-    : Hwc2TestProperty(mSourceCrops, mCompositionSupport),
-      mFrectScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteFrectScalars:
-            (coverage == Hwc2TestCoverage::Basic)? mBasicFrectScalars:
-            mDefaultFrectScalars),
-      mBufferArea(bufferArea)
-{
-    update();
-}
-
-std::string Hwc2TestSourceCrop::dump() const
-{
-    std::stringstream dmp;
-    const hwc_frect_t& sourceCrop = get();
-    dmp << "\tsource crop: left " << sourceCrop.left << ", top "
-            << sourceCrop.top << ", right " << sourceCrop.right << ", bottom "
-            << sourceCrop.bottom << "\n";
-    return dmp.str();
-}
-
-void Hwc2TestSourceCrop::updateBufferArea(const Area& bufferArea)
-{
-    mBufferArea = bufferArea;
-    update();
-}
-
-void Hwc2TestSourceCrop::update()
-{
-    mSourceCrops.clear();
-
-    if (mBufferArea.width == 0 && mBufferArea.height == 0) {
-        mSourceCrops.push_back({0, 0, 0, 0});
-        return;
-    }
-
-    for (const auto& frectScalar : mFrectScalars) {
-        mSourceCrops.push_back({
-                frectScalar.left * mBufferArea.width,
-                frectScalar.top * mBufferArea.height,
-                frectScalar.right * mBufferArea.width,
-                frectScalar.bottom * mBufferArea.height});
-    }
-}
-
-const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mDefaultFrectScalars = {
-    {0.0, 0.0, 1.0, 1.0},
-};
-
-const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mBasicFrectScalars = {
-    {0.0, 0.0, 1.0, 1.0},
-    {0.0, 0.0, 0.5, 0.5},
-    {0.5, 0.5, 1.0, 1.0},
-};
-
-const std::vector<hwc_frect_t> Hwc2TestSourceCrop::mCompleteFrectScalars = {
-    {0.0, 0.0, 1.0, 1.0},
-    {0.0, 0.0, 0.5, 0.5},
-    {0.5, 0.5, 1.0, 1.0},
-    {0.0, 0.0, 0.25, 0.25},
-    {0.25, 0.25, 0.75, 0.75},
-};
-
-
-Hwc2TestSurfaceDamage::Hwc2TestSurfaceDamage(Hwc2TestCoverage coverage)
-    : Hwc2TestProperty(mSurfaceDamages, mCompositionSupport),
-      mRegionScalars((coverage == Hwc2TestCoverage::Complete)? mCompleteRegionScalars:
-            (coverage == Hwc2TestCoverage::Basic)? mBasicRegionScalars:
-            mDefaultRegionScalars)
-{
-    update();
-}
-
-Hwc2TestSurfaceDamage::~Hwc2TestSurfaceDamage()
-{
-    freeSurfaceDamages();
-}
-
-std::string Hwc2TestSurfaceDamage::dump() const
-{
-    std::stringstream dmp;
-
-    const hwc_region_t& curr = get();
-    dmp << "\tsurface damage: region count " << curr.numRects << "\n";
-    for (size_t i = 0; i < curr.numRects; i++) {
-        const hwc_rect_t& rect = curr.rects[i];
-        dmp << "\t\trect: left " << rect.left << ", top " << rect.top
-                << ", right " << rect.right << ", bottom " << rect.bottom << "\n";
-    }
-
-    return dmp.str();
-}
-
-void Hwc2TestSurfaceDamage::updateBufferArea(const Area& bufferArea)
-{
-    mBufferArea = bufferArea;
-    update();
-}
-
-void Hwc2TestSurfaceDamage::update()
-{
-    freeSurfaceDamages();
-
-    if (mBufferArea.width == 0 && mBufferArea.height == 0) {
-        mSurfaceDamages.push_back({0, nullptr});
-        return;
-    }
-
-    hwc_region_t damage;
-
-    for (const auto& regionScalar : mRegionScalars) {
-        damage.numRects = regionScalar.size();
-
-        if (damage.numRects > 0) {
-            hwc_rect_t* rects = new hwc_rect_t[damage.numRects];
-            if (!rects) {
-                ALOGW("failed to allocate new hwc_rect_t array");
-                continue;
-            }
-
-            for (size_t i = 0; i < damage.numRects; i++) {
-                rects[i].left = regionScalar[i].left * mBufferArea.width;
-                rects[i].top = regionScalar[i].top * mBufferArea.height;
-                rects[i].right = regionScalar[i].right * mBufferArea.width;
-                rects[i].bottom = regionScalar[i].bottom * mBufferArea.height;
-            }
-
-            damage.rects = static_cast<hwc_rect_t const*>(rects);
-        } else {
-            damage.rects = nullptr;
-        }
-
-        mSurfaceDamages.push_back(damage);
-    }
-}
-
-void Hwc2TestSurfaceDamage::freeSurfaceDamages()
-{
-    for (const auto& surfaceDamage : mSurfaceDamages) {
-        if (surfaceDamage.numRects > 0 && surfaceDamage.rects)
-            delete[] surfaceDamage.rects;
-    }
-    mSurfaceDamages.clear();
-}
-
-const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mDefaultRegionScalars = {
-    {{}},
-};
-
-const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mBasicRegionScalars = {
-    {{}},
-    {{0.0, 0.0, 1.0, 1.0}},
-};
-
-const std::vector<std::vector<hwc_frect_t>> Hwc2TestSurfaceDamage::mCompleteRegionScalars = {
-    {{}},
-    {{0.0, 0.0, 1.0, 1.0}},
-    {{0.0, 0.0, 0.5, 0.5}, {0.5, 0.5, 1.0, 1.0}},
-};
-
-
-Hwc2TestTransform::Hwc2TestTransform(Hwc2TestCoverage coverage)
-    : Hwc2TestProperty(coverage, mCompleteTransforms, mBasicTransforms,
-            mDefaultTransforms, mCompositionSupport) { }
-
-std::string Hwc2TestTransform::dump() const
-{
-    std::stringstream dmp;
-    dmp << "\ttransform: " << getTransformName(get()) << "\n";
-    return dmp.str();
-}
-
-const std::vector<hwc_transform_t> Hwc2TestTransform::mDefaultTransforms = {
-    static_cast<hwc_transform_t>(0),
-};
-
-const std::vector<hwc_transform_t> Hwc2TestTransform::mBasicTransforms = {
-    static_cast<hwc_transform_t>(0),
-    HWC_TRANSFORM_FLIP_H,
-    HWC_TRANSFORM_FLIP_V,
-    HWC_TRANSFORM_ROT_90,
-};
-
-const std::vector<hwc_transform_t> Hwc2TestTransform::mCompleteTransforms = {
-    static_cast<hwc_transform_t>(0),
-    HWC_TRANSFORM_FLIP_H,
-    HWC_TRANSFORM_FLIP_V,
-    HWC_TRANSFORM_ROT_90,
-    HWC_TRANSFORM_ROT_180,
-    HWC_TRANSFORM_ROT_270,
-    HWC_TRANSFORM_FLIP_H_ROT_90,
-    HWC_TRANSFORM_FLIP_V_ROT_90,
-};
-
-
-Hwc2TestVisibleRegion::~Hwc2TestVisibleRegion()
-{
-    release();
-}
-
-std::string Hwc2TestVisibleRegion::dump() const
-{
-    std::stringstream dmp;
-
-    const hwc_region_t& curr = get();
-    dmp << "\tvisible region: region count " << curr.numRects << "\n";
-    for (size_t i = 0; i < curr.numRects; i++) {
-        const hwc_rect_t& rect = curr.rects[i];
-        dmp << "\t\trect: left " << rect.left << ", top " << rect.top
-                << ", right " << rect.right << ", bottom " << rect.bottom << "\n";
-    }
-
-    return dmp.str();
-}
-
-void Hwc2TestVisibleRegion::set(const android::Region& visibleRegion)
-{
-    release();
-
-    size_t size = 0;
-    const android::Rect* rects = visibleRegion.getArray(&size);
-
-    mVisibleRegion.numRects = size;
-    mVisibleRegion.rects = nullptr;
-
-    if (size > 0) {
-        hwc_rect_t* hwcRects = new hwc_rect_t[size];
-        for (size_t i = 0; i < size; i++) {
-            hwcRects[i].left = rects[i].left;
-            hwcRects[i].top = rects[i].top;
-            hwcRects[i].right = rects[i].right;
-            hwcRects[i].bottom = rects[i].bottom;
-        }
-        mVisibleRegion.rects = hwcRects;
-    }
-}
-
-hwc_region_t Hwc2TestVisibleRegion::get() const
-{
-    return mVisibleRegion;
-}
-
-void Hwc2TestVisibleRegion::release()
-{
-    if (mVisibleRegion.numRects > 0 && mVisibleRegion.rects)
-        delete[] mVisibleRegion.rects;
-    mVisibleRegion.rects = nullptr;
-    mVisibleRegion.numRects = 0;
-}
-
-/* Identifies which layer properties are supported by each composition type.
- * hwc2_composition_t values range from:
- *  HWC2_COMPOSITION_INVALID = 0,
- *  HWC2_COMPOSITION_CLIENT = 1,
- *  HWC2_COMPOSITION_DEVICE = 2,
- *  HWC2_COMPOSITION_SOLID_COLOR = 3,
- *  HWC2_COMPOSITION_CURSOR = 4,
- *  HWC2_COMPOSITION_SIDEBAND = 5,
- *
- * Each property array can be indexed by a hwc2_composition_t value.
- * By using an array instead of a more complex data structure, runtimes for
- * some test cases showed a noticeable improvement.
- */
-
-/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
-const std::array<bool, 6> Hwc2TestBufferArea::mCompositionSupport = {{
-    false,   true,    true,    false,   true,    true,
-}};
-
-/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
-const std::array<bool, 6> Hwc2TestBlendMode::mCompositionSupport = {{
-    false,   true,    true,    false,   true,    true,
-}};
-
-/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
-const std::array<bool, 6> Hwc2TestColor::mCompositionSupport = {{
-    false,   false,   false,   true,    false,   false,
-}};
-
-/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
-const std::array<bool, 6> Hwc2TestComposition::mCompositionSupport = {{
-    false,   true,    true,    true,    true,    true,
-}};
-
-/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
-const std::array<bool, 6> Hwc2TestDataspace::mCompositionSupport = {{
-    false,   true,    true,    true,    true,    false,
-}};
-
-/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
-const std::array<bool, 6> Hwc2TestDisplayDimension::mCompositionSupport = {{
-    false,   true,    true,    true,    true,    true,
-}};
-
-/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
-const std::array<bool, 6> Hwc2TestDisplayFrame::mCompositionSupport = {{
-    false,   true,    true,    true,    false,   true,
-}};
-
-/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
-const std::array<bool, 6> Hwc2TestPlaneAlpha::mCompositionSupport = {{
-    false,   true,    true,    true,    true,    true,
-}};
-
-/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
-const std::array<bool, 6> Hwc2TestSourceCrop::mCompositionSupport = {{
-    false,   true,    true,    false,   true,    false,
-}};
-
-/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
-const std::array<bool, 6> Hwc2TestSurfaceDamage::mCompositionSupport = {{
-    false,   false,   true,    false,   true,    false,
-}};
-
-/*  INVALID  CLIENT   DEVICE   COLOR    CURSOR   SIDEBAND */
-const std::array<bool, 6> Hwc2TestTransform::mCompositionSupport = {{
-    false,   true,    true,    false,   true,    true,
-}};
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h b/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
deleted file mode 100644
index 06ae314..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestProperties.h
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef _HWC2_TEST_PROPERTIES_H
-#define _HWC2_TEST_PROPERTIES_H
-
-#include <array>
-#include <vector>
-
-#include <ui/GraphicTypes.h>
-#include <ui/Region.h>
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-enum class Hwc2TestCoverage {
-    Default = 0,
-    Basic,
-    Complete,
-};
-
-enum class Hwc2TestPropertyName {
-    BlendMode = 1,
-    BufferArea,
-    Color,
-    Composition,
-    CursorPosition,
-    Dataspace,
-    DisplayFrame,
-    PlaneAlpha,
-    SourceCrop,
-    SurfaceDamage,
-    Transform,
-};
-
-typedef struct {
-    int32_t width;
-    int32_t height;
-} Area;
-
-
-typedef struct {
-    uint32_t width;
-    uint32_t height;
-} UnsignedArea;
-
-
-class Hwc2TestContainer {
-public:
-    virtual ~Hwc2TestContainer() = default;
-
-    /* Resets the container */
-    virtual void reset() = 0;
-
-    /* Attempts to advance to the next valid value. Returns true if one can be
-     * found */
-    virtual bool advance() = 0;
-
-    virtual std::string dump() const = 0;
-
-    /* Returns true if the container supports the given composition type */
-    virtual bool isSupported(hwc2_composition_t composition) = 0;
-};
-
-
-template <class T>
-class Hwc2TestProperty : public Hwc2TestContainer {
-public:
-    Hwc2TestProperty(Hwc2TestCoverage coverage,
-            const std::vector<T>& completeList, const std::vector<T>& basicList,
-            const std::vector<T>& defaultList,
-            const std::array<bool, 6>& compositionSupport)
-        : Hwc2TestProperty((coverage == Hwc2TestCoverage::Complete)? completeList:
-                (coverage == Hwc2TestCoverage::Basic)? basicList : defaultList,
-                compositionSupport) { }
-
-    Hwc2TestProperty(const std::vector<T>& list,
-            const std::array<bool, 6>& compositionSupport)
-        : mList(list),
-          mCompositionSupport(compositionSupport) { }
-
-    void reset() override
-    {
-        mListIdx = 0;
-    }
-
-    bool advance() override
-    {
-        if (mListIdx + 1 < mList.size()) {
-            mListIdx++;
-            updateDependents();
-            return true;
-        }
-        reset();
-        updateDependents();
-        return false;
-    }
-
-    T get() const
-    {
-        return mList.at(mListIdx);
-    }
-
-    virtual bool isSupported(hwc2_composition_t composition)
-    {
-        return mCompositionSupport.at(composition);
-    }
-
-protected:
-    /* If a derived class has dependents, override this function */
-    virtual void updateDependents() { }
-
-    const std::vector<T>& mList;
-    size_t mListIdx = 0;
-
-    const std::array<bool, 6>& mCompositionSupport;
-};
-
-class Hwc2TestBuffer;
-class Hwc2TestSourceCrop;
-class Hwc2TestSurfaceDamage;
-
-class Hwc2TestBufferArea : public Hwc2TestProperty<Area> {
-public:
-    Hwc2TestBufferArea(Hwc2TestCoverage coverage, const Area& displayArea);
-
-    std::string dump() const override;
-
-    void setDependent(Hwc2TestBuffer* buffer);
-    void setDependent(Hwc2TestSourceCrop* sourceCrop);
-    void setDependent(Hwc2TestSurfaceDamage* surfaceDamage);
-
-protected:
-    void update();
-    void updateDependents() override;
-
-    const std::vector<float>& mScalars;
-    static const std::vector<float> mDefaultScalars;
-    static const std::vector<float> mBasicScalars;
-    static const std::vector<float> mCompleteScalars;
-
-    Area mDisplayArea;
-
-    Hwc2TestBuffer* mBuffer = nullptr;
-    Hwc2TestSourceCrop* mSourceCrop = nullptr;
-    Hwc2TestSurfaceDamage* mSurfaceDamage = nullptr;
-
-    std::vector<Area> mBufferAreas;
-
-    static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestColor;
-
-class Hwc2TestBlendMode : public Hwc2TestProperty<hwc2_blend_mode_t> {
-public:
-    explicit Hwc2TestBlendMode(Hwc2TestCoverage coverage);
-
-    std::string dump() const override;
-
-    void setDependent(Hwc2TestColor* color);
-
-protected:
-    void updateDependents() override;
-
-    Hwc2TestColor* mColor = nullptr;
-
-    static const std::vector<hwc2_blend_mode_t> mDefaultBlendModes;
-    static const std::vector<hwc2_blend_mode_t> mBasicBlendModes;
-    static const std::vector<hwc2_blend_mode_t> mCompleteBlendModes;
-
-    static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestColor : public Hwc2TestProperty<hwc_color_t> {
-public:
-    explicit Hwc2TestColor(Hwc2TestCoverage coverage,
-                           hwc2_blend_mode_t blendMode = HWC2_BLEND_MODE_NONE);
-
-    std::string dump() const override;
-
-    void updateBlendMode(hwc2_blend_mode_t blendMode);
-
-protected:
-    void update();
-
-    std::vector<hwc_color_t> mBaseColors;
-    static const std::vector<hwc_color_t> mDefaultBaseColors;
-    static const std::vector<hwc_color_t> mBasicBaseColors;
-    static const std::vector<hwc_color_t> mCompleteBaseColors;
-
-    hwc2_blend_mode_t mBlendMode;
-
-    std::vector<hwc_color_t> mColors;
-
-    static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestComposition : public Hwc2TestProperty<hwc2_composition_t> {
-public:
-    explicit Hwc2TestComposition(Hwc2TestCoverage coverage);
-
-    std::string dump() const override;
-
-protected:
-    static const std::vector<hwc2_composition_t> mDefaultCompositions;
-    static const std::vector<hwc2_composition_t> mBasicCompositions;
-    static const std::vector<hwc2_composition_t> mCompleteCompositions;
-
-    static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestDataspace : public Hwc2TestProperty<android::ui::Dataspace> {
-public:
-    explicit Hwc2TestDataspace(Hwc2TestCoverage coverage);
-
-    std::string dump() const override;
-
-protected:
-    static const std::vector<android::ui::Dataspace> defaultDataspaces;
-    static const std::vector<android::ui::Dataspace> basicDataspaces;
-    static const std::vector<android::ui::Dataspace> completeDataspaces;
-
-    static const std::array<bool, 6> mCompositionSupport;
-};
-
-class Hwc2TestVirtualBuffer;
-
-class Hwc2TestDisplayDimension : public Hwc2TestProperty<UnsignedArea> {
-public:
-    explicit Hwc2TestDisplayDimension(Hwc2TestCoverage coverage);
-
-    std::string dump() const;
-
-    void setDependent(Hwc2TestVirtualBuffer* buffer);
-
-private:
-    void updateDependents();
-
-    std::set<Hwc2TestVirtualBuffer*> mBuffers;
-
-    static const std::vector<UnsignedArea> mDefaultDisplayDimensions;
-    static const std::vector<UnsignedArea> mBasicDisplayDimensions;
-    static const std::vector<UnsignedArea> mCompleteDisplayDimensions;
-
-    static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestDisplayFrame : public Hwc2TestProperty<hwc_rect_t> {
-public:
-    Hwc2TestDisplayFrame(Hwc2TestCoverage coverage, const Area& displayArea);
-
-    std::string dump() const override;
-
-protected:
-    void update();
-
-    const std::vector<hwc_frect_t>& mFrectScalars;
-    const static std::vector<hwc_frect_t> mDefaultFrectScalars;
-    const static std::vector<hwc_frect_t> mBasicFrectScalars;
-    const static std::vector<hwc_frect_t> mCompleteFrectScalars;
-
-    Area mDisplayArea;
-
-    std::vector<hwc_rect_t> mDisplayFrames;
-
-    static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestPlaneAlpha : public Hwc2TestProperty<float> {
-public:
-    explicit Hwc2TestPlaneAlpha(Hwc2TestCoverage coverage);
-
-    std::string dump() const override;
-
-protected:
-    static const std::vector<float> mDefaultPlaneAlphas;
-    static const std::vector<float> mBasicPlaneAlphas;
-    static const std::vector<float> mCompletePlaneAlphas;
-
-    static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestSourceCrop : public Hwc2TestProperty<hwc_frect_t> {
-public:
-    explicit Hwc2TestSourceCrop(Hwc2TestCoverage coverage, const Area& bufferArea = {0, 0});
-
-    std::string dump() const override;
-
-    void updateBufferArea(const Area& bufferArea);
-
-protected:
-    void update();
-
-    const std::vector<hwc_frect_t>& mFrectScalars;
-    const static std::vector<hwc_frect_t> mDefaultFrectScalars;
-    const static std::vector<hwc_frect_t> mBasicFrectScalars;
-    const static std::vector<hwc_frect_t> mCompleteFrectScalars;
-
-    Area mBufferArea;
-
-    std::vector<hwc_frect_t> mSourceCrops;
-
-    static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestSurfaceDamage : public Hwc2TestProperty<hwc_region_t> {
-public:
-    explicit Hwc2TestSurfaceDamage(Hwc2TestCoverage coverage);
-    ~Hwc2TestSurfaceDamage();
-
-    std::string dump() const override;
-
-    void updateBufferArea(const Area& bufferArea);
-
-protected:
-    void update();
-    void freeSurfaceDamages();
-
-    const std::vector<std::vector<hwc_frect_t>> &mRegionScalars;
-    const static std::vector<std::vector<hwc_frect_t>> mDefaultRegionScalars;
-    const static std::vector<std::vector<hwc_frect_t>> mBasicRegionScalars;
-    const static std::vector<std::vector<hwc_frect_t>> mCompleteRegionScalars;
-
-    Area mBufferArea = {0, 0};
-
-    std::vector<hwc_region_t> mSurfaceDamages;
-
-    static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestTransform : public Hwc2TestProperty<hwc_transform_t> {
-public:
-    explicit Hwc2TestTransform(Hwc2TestCoverage coverage);
-
-    std::string dump() const override;
-
-protected:
-    static const std::vector<hwc_transform_t> mDefaultTransforms;
-    static const std::vector<hwc_transform_t> mBasicTransforms;
-    static const std::vector<hwc_transform_t> mCompleteTransforms;
-
-    static const std::array<bool, 6> mCompositionSupport;
-};
-
-
-class Hwc2TestVisibleRegion {
-public:
-    ~Hwc2TestVisibleRegion();
-
-    std::string dump() const;
-
-    void set(const android::Region& visibleRegion);
-    hwc_region_t get() const;
-    void release();
-
-protected:
-    hwc_region_t mVisibleRegion = {0, nullptr};
-};
-
-#endif /* ifndef _HWC2_TEST_PROPERTIES_H */
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
deleted file mode 100644
index e6cceb8..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.cpp
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2016 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 <sstream>
-#include <sys/stat.h>
-
-#include "Hwc2TestVirtualDisplay.h"
-
-#define DIR_NAME "images"
-
-Hwc2TestVirtualDisplay::Hwc2TestVirtualDisplay(
-        Hwc2TestCoverage coverage)
-    : mDisplayDimension(coverage)
-{
-    mDisplayDimension.setDependent(&mOutputBuffer);
-    mDisplayDimension.setDependent(&mExpectedBuffer);
-}
-
-std::string Hwc2TestVirtualDisplay::dump() const
-{
-    std::stringstream dmp;
-
-    dmp << "virtual display: \n";
-
-    mDisplayDimension.dump();
-
-    return dmp.str();
-}
-
-int Hwc2TestVirtualDisplay::getOutputBuffer(buffer_handle_t* outHandle,
-        android::base::unique_fd* outAcquireFence)
-{
-    int32_t acquireFence;
-    int ret = mOutputBuffer.getOutputBuffer(outHandle, &acquireFence);
-    outAcquireFence->reset(acquireFence);
-    return ret;
-}
-
-void Hwc2TestVirtualDisplay::reset()
-{
-    return mDisplayDimension.reset();
-}
-
-bool Hwc2TestVirtualDisplay::advance()
-{
-    return mDisplayDimension.advance();
-}
-
-UnsignedArea Hwc2TestVirtualDisplay::getDisplayDimension() const
-{
-    return mDisplayDimension.get();
-}
-
-int Hwc2TestVirtualDisplay::verifyOutputBuffer(const Hwc2TestLayers* testLayers,
-        const std::vector<hwc2_layer_t>* allLayers,
-        const std::set<hwc2_layer_t>* clearLayers)
-{
-    int ret = mExpectedBuffer.generateExpectedBuffer(testLayers, allLayers,
-            clearLayers);
-    if (ret)
-        return ret;
-
-    ComparatorResult::get().CompareBuffers(mOutputBuffer.graphicBuffer(),
-        mExpectedBuffer.graphicBuffer());
-
-    return 0;
-}
-
-int Hwc2TestVirtualDisplay::writeBuffersToFile(std::string name)
-{
-    std::ostringstream expectedPath;
-    std::ostringstream resultPath;
-    int ret = mkdir(DIR_NAME, DEFFILEMODE);
-    if (ret && errno != EEXIST)
-        return ret;
-
-    expectedPath << DIR_NAME << "/expected-" << name << ".png";
-    resultPath << DIR_NAME << "/result-" << name << ".png";
-
-    if (!mExpectedBuffer.writeBufferToFile(expectedPath.str()) ||
-            !mOutputBuffer.writeBufferToFile(resultPath.str()))
-        return -1;
-
-    return 0;
-}
diff --git a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h b/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
deleted file mode 100644
index 5a74a6c..0000000
--- a/services/surfaceflinger/tests/hwc2/Hwc2TestVirtualDisplay.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef _HWC2_TEST_VIRTUAL_DISPLAY_H
-#define _HWC2_TEST_VIRTUAL_DISPLAY_H
-
-#include "Hwc2TestBuffer.h"
-#include "Hwc2TestPixelComparator.h"
-#include "Hwc2TestProperties.h"
-
-#define HWC2_INCLUDE_STRINGIFICATION
-#define HWC2_USE_CPP11
-#include <hardware/hwcomposer2.h>
-#undef HWC2_INCLUDE_STRINGIFICATION
-#undef HWC2_USE_CPP11
-
-class Hwc2TestVirtualDisplay {
-public:
-    explicit Hwc2TestVirtualDisplay(Hwc2TestCoverage coverage);
-
-    std::string dump() const;
-
-    int getOutputBuffer(buffer_handle_t* outHandle,
-            android::base::unique_fd* outAcquireFence);
-
-    int verifyOutputBuffer(const Hwc2TestLayers* testLayers,
-            const std::vector<hwc2_layer_t>* allLayers,
-            const std::set<hwc2_layer_t>* clearLayers);
-
-    int writeBuffersToFile(std::string name);
-    void reset();
-    bool advance();
-
-    UnsignedArea getDisplayDimension() const;
-
-private:
-    Hwc2TestOutputBuffer mOutputBuffer;
-    Hwc2TestExpectedBuffer mExpectedBuffer;
-    Hwc2TestDisplayDimension mDisplayDimension;
-};
-
-#endif /* ifndef _HWC2_TEST_VIRTUAL_DISPLAY_H */
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index f842d61..3c4a791 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -36,26 +36,38 @@
         ":libsurfaceflinger_sources",
         "libsurfaceflinger_unittest_main.cpp",
         "CachingTest.cpp",
-	"CompositionTest.cpp",
+        "CompositionTest.cpp",
         "DispSyncSourceTest.cpp",
         "DisplayIdentificationTest.cpp",
         "DisplayTransactionTest.cpp",
         "EventControlThreadTest.cpp",
         "EventThreadTest.cpp",
-        "IdleTimerTest.cpp",
+        "HWComposerTest.cpp",
+        "OneShotTimerTest.cpp",
         "LayerHistoryTest.cpp",
+        "LayerHistoryTestV2.cpp",
         "LayerMetadataTest.cpp",
+        "PhaseOffsetsTest.cpp",
+        "PromiseTest.cpp",
         "SchedulerTest.cpp",
         "SchedulerUtilsTest.cpp",
+        "SetFrameRateTest.cpp",
         "RefreshRateConfigsTest.cpp",
+        "RefreshRateSelectionTest.cpp",
         "RefreshRateStatsTest.cpp",
         "RegionSamplingTest.cpp",
         "TimeStatsTest.cpp",
+        "FrameTracerTest.cpp",
+        "TransactionApplicationTest.cpp",
+        "StrongTypingTest.cpp",
+        "VSyncDispatchTimerQueueTest.cpp",
+        "VSyncDispatchRealtimeTest.cpp",
+        "VSyncModulatorTest.cpp",
+        "VSyncPredictorTest.cpp",
+        "VSyncReactorTest.cpp",
         "mock/DisplayHardware/MockComposer.cpp",
         "mock/DisplayHardware/MockDisplay.cpp",
         "mock/DisplayHardware/MockPowerAdvisor.cpp",
-        "mock/gui/MockGraphicBufferConsumer.cpp",
-        "mock/gui/MockGraphicBufferProducer.cpp",
         "mock/MockDispSync.cpp",
         "mock/MockEventControlThread.cpp",
         "mock/MockEventThread.cpp",
@@ -63,13 +75,24 @@
         "mock/MockNativeWindowSurface.cpp",
         "mock/MockSurfaceInterceptor.cpp",
         "mock/MockTimeStats.cpp",
+        "mock/MockFrameTracer.cpp",
         "mock/system/window/MockNativeWindow.cpp",
     ],
     static_libs: [
         "libgmock",
         "libcompositionengine",
         "libcompositionengine_mocks",
+        "libgui_mocks",
+        "libperfetto_client_experimental",
         "librenderengine_mocks",
+        "perfetto_trace_protos",
+    ],
+    shared_libs: [
+        "libprotoutil",
+        "libstatssocket",
+        "libsurfaceflinger",
+        "libtimestats",
+        "libtimestats_proto",
     ],
     header_libs: [
         "libsurfaceflinger_headers",
diff --git a/services/surfaceflinger/tests/unittests/CachingTest.cpp b/services/surfaceflinger/tests/unittests/CachingTest.cpp
index 74ce540..1b8c76d 100644
--- a/services/surfaceflinger/tests/unittests/CachingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CachingTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "CachingTest"
 
@@ -91,3 +95,6 @@
     }
 }
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 349dd3f..32d722e 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "CompositionTest"
 
@@ -31,21 +35,29 @@
 #include <utils/String8.h>
 
 #include "BufferQueueLayer.h"
-#include "ColorLayer.h"
+#include "EffectLayer.h"
 #include "Layer.h"
-
-#include "TestableScheduler.h"
 #include "TestableSurfaceFlinger.h"
 #include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockPowerAdvisor.h"
 #include "mock/MockDispSync.h"
 #include "mock/MockEventControlThread.h"
 #include "mock/MockEventThread.h"
 #include "mock/MockMessageQueue.h"
+#include "mock/MockTimeStats.h"
 #include "mock/system/window/MockNativeWindow.h"
 
 namespace android {
 namespace {
 
+namespace hal = android::hardware::graphics::composer::hal;
+
+using hal::Error;
+using hal::IComposer;
+using hal::IComposerClient;
+using hal::PowerMode;
+using hal::Transform;
+
 using testing::_;
 using testing::AtLeast;
 using testing::Between;
@@ -61,16 +73,11 @@
 using testing::ReturnRef;
 using testing::SetArgPointee;
 
-using android::Hwc2::Error;
-using android::Hwc2::IComposer;
-using android::Hwc2::IComposerClient;
-using android::Hwc2::Transform;
-
 using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
 using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
 
-constexpr hwc2_display_t HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
-constexpr hwc2_layer_t HWC_LAYER = 5000;
+constexpr hal::HWDisplayId HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
+constexpr hal::HWLayerId HWC_LAYER = 5000;
 constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0);
 
 constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
@@ -95,16 +102,13 @@
         mFlinger.mutableEventQueue().reset(mMessageQueue);
         setupScheduler();
 
-        EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
-        EXPECT_CALL(*mPrimaryDispSync, getPeriod())
-                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
-        EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
         EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
                 .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
         EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
                 .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
 
         mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
+        mFlinger.setupTimeStats(std::shared_ptr<TimeStats>(mTimeStats));
         setupComposer(0);
     }
 
@@ -116,8 +120,6 @@
 
     void setupComposer(int virtualDisplayCount) {
         mComposer = new Hwc2::mock::Composer();
-        EXPECT_CALL(*mComposer, getCapabilities())
-                .WillOnce(Return(std::vector<IComposer::Capability>()));
         EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
         mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
 
@@ -125,25 +127,31 @@
     }
 
     void setupScheduler() {
-        std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}};
-        mFlinger.mutableRefreshRateConfigs() =
-                std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false,
-                                                                configs,
-                                                                /*currentConfig=*/0);
-        mFlinger.mutableRefreshRateStats() =
-                std::make_unique<scheduler::RefreshRateStats>(*mFlinger.mutableRefreshRateConfigs(),
-                                                              *mFlinger.mutableTimeStats(),
-                                                              /*currentConfig=*/0,
-                                                              /*powerMode=*/HWC_POWER_MODE_OFF);
-        mScheduler = new TestableScheduler(*mFlinger.mutableRefreshRateConfigs());
-        mScheduler->mutableEventControlThread().reset(mEventControlThread);
-        mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
-        EXPECT_CALL(*mEventThread.get(), registerDisplayEventConnection(_));
-        sp<Scheduler::ConnectionHandle> connectionHandle =
-                mScheduler->addConnection(std::move(mEventThread));
-        mFlinger.mutableSfConnectionHandle() = std::move(connectionHandle);
+        auto eventThread = std::make_unique<mock::EventThread>();
+        auto sfEventThread = std::make_unique<mock::EventThread>();
 
-        mFlinger.mutableScheduler().reset(mScheduler);
+        EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*eventThread, createEventConnection(_, _))
+                .WillOnce(Return(
+                        new EventThreadConnection(eventThread.get(), ResyncCallback(),
+                                                  ISurfaceComposer::eConfigChangedSuppress)));
+
+        EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+                .WillOnce(Return(
+                        new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
+                                                  ISurfaceComposer::eConfigChangedSuppress)));
+
+        auto primaryDispSync = std::make_unique<mock::DispSync>();
+
+        EXPECT_CALL(*primaryDispSync, computeNextRefresh(0, _)).WillRepeatedly(Return(0));
+        EXPECT_CALL(*primaryDispSync, getPeriod())
+                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+        EXPECT_CALL(*primaryDispSync, expectedPresentTime(_)).WillRepeatedly(Return(0));
+
+        mFlinger.setupScheduler(std::move(primaryDispSync),
+                                std::make_unique<mock::EventControlThread>(),
+                                std::move(eventThread), std::move(sfEventThread));
     }
 
     void setupForceGeometryDirty() {
@@ -165,9 +173,9 @@
     template <typename Case>
     void captureScreenComposition();
 
-    std::unordered_set<HWC2::Capability> mDefaultCapabilities = {HWC2::Capability::SidebandStream};
+    std::unordered_set<hal::Capability> mDefaultCapabilities = {hal::Capability::SIDEBAND_STREAM};
 
-    TestableScheduler* mScheduler;
+    bool mDisplayOff = false;
     TestableSurfaceFlinger mFlinger;
     sp<DisplayDevice> mDisplay;
     sp<DisplayDevice> mExternalDisplay;
@@ -178,13 +186,11 @@
     sp<GraphicBuffer> mBuffer = new GraphicBuffer();
     ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer();
 
-    std::unique_ptr<mock::EventThread> mEventThread = std::make_unique<mock::EventThread>();
-    mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
-
     Hwc2::mock::Composer* mComposer = nullptr;
     renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
+    mock::TimeStats* mTimeStats = new mock::TimeStats();
     mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
-    mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+    Hwc2::mock::PowerAdvisor mPowerAdvisor;
 
     sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
 
@@ -225,6 +231,7 @@
     const Rect sourceCrop(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
     constexpr bool useIdentityTransform = true;
     constexpr bool forSystem = true;
+    constexpr bool regionSampling = false;
 
     DisplayRenderArea renderArea(mDisplay, sourceCrop, DEFAULT_DISPLAY_WIDTH,
                                  DEFAULT_DISPLAY_HEIGHT, ui::Dataspace::V0_SRGB,
@@ -243,7 +250,7 @@
     int fd = -1;
     status_t result =
             mFlinger.captureScreenImplLocked(renderArea, traverseLayers, mCaptureScreenBuffer.get(),
-                                             useIdentityTransform, forSystem, &fd);
+                                             useIdentityTransform, forSystem, &fd, regionSampling);
     if (fd >= 0) {
         close(fd);
     }
@@ -260,17 +267,13 @@
 template <typename Derived>
 struct BaseDisplayVariant {
     static constexpr bool IS_SECURE = true;
-    static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
+    static constexpr hal::PowerMode INIT_POWER_MODE = hal::PowerMode::ON;
 
     static void setupPreconditions(CompositionTest* test) {
-        EXPECT_CALL(*test->mComposer,
-                    setPowerMode(HWC_DISPLAY,
-                                 static_cast<Hwc2::IComposerClient::PowerMode>(
-                                         Derived::INIT_POWER_MODE)))
+        EXPECT_CALL(*test->mComposer, setPowerMode(HWC_DISPLAY, Derived::INIT_POWER_MODE))
                 .WillOnce(Return(Error::NONE));
 
-        FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, HWC2::DisplayType::Physical,
-                               true /* isPrimary */)
+        FakeHwcDisplayInjector(DEFAULT_DISPLAY_ID, hal::DisplayType::PHYSICAL, true /* isPrimary */)
                 .setCapabilities(&test->mDefaultCapabilities)
                 .setPowerMode(Derived::INIT_POWER_MODE)
                 .inject(&test->mFlinger, test->mComposer);
@@ -283,8 +286,28 @@
         EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
         EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
         EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
-        test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DEFAULT_DISPLAY_ID,
-                                                   false /* isVirtual */, true /* isPrimary */)
+
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+
+        auto ceDisplayArgs =
+                compositionengine::DisplayCreationArgsBuilder()
+                        .setPhysical({DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal})
+                        .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
+                        .setIsSecure(Derived::IS_SECURE)
+                        .setLayerStackId(DEFAULT_LAYER_STACK)
+                        .setPowerAdvisor(&test->mPowerAdvisor)
+                        .setName(std::string("Injected display for ") +
+                                 test_info->test_case_name() + "." + test_info->name())
+                        .build();
+
+        auto compositionDisplay =
+                compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+                                                       ceDisplayArgs);
+
+        test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay,
+                                                   DisplayConnectionType::Internal, HWC_DISPLAY,
+                                                   true /* isPrimary */)
                                  .setDisplaySurface(test->mDisplaySurface)
                                  .setNativeWindow(test->mNativeWindow)
                                  .setSecure(Derived::IS_SECURE)
@@ -306,18 +329,12 @@
         EXPECT_CALL(*test->mComposer,
                     setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
                 .Times(1);
-        EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
         EXPECT_CALL(*test->mComposer, getDisplayRequests(HWC_DISPLAY, _, _, _)).Times(1);
         EXPECT_CALL(*test->mComposer, acceptDisplayChanges(HWC_DISPLAY)).Times(1);
         EXPECT_CALL(*test->mComposer, presentDisplay(HWC_DISPLAY, _)).Times(1);
         EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1);
 
         EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
-        // TODO: remove once we verify that we can just grab the fence from the
-        // FramebufferSurface.
-        EXPECT_CALL(*test->mRenderEngine, flush()).WillRepeatedly(Invoke([]() {
-            return base::unique_fd();
-        }));
 
         EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
         EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1);
@@ -329,17 +346,17 @@
     template <typename Case>
     static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
-                .WillRepeatedly(
-                        [](const renderengine::DisplaySettings& displaySettings,
-                           const std::vector<renderengine::LayerSettings>&, ANativeWindowBuffer*,
-                           const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
-                            EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
-                            EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
-                                      displaySettings.physicalDisplay);
-                            EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
-                                      displaySettings.clip);
-                            return NO_ERROR;
-                        });
+                .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings,
+                                   const std::vector<const renderengine::LayerSettings*>&,
+                                   ANativeWindowBuffer*, const bool, base::unique_fd&&,
+                                   base::unique_fd*) -> status_t {
+                    EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
+                    EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                              displaySettings.physicalDisplay);
+                    EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                              displaySettings.clip);
+                    return NO_ERROR;
+                });
     }
 
     static void setupNonEmptyFrameCompositionCallExpectations(CompositionTest* test) {
@@ -351,14 +368,24 @@
     }
 
     static void setupHwcCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+
         EXPECT_CALL(*test->mDisplaySurface,
                     prepareFrame(compositionengine::DisplaySurface::COMPOSITION_HWC))
                 .Times(1);
     }
 
+    static void setupHwcClientCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+    }
+
+    static void setupHwcForcedClientCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, validateDisplay(HWC_DISPLAY, _, _)).Times(1);
+    }
+
     static void setupRECompositionCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mDisplaySurface,
-                    prepareFrame(compositionengine::DisplaySurface::COMPOSITION_GLES))
+                    prepareFrame(compositionengine::DisplaySurface::COMPOSITION_GPU))
                 .Times(1);
         EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
                 .WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
@@ -368,18 +395,18 @@
                 .WillOnce(DoAll(SetArgPointee<0>(test->mNativeWindowBuffer), SetArgPointee<1>(-1),
                                 Return(0)));
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
-                .WillRepeatedly(
-                        [](const renderengine::DisplaySettings& displaySettings,
-                           const std::vector<renderengine::LayerSettings>&, ANativeWindowBuffer*,
-                           const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
-                            EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
-                            EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
-                                      displaySettings.physicalDisplay);
-                            EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
-                                      displaySettings.clip);
-                            EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace);
-                            return NO_ERROR;
-                        });
+                .WillRepeatedly([](const renderengine::DisplaySettings& displaySettings,
+                                   const std::vector<const renderengine::LayerSettings*>&,
+                                   ANativeWindowBuffer*, const bool, base::unique_fd&&,
+                                   base::unique_fd*) -> status_t {
+                    EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
+                    EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                              displaySettings.physicalDisplay);
+                    EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                              displaySettings.clip);
+                    EXPECT_EQ(ui::Dataspace::UNKNOWN, displaySettings.outputDataspace);
+                    return NO_ERROR;
+                });
     }
 
     template <typename Case>
@@ -410,7 +437,7 @@
 };
 
 struct PoweredOffDisplaySetupVariant : public BaseDisplayVariant<PoweredOffDisplaySetupVariant> {
-    static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_OFF;
+    static constexpr hal::PowerMode INIT_POWER_MODE = hal::PowerMode::OFF;
 
     template <typename Case>
     static void setupPreconditionCallExpectations(CompositionTest*) {}
@@ -429,6 +456,8 @@
     }
 
     static void setupHwcCompositionCallExpectations(CompositionTest*) {}
+    static void setupHwcClientCompositionCallExpectations(CompositionTest*) {}
+    static void setupHwcForcedClientCompositionCallExpectations(CompositionTest*) {}
 
     static void setupRECompositionCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
@@ -513,11 +542,11 @@
 
         EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
         enqueueBuffer(test, layer);
-        Mock::VerifyAndClear(test->mMessageQueue);
+        Mock::VerifyAndClearExpectations(test->mMessageQueue);
 
         EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
         bool ignoredRecomputeVisibleRegions;
-        layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
+        layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, 0);
         Mock::VerifyAndClear(test->mRenderEngine);
     }
 
@@ -532,69 +561,85 @@
     }
 
     static void setupHwcSetGeometryCallExpectations(CompositionTest* test) {
-        // TODO: Coverage of other values
-        EXPECT_CALL(*test->mComposer,
-                    setLayerBlendMode(HWC_DISPLAY, HWC_LAYER, LayerProperties::BLENDMODE))
-                .Times(1);
-        // TODO: Coverage of other values for origin
-        EXPECT_CALL(*test->mComposer,
-                    setLayerDisplayFrame(HWC_DISPLAY, HWC_LAYER,
-                                         IComposerClient::Rect({0, 0, LayerProperties::WIDTH,
-                                                                LayerProperties::HEIGHT})))
-                .Times(1);
-        EXPECT_CALL(*test->mComposer,
-                    setLayerPlaneAlpha(HWC_DISPLAY, HWC_LAYER, LayerProperties::COLOR[3]))
-                .Times(1);
-        // TODO: Coverage of other values
-        EXPECT_CALL(*test->mComposer, setLayerZOrder(HWC_DISPLAY, HWC_LAYER, 0u)).Times(1);
-        // TODO: Coverage of other values
-        EXPECT_CALL(*test->mComposer, setLayerInfo(HWC_DISPLAY, HWC_LAYER, 0u, 0u)).Times(1);
+        if (!test->mDisplayOff) {
+            // TODO: Coverage of other values
+            EXPECT_CALL(*test->mComposer,
+                        setLayerBlendMode(HWC_DISPLAY, HWC_LAYER, LayerProperties::BLENDMODE))
+                    .Times(1);
+            // TODO: Coverage of other values for origin
+            EXPECT_CALL(*test->mComposer,
+                        setLayerDisplayFrame(HWC_DISPLAY, HWC_LAYER,
+                                             IComposerClient::Rect({0, 0, LayerProperties::WIDTH,
+                                                                    LayerProperties::HEIGHT})))
+                    .Times(1);
+            EXPECT_CALL(*test->mComposer,
+                        setLayerPlaneAlpha(HWC_DISPLAY, HWC_LAYER, LayerProperties::COLOR[3]))
+                    .Times(1);
+            // TODO: Coverage of other values
+            EXPECT_CALL(*test->mComposer, setLayerZOrder(HWC_DISPLAY, HWC_LAYER, 0u)).Times(1);
+            // TODO: Coverage of other values
+            EXPECT_CALL(*test->mComposer, setLayerInfo(HWC_DISPLAY, HWC_LAYER, 0u, 0u)).Times(1);
 
-        // These expectations retire on saturation as the code path these
-        // expectations are for appears to make an extra call to them.
-        // TODO: Investigate this extra call
-        EXPECT_CALL(*test->mComposer, setLayerTransform(HWC_DISPLAY, HWC_LAYER, DEFAULT_TRANSFORM))
-                .Times(AtLeast(1))
-                .RetiresOnSaturation();
+            // These expectations retire on saturation as the code path these
+            // expectations are for appears to make an extra call to them.
+            // TODO: Investigate this extra call
+            EXPECT_CALL(*test->mComposer,
+                        setLayerTransform(HWC_DISPLAY, HWC_LAYER, DEFAULT_TRANSFORM))
+                    .Times(AtLeast(1))
+                    .RetiresOnSaturation();
+        }
     }
 
     static void setupHwcSetSourceCropBufferCallExpectations(CompositionTest* test) {
-        EXPECT_CALL(*test->mComposer,
-                    setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
-                                       IComposerClient::FRect({0.f, 0.f, LayerProperties::WIDTH,
-                                                               LayerProperties::HEIGHT})))
-                .Times(1);
+        if (!test->mDisplayOff) {
+            EXPECT_CALL(*test->mComposer,
+                        setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+                                           IComposerClient::FRect({0.f, 0.f, LayerProperties::WIDTH,
+                                                                   LayerProperties::HEIGHT})))
+                    .Times(1);
+        }
     }
 
     static void setupHwcSetSourceCropColorCallExpectations(CompositionTest* test) {
-        EXPECT_CALL(*test->mComposer,
-                    setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
-                                       IComposerClient::FRect({0.f, 0.f, 0.f, 0.f})))
-                .Times(1);
+        if (!test->mDisplayOff) {
+            EXPECT_CALL(*test->mComposer,
+                        setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+                                           IComposerClient::FRect({0.f, 0.f, 0.f, 0.f})))
+                    .Times(1);
+        }
     }
 
     static void setupHwcSetPerFrameCallExpectations(CompositionTest* test) {
-        EXPECT_CALL(*test->mComposer,
-                    setLayerVisibleRegion(HWC_DISPLAY, HWC_LAYER,
-                                          std::vector<IComposerClient::Rect>({IComposerClient::Rect(
-                                                  {0, 0, LayerProperties::WIDTH,
-                                                   LayerProperties::HEIGHT})})))
-                .Times(1);
+        if (!test->mDisplayOff) {
+            EXPECT_CALL(*test->mComposer,
+                        setLayerVisibleRegion(HWC_DISPLAY, HWC_LAYER,
+                                              std::vector<IComposerClient::Rect>(
+                                                      {IComposerClient::Rect(
+                                                              {0, 0, LayerProperties::WIDTH,
+                                                               LayerProperties::HEIGHT})})))
+                    .Times(1);
+        }
     }
 
     static void setupHwcSetPerFrameColorCallExpectations(CompositionTest* test) {
-        EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
+        if (!test->mDisplayOff) {
+            EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _))
+                    .Times(1);
 
-        // TODO: use COLOR
-        EXPECT_CALL(*test->mComposer,
-                    setLayerColor(HWC_DISPLAY, HWC_LAYER,
-                                  IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
-                .Times(1);
+            // TODO: use COLOR
+            EXPECT_CALL(*test->mComposer,
+                        setLayerColor(HWC_DISPLAY, HWC_LAYER,
+                                      IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
+                    .Times(1);
+        }
     }
 
     static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
-        EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
-        EXPECT_CALL(*test->mComposer, setLayerBuffer(HWC_DISPLAY, HWC_LAYER, _, _, _)).Times(1);
+        if (!test->mDisplayOff) {
+            EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _))
+                    .Times(1);
+            EXPECT_CALL(*test->mComposer, setLayerBuffer(HWC_DISPLAY, HWC_LAYER, _, _, _)).Times(1);
+        }
 
         setupBufferLayerPostFrameCallExpectations(test);
     }
@@ -602,7 +647,7 @@
     static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([](const renderengine::DisplaySettings& displaySettings,
-                             const std::vector<renderengine::LayerSettings>& layerSettings,
+                             const std::vector<const renderengine::LayerSettings*>& layerSettings,
                              ANativeWindowBuffer*, const bool, base::unique_fd&&,
                              base::unique_fd*) -> status_t {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
@@ -612,16 +657,22 @@
                               displaySettings.clip);
                     // screen capture adds an additional color layer as an alpha
                     // prefill, so gtet the back layer.
-                    renderengine::LayerSettings layer = layerSettings.back();
-                    EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull()));
-                    EXPECT_THAT(layer.source.buffer.fence, Not(IsNull()));
-                    EXPECT_EQ(DEFAULT_TEXTURE_ID, layer.source.buffer.textureName);
-                    EXPECT_EQ(false, layer.source.buffer.isY410BT2020);
-                    EXPECT_EQ(true, layer.source.buffer.usePremultipliedAlpha);
-                    EXPECT_EQ(false, layer.source.buffer.isOpaque);
-                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
-                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
-                    EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
+                    if (layerSettings.empty()) {
+                        ADD_FAILURE() << "layerSettings was not expected to be empty in "
+                                         "setupREBufferCompositionCommonCallExpectations "
+                                         "verification lambda";
+                        return NO_ERROR;
+                    }
+                    const renderengine::LayerSettings* layer = layerSettings.back();
+                    EXPECT_THAT(layer->source.buffer.buffer, Not(IsNull()));
+                    EXPECT_THAT(layer->source.buffer.fence, Not(IsNull()));
+                    EXPECT_EQ(DEFAULT_TEXTURE_ID, layer->source.buffer.textureName);
+                    EXPECT_EQ(false, layer->source.buffer.isY410BT2020);
+                    EXPECT_EQ(true, layer->source.buffer.usePremultipliedAlpha);
+                    EXPECT_EQ(false, layer->source.buffer.isOpaque);
+                    EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
+                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
+                    EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
                     return NO_ERROR;
                 });
     }
@@ -645,7 +696,7 @@
     static void setupREColorCompositionCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([](const renderengine::DisplaySettings& displaySettings,
-                             const std::vector<renderengine::LayerSettings>& layerSettings,
+                             const std::vector<const renderengine::LayerSettings*>& layerSettings,
                              ANativeWindowBuffer*, const bool, base::unique_fd&&,
                              base::unique_fd*) -> status_t {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
@@ -655,14 +706,20 @@
                               displaySettings.clip);
                     // screen capture adds an additional color layer as an alpha
                     // prefill, so get the back layer.
-                    renderengine::LayerSettings layer = layerSettings.back();
-                    EXPECT_THAT(layer.source.buffer.buffer, IsNull());
+                    if (layerSettings.empty()) {
+                        ADD_FAILURE()
+                                << "layerSettings was not expected to be empty in "
+                                   "setupREColorCompositionCallExpectations verification lambda";
+                        return NO_ERROR;
+                    }
+                    const renderengine::LayerSettings* layer = layerSettings.back();
+                    EXPECT_THAT(layer->source.buffer.buffer, IsNull());
                     EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
                                     LayerProperties::COLOR[2]),
-                              layer.source.solidColor);
-                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
-                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
-                    EXPECT_EQ(LayerProperties::COLOR[3], layer.alpha);
+                              layer->source.solidColor);
+                    EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
+                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
+                    EXPECT_EQ(LayerProperties::COLOR[3], layer->alpha);
                     return NO_ERROR;
                 });
     }
@@ -674,7 +731,9 @@
 
 struct DefaultLayerProperties : public BaseLayerProperties<DefaultLayerProperties> {};
 
-struct ColorLayerProperties : public BaseLayerProperties<ColorLayerProperties> {};
+struct EffectLayerProperties : public BaseLayerProperties<EffectLayerProperties> {
+    static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE;
+};
 
 struct SidebandLayerProperties : public BaseLayerProperties<SidebandLayerProperties> {
     using Base = BaseLayerProperties<SidebandLayerProperties>;
@@ -715,7 +774,7 @@
     static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
         EXPECT_CALL(*test->mRenderEngine, drawLayers)
                 .WillOnce([](const renderengine::DisplaySettings& displaySettings,
-                             const std::vector<renderengine::LayerSettings>& layerSettings,
+                             const std::vector<const renderengine::LayerSettings*>& layerSettings,
                              ANativeWindowBuffer*, const bool, base::unique_fd&&,
                              base::unique_fd*) -> status_t {
                     EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
@@ -725,12 +784,18 @@
                               displaySettings.clip);
                     // screen capture adds an additional color layer as an alpha
                     // prefill, so get the back layer.
-                    renderengine::LayerSettings layer = layerSettings.back();
-                    EXPECT_THAT(layer.source.buffer.buffer, IsNull());
-                    EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor);
-                    EXPECT_EQ(0.0, layer.geometry.roundedCornersRadius);
-                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer.sourceDataspace);
-                    EXPECT_EQ(1.0f, layer.alpha);
+                    if (layerSettings.empty()) {
+                        ADD_FAILURE() << "layerSettings was not expected to be empty in "
+                                         "setupInsecureREBufferCompositionCommonCallExpectations "
+                                         "verification lambda";
+                        return NO_ERROR;
+                    }
+                    const renderengine::LayerSettings* layer = layerSettings.back();
+                    EXPECT_THAT(layer->source.buffer.buffer, IsNull());
+                    EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer->source.solidColor);
+                    EXPECT_EQ(0.0, layer->geometry.roundedCornersRadius);
+                    EXPECT_EQ(ui::Dataspace::UNKNOWN, layer->sourceDataspace);
+                    EXPECT_EQ(1.0f, layer->alpha);
                     return NO_ERROR;
                 });
     }
@@ -769,13 +834,16 @@
 struct BaseLayerVariant {
     template <typename L, typename F>
     static sp<L> createLayerWithFactory(CompositionTest* test, F factory) {
-        EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(0);
+        EXPECT_CALL(*test->mMessageQueue, postMessage(_)).Times(0);
 
         sp<L> layer = factory();
 
+        // Layer should be registered with scheduler.
+        EXPECT_EQ(1, test->mFlinger.scheduler()->layerHistorySize());
+
         Mock::VerifyAndClear(test->mComposer);
         Mock::VerifyAndClear(test->mRenderEngine);
-        Mock::VerifyAndClear(test->mMessageQueue);
+        Mock::VerifyAndClearExpectations(test->mMessageQueue);
 
         auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
         layerDrawingState.layerStack = DEFAULT_LAYER_STACK;
@@ -783,8 +851,7 @@
         layerDrawingState.active.h = 100;
         layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
                                         LayerProperties::COLOR[2], LayerProperties::COLOR[3]);
-        layer->computeBounds(FloatRect(0, 0, 100, 100), ui::Transform());
-        layer->setVisibleRegion(Region(Rect(0, 0, 100, 100)));
+        layer->computeBounds(FloatRect(0, 0, 100, 100), ui::Transform(), 0.f /* shadowRadius */);
 
         return layer;
     }
@@ -793,19 +860,13 @@
         EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
                 .WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
 
-        std::vector<std::unique_ptr<compositionengine::OutputLayer>> outputLayers;
-        outputLayers.emplace_back(test->mDisplay->getCompositionDisplay()
-                                          ->getOrCreateOutputLayer(DEFAULT_DISPLAY_ID,
-                                                                   layer->getCompositionLayer(),
-                                                                   layer));
-
-        test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(std::move(outputLayers));
+        auto outputLayer = test->mDisplay->getCompositionDisplay()->injectOutputLayerForTest(
+                layer->getCompositionEngineLayerFE());
+        outputLayer->editState().visibleRegion = Region(Rect(0, 0, 100, 100));
+        outputLayer->editState().outputSpaceVisibleRegion = Region(Rect(0, 0, 100, 100));
 
         Mock::VerifyAndClear(test->mComposer);
 
-        Vector<sp<Layer>> layers;
-        layers.add(layer);
-        test->mDisplay->setVisibleLayersSortedByZ(layers);
         test->mFlinger.mutableDrawingState().layersSortedByZ.add(layer);
     }
 
@@ -813,23 +874,26 @@
         EXPECT_CALL(*test->mComposer, destroyLayer(HWC_DISPLAY, HWC_LAYER))
                 .WillOnce(Return(Error::NONE));
 
-        test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(
-                std::vector<std::unique_ptr<compositionengine::OutputLayer>>());
+        test->mDisplay->getCompositionDisplay()->clearOutputLayers();
         test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
+
+        // Layer should be unregistered with scheduler.
+        test->mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
+        EXPECT_EQ(0, test->mFlinger.scheduler()->layerHistorySize());
     }
 };
 
 template <typename LayerProperties>
-struct ColorLayerVariant : public BaseLayerVariant<LayerProperties> {
+struct EffectLayerVariant : public BaseLayerVariant<LayerProperties> {
     using Base = BaseLayerVariant<LayerProperties>;
-    using FlingerLayerType = sp<ColorLayer>;
+    using FlingerLayerType = sp<EffectLayer>;
 
     static FlingerLayerType createLayer(CompositionTest* test) {
-        FlingerLayerType layer = Base::template createLayerWithFactory<ColorLayer>(test, [test]() {
-            return new ColorLayer(LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(),
-                                                    String8("test-layer"), LayerProperties::WIDTH,
-                                                    LayerProperties::HEIGHT,
-                                                    LayerProperties::LAYER_FLAGS, LayerMetadata()));
+        FlingerLayerType layer = Base::template createLayerWithFactory<EffectLayer>(test, [test]() {
+            return new EffectLayer(
+                    LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(), "test-layer",
+                                      LayerProperties::WIDTH, LayerProperties::HEIGHT,
+                                      LayerProperties::LAYER_FLAGS, LayerMetadata()));
         });
 
         auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
@@ -866,11 +930,12 @@
 
         FlingerLayerType layer =
                 Base::template createLayerWithFactory<BufferQueueLayer>(test, [test]() {
-                    return new BufferQueueLayer(
-                            LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(),
-                                              String8("test-layer"), LayerProperties::WIDTH,
-                                              LayerProperties::HEIGHT,
-                                              LayerProperties::LAYER_FLAGS, LayerMetadata()));
+                    sp<Client> client;
+                    LayerCreationArgs args(test->mFlinger.mFlinger.get(), client, "test-layer",
+                                           LayerProperties::WIDTH, LayerProperties::HEIGHT,
+                                           LayerProperties::LAYER_FLAGS, LayerMetadata());
+                    args.textureName = test->mFlinger.mutableTexturePool().back();
+                    return new BufferQueueLayer(args);
                 });
 
         LayerProperties::setupLayerState(test, layer);
@@ -879,7 +944,7 @@
     }
 
     static void cleanupInjectedLayers(CompositionTest* test) {
-        EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(1);
+        EXPECT_CALL(*test->mMessageQueue, postMessage(_)).Times(1);
         Base::cleanupInjectedLayers(test);
     }
 
@@ -924,12 +989,14 @@
 
 template <IComposerClient::Composition CompositionType>
 struct KeepCompositionTypeVariant {
-    static constexpr HWC2::Composition TYPE = static_cast<HWC2::Composition>(CompositionType);
+    static constexpr hal::Composition TYPE = CompositionType;
 
     static void setupHwcSetCallExpectations(CompositionTest* test) {
-        EXPECT_CALL(*test->mComposer,
-                    setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, CompositionType))
-                .Times(1);
+        if (!test->mDisplayOff) {
+            EXPECT_CALL(*test->mComposer,
+                        setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, CompositionType))
+                    .Times(1);
+        }
     }
 
     static void setupHwcGetCallExpectations(CompositionTest* test) {
@@ -940,12 +1007,14 @@
 template <IComposerClient::Composition InitialCompositionType,
           IComposerClient::Composition FinalCompositionType>
 struct ChangeCompositionTypeVariant {
-    static constexpr HWC2::Composition TYPE = static_cast<HWC2::Composition>(FinalCompositionType);
+    static constexpr hal::Composition TYPE = FinalCompositionType;
 
     static void setupHwcSetCallExpectations(CompositionTest* test) {
-        EXPECT_CALL(*test->mComposer,
-                    setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, InitialCompositionType))
-                .Times(1);
+        if (!test->mDisplayOff) {
+            EXPECT_CALL(*test->mComposer,
+                        setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, InitialCompositionType))
+                    .Times(1);
+        }
     }
 
     static void setupHwcGetCallExpectations(CompositionTest* test) {
@@ -996,14 +1065,46 @@
     template <typename Case>
     static void setupCallExpectations(CompositionTest* test) {
         Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+        Case::Display::setupHwcClientCompositionCallExpectations(test);
         Case::Display::setupRECompositionCallExpectations(test);
         Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
     }
 };
 
-struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
+struct ForcedClientCompositionResultVariant : public CompositionResultBaseVariant {
     static void setupLayerState(CompositionTest* test, sp<Layer> layer) {
-        layer->forceClientComposition(test->mDisplay);
+        const auto outputLayer =
+                TestableSurfaceFlinger::findOutputLayerForDisplay(layer, test->mDisplay);
+        LOG_FATAL_IF(!outputLayer);
+        outputLayer->editState().forceClientComposition = true;
+    }
+
+    template <typename Case>
+    static void setupCallExpectations(CompositionTest* test) {
+        Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+        Case::Display::setupHwcForcedClientCompositionCallExpectations(test);
+        Case::Display::setupRECompositionCallExpectations(test);
+        Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
+    }
+
+    template <typename Case>
+    static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {}
+
+    template <typename Case>
+    static void setupCallExpectationsForDirtyFrame(CompositionTest*) {}
+};
+
+struct ForcedClientCompositionViaDebugOptionResultVariant : public CompositionResultBaseVariant {
+    static void setupLayerState(CompositionTest* test, sp<Layer>) {
+        test->mFlinger.mutableDebugDisableHWC() = true;
+    }
+
+    template <typename Case>
+    static void setupCallExpectations(CompositionTest* test) {
+        Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+        Case::Display::setupHwcForcedClientCompositionCallExpectations(test);
+        Case::Display::setupRECompositionCallExpectations(test);
+        Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
     }
 
     template <typename Case>
@@ -1080,11 +1181,11 @@
     static void cleanup(CompositionTest* test) {
         Layer::cleanupInjectedLayers(test);
 
-        for (auto& hwcDisplay : test->mFlinger.mFakeHwcDisplays) {
-            hwcDisplay->mutableLayers().clear();
+        for (auto& displayData : test->mFlinger.mutableHwcDisplayData()) {
+            static_cast<TestableSurfaceFlinger::HWC2Display*>(displayData.second.hwcDisplay.get())
+                    ->mutableLayers()
+                    .clear();
         }
-
-        test->mDisplay->setVisibleLayersSortedByZ(Vector<sp<android::Layer>>());
     }
 };
 
@@ -1146,31 +1247,31 @@
  *  Single-color layers
  */
 
-TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyGeometry) {
+TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyGeometry) {
     displayRefreshCompositionDirtyGeometry<
-            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+            CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
                             KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
                             HwcCompositionResultVariant>>();
 }
 
-TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyFrame) {
+TEST_F(CompositionTest, HWCComposedEffectLayerWithDirtyFrame) {
     displayRefreshCompositionDirtyFrame<
-            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+            CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
                             KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
                             HwcCompositionResultVariant>>();
 }
 
-TEST_F(CompositionTest, REComposedColorLayer) {
+TEST_F(CompositionTest, REComposedEffectLayer) {
     displayRefreshCompositionDirtyFrame<
-            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+            CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
                             ChangeCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR,
                                                          IComposerClient::Composition::CLIENT>,
                             RECompositionResultVariant>>();
 }
 
-TEST_F(CompositionTest, captureScreenColorLayer) {
+TEST_F(CompositionTest, captureScreenEffectLayer) {
     captureScreenComposition<
-            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+            CompositionCase<DefaultDisplaySetupVariant, EffectLayerVariant<EffectLayerProperties>,
                             NoCompositionTypeVariant, REScreenshotResultVariant>>();
 }
 
@@ -1299,6 +1400,7 @@
  */
 
 TEST_F(CompositionTest, displayOffHWCComposedNormalBufferLayerWithDirtyGeometry) {
+    mDisplayOff = true;
     displayRefreshCompositionDirtyGeometry<CompositionCase<
             PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
             KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
@@ -1306,6 +1408,7 @@
 }
 
 TEST_F(CompositionTest, displayOffHWCComposedNormalBufferLayerWithDirtyFrame) {
+    mDisplayOff = true;
     displayRefreshCompositionDirtyFrame<CompositionCase<
             PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
             KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
@@ -1313,6 +1416,7 @@
 }
 
 TEST_F(CompositionTest, displayOffREComposedNormalBufferLayer) {
+    mDisplayOff = true;
     displayRefreshCompositionDirtyFrame<CompositionCase<
             PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
             ChangeCompositionTypeVariant<IComposerClient::Composition::DEVICE,
@@ -1326,5 +1430,26 @@
             NoCompositionTypeVariant, REScreenshotResultVariant>>();
 }
 
+/* ------------------------------------------------------------------------
+ *  Client composition forced through debug/developer settings
+ */
+
+TEST_F(CompositionTest, DebugOptionForcingClientCompositionOfBufferLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+                            ForcedClientCompositionViaDebugOptionResultVariant>>();
+}
+
+TEST_F(CompositionTest, DebugOptionForcingClientCompositionOfBufferLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+                            ForcedClientCompositionViaDebugOptionResultVariant>>();
+}
+
 } // namespace
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index 0aa8cf5..afebc40 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -43,7 +43,7 @@
     void createDispSync();
     void createDispSyncSource();
 
-    void onVSyncEvent(nsecs_t when) override;
+    void onVSyncEvent(nsecs_t when, nsecs_t expectedVSyncTimestamp) override;
 
     std::unique_ptr<mock::DispSync> mDispSync;
     std::unique_ptr<DispSyncSource> mDispSyncSource;
@@ -51,7 +51,6 @@
     AsyncCallRecorder<void (*)(nsecs_t)> mVSyncEventCallRecorder;
 
     static constexpr std::chrono::nanoseconds mPhaseOffset = 6ms;
-    static constexpr std::chrono::nanoseconds mOffsetThresholdForNextVsync = 16ms;
     static constexpr int mIterations = 100;
 };
 
@@ -67,7 +66,7 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
-void DispSyncSourceTest::onVSyncEvent(nsecs_t when) {
+void DispSyncSourceTest::onVSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) {
     ALOGD("onVSyncEvent: %" PRId64, when);
 
     mVSyncEventCallRecorder.recordCall(when);
@@ -79,8 +78,7 @@
 
 void DispSyncSourceTest::createDispSyncSource() {
     createDispSync();
-    mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(),
-                                                       mOffsetThresholdForNextVsync.count(), true,
+    mDispSyncSource = std::make_unique<DispSyncSource>(mDispSync.get(), mPhaseOffset.count(), true,
                                                        "DispSyncSourceTest");
     mDispSyncSource->setCallback(this);
 }
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
index 55995d0..2a0e913 100644
--- a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#include <functional>
+#include <string_view>
+
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
@@ -61,11 +64,73 @@
         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
         "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6";
 
+const unsigned char kPanasonicTvEdid[] =
+        "\x00\xff\xff\xff\xff\xff\xff\x00\x34\xa9\x96\xa2\x01\x01\x01"
+        "\x01\x00\x1d\x01\x03\x80\x80\x48\x78\x0a\xda\xff\xa3\x58\x4a"
+        "\xa2\x29\x17\x49\x4b\x20\x08\x00\x31\x40\x61\x40\x01\x01\x01"
+        "\x01\x01\x01\x01\x01\x01\x01\x01\x01\x08\xe8\x00\x30\xf2\x70"
+        "\x5a\x80\xb0\x58\x8a\x00\xba\x88\x21\x00\x00\x1e\x02\x3a\x80"
+        "\x18\x71\x38\x2d\x40\x58\x2c\x45\x00\xba\x88\x21\x00\x00\x1e"
+        "\x00\x00\x00\xfc\x00\x50\x61\x6e\x61\x73\x6f\x6e\x69\x63\x2d"
+        "\x54\x56\x0a\x00\x00\x00\xfd\x00\x17\x3d\x0f\x88\x3c\x00\x0a"
+        "\x20\x20\x20\x20\x20\x20\x01\x1d\x02\x03\x6b\xf0\x57\x61\x60"
+        "\x10\x1f\x66\x65\x05\x14\x20\x21\x22\x04\x13\x03\x12\x07\x16"
+        "\x5d\x5e\x5f\x62\x63\x64\x2c\x0d\x07\x01\x15\x07\x50\x57\x07"
+        "\x01\x67\x04\x03\x83\x0f\x00\x00\x6e\x03\x0c\x00\x20\x00\x38"
+        "\x3c\x2f\x08\x80\x01\x02\x03\x04\x67\xd8\x5d\xc4\x01\x78\x80"
+        "\x03\xe2\x00\x4b\xe3\x05\xff\x01\xe2\x0f\x33\xe3\x06\x0f\x01"
+        "\xe5\x01\x8b\x84\x90\x01\xeb\x01\x46\xd0\x00\x44\x03\x70\x80"
+        "\x5e\x75\x94\xe6\x11\x46\xd0\x00\x70\x00\x66\x21\x56\xaa\x51"
+        "\x00\x1e\x30\x46\x8f\x33\x00\xba\x88\x21\x00\x00\x1e\x00\x00"
+        "\xc8";
+
+const unsigned char kHisenseTvEdid[] =
+        "\x00\xff\xff\xff\xff\xff\xff\x00\x20\xa3\x00\x00\x00\x00\x00"
+        "\x00\x12\x1d\x01\x03\x80\x00\x00\x78\x0a\xd7\xa5\xa2\x59\x4a"
+        "\x96\x24\x14\x50\x54\xa3\x08\x00\xd1\xc0\xb3\x00\x81\x00\x81"
+        "\x80\x81\x40\x81\xc0\x01\x01\x01\x01\x02\x3a\x80\x18\x71\x38"
+        "\x2d\x40\x58\x2c\x45\x00\x3f\x43\x21\x00\x00\x1a\x02\x3a\x80"
+        "\x18\x71\x38\x2d\x40\x58\x2c\x45\x00\x3f\x43\x21\x00\x00\x1a"
+        "\x00\x00\x00\xfd\x00\x1e\x4c\x1e\x5a\x1e\x00\x0a\x20\x20\x20"
+        "\x20\x20\x20\x00\x00\x00\xfc\x00\x48\x69\x73\x65\x6e\x73\x65"
+        "\x0a\x20\x20\x20\x20\x20\x01\x47\x02\x03\x2d\x71\x50\x90\x05"
+        "\x04\x03\x07\x02\x06\x01\x1f\x14\x13\x12\x16\x11\x15\x20\x2c"
+        "\x09\x07\x03\x15\x07\x50\x57\x07\x00\x39\x07\xbb\x66\x03\x0c"
+        "\x00\x12\x34\x00\x83\x01\x00\x00\x01\x1d\x00\x72\x51\xd0\x1e"
+        "\x20\x6e\x28\x55\x00\xc4\x8e\x21\x00\x00\x1e\x01\x1d\x80\x18"
+        "\x71\x1c\x16\x20\x58\x2c\x25\x00\xc4\x8e\x21\x00\x00\x9e\x8c"
+        "\x0a\xd0\x8a\x20\xe0\x2d\x10\x10\x3e\x96\x00\x13\x8e\x21\x00"
+        "\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+        "\x07";
+
+const unsigned char kCtlDisplayEdid[] =
+        "\x00\xff\xff\xff\xff\xff\xff\x00\x0e\x8c\x9d\x24\x00\x00\x00\x00"
+        "\xff\x17\x01\x04\xa5\x34\x1d\x78\x3a\xa7\x25\xa4\x57\x51\xa0\x26"
+        "\x10\x50\x54\xbf\xef\x80\xb3\x00\xa9\x40\x95\x00\x81\x40\x81\x80"
+        "\x95\x0f\x71\x4f\x90\x40\x02\x3a\x80\x18\x71\x38\x2d\x40\x58\x2c"
+        "\x45\x00\x09\x25\x21\x00\x00\x1e\x66\x21\x50\xb0\x51\x00\x1b\x30"
+        "\x40\x70\x36\x00\x09\x25\x21\x00\x00\x1e\x00\x00\x00\xfd\x00\x31"
+        "\x4c\x1e\x52\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xfc"
+        "\x00\x4c\x50\x32\x33\x36\x31\x0a\x20\x20\x20\x20\x20\x20\x01\x3e"
+        "\x02\x03\x22\xf2\x4f\x90\x9f\x05\x14\x04\x13\x03\x02\x12\x11\x07"
+        "\x06\x16\x15\x01\x23\x09\x07\x07\x83\x01\x00\x00\x65\xb9\x14\x00"
+        "\x04\x00\x02\x3a\x80\x18\x71\x38\x2d\x40\x58\x2c\x45\x00\x09\x25"
+        "\x21\x00\x00\x1e\x02\x3a\x80\xd0\x72\x38\x2d\x40\x10\x2c\x45\x80"
+        "\x09\x25\x21\x00\x00\x1e\x01\x1d\x00\x72\x51\xd0\x1e\x20\x6e\x28"
+        "\x55\x00\x09\x25\x21\x00\x00\x1e\x8c\x0a\xd0\x8a\x20\xe0\x2d\x10"
+        "\x10\x3e\x96\x00\x09\x25\x21\x00\x00\x18\x00\x00\x00\x00\x00\x00"
+        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4";
+
 template <size_t N>
 DisplayIdentificationData asDisplayIdentificationData(const unsigned char (&bytes)[N]) {
     return DisplayIdentificationData(bytes, bytes + N - 1);
 }
 
+uint32_t hash(const char* str) {
+    return static_cast<uint32_t>(std::hash<std::string_view>()(str));
+}
+
 } // namespace
 
 const DisplayIdentificationData& getInternalEdid() {
@@ -83,12 +148,30 @@
     return data;
 }
 
+const DisplayIdentificationData& getPanasonicTvEdid() {
+    static const DisplayIdentificationData data = asDisplayIdentificationData(kPanasonicTvEdid);
+    return data;
+}
+
+const DisplayIdentificationData& getHisenseTvEdid() {
+    static const DisplayIdentificationData data = asDisplayIdentificationData(kHisenseTvEdid);
+    return data;
+}
+
+const DisplayIdentificationData& getCtlDisplayEdid() {
+    static const DisplayIdentificationData data = asDisplayIdentificationData(kCtlDisplayEdid);
+    return data;
+}
+
 TEST(DisplayIdentificationTest, isEdid) {
     EXPECT_FALSE(isEdid({}));
 
     EXPECT_TRUE(isEdid(getInternalEdid()));
     EXPECT_TRUE(isEdid(getExternalEdid()));
     EXPECT_TRUE(isEdid(getExternalEedid()));
+    EXPECT_TRUE(isEdid(getPanasonicTvEdid()));
+    EXPECT_TRUE(isEdid(getHisenseTvEdid()));
+    EXPECT_TRUE(isEdid(getCtlDisplayEdid()));
 }
 
 TEST(DisplayIdentificationTest, parseEdid) {
@@ -97,19 +180,86 @@
     EXPECT_EQ(0x4ca3u, edid->manufacturerId);
     EXPECT_STREQ("SEC", edid->pnpId.data());
     // ASCII text should be used as fallback if display name and serial number are missing.
-    EXPECT_EQ("121AT11-801", edid->displayName);
+    EXPECT_EQ(hash("121AT11-801"), edid->modelHash);
+    EXPECT_TRUE(edid->displayName.empty());
+    EXPECT_EQ(12610, edid->productId);
+    EXPECT_EQ(21, edid->manufactureOrModelYear);
+    EXPECT_EQ(0, edid->manufactureWeek);
+    EXPECT_FALSE(edid->cea861Block);
 
     edid = parseEdid(getExternalEdid());
     ASSERT_TRUE(edid);
     EXPECT_EQ(0x22f0u, edid->manufacturerId);
     EXPECT_STREQ("HWP", edid->pnpId.data());
+    EXPECT_EQ(hash("HP ZR30w"), edid->modelHash);
     EXPECT_EQ("HP ZR30w", edid->displayName);
+    EXPECT_EQ(10348, edid->productId);
+    EXPECT_EQ(22, edid->manufactureOrModelYear);
+    EXPECT_EQ(2, edid->manufactureWeek);
+    EXPECT_FALSE(edid->cea861Block);
 
     edid = parseEdid(getExternalEedid());
     ASSERT_TRUE(edid);
     EXPECT_EQ(0x4c2du, edid->manufacturerId);
     EXPECT_STREQ("SAM", edid->pnpId.data());
+    EXPECT_EQ(hash("SAMSUNG"), edid->modelHash);
     EXPECT_EQ("SAMSUNG", edid->displayName);
+    EXPECT_EQ(2302, edid->productId);
+    EXPECT_EQ(21, edid->manufactureOrModelYear);
+    EXPECT_EQ(41, edid->manufactureWeek);
+    ASSERT_TRUE(edid->cea861Block);
+    ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock);
+    auto physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress;
+    EXPECT_EQ(2, physicalAddress.a);
+    EXPECT_EQ(0, physicalAddress.b);
+    EXPECT_EQ(0, physicalAddress.c);
+    EXPECT_EQ(0, physicalAddress.d);
+
+    edid = parseEdid(getPanasonicTvEdid());
+    ASSERT_TRUE(edid);
+    EXPECT_EQ(13481, edid->manufacturerId);
+    EXPECT_STREQ("MEI", edid->pnpId.data());
+    EXPECT_EQ(hash("Panasonic-TV"), edid->modelHash);
+    EXPECT_EQ("Panasonic-TV", edid->displayName);
+    EXPECT_EQ(41622, edid->productId);
+    EXPECT_EQ(29, edid->manufactureOrModelYear);
+    EXPECT_EQ(0, edid->manufactureWeek);
+    ASSERT_TRUE(edid->cea861Block);
+    ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock);
+    physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress;
+    EXPECT_EQ(2, physicalAddress.a);
+    EXPECT_EQ(0, physicalAddress.b);
+    EXPECT_EQ(0, physicalAddress.c);
+    EXPECT_EQ(0, physicalAddress.d);
+
+    edid = parseEdid(getHisenseTvEdid());
+    ASSERT_TRUE(edid);
+    EXPECT_EQ(8355, edid->manufacturerId);
+    EXPECT_STREQ("HEC", edid->pnpId.data());
+    EXPECT_EQ(hash("Hisense"), edid->modelHash);
+    EXPECT_EQ("Hisense", edid->displayName);
+    EXPECT_EQ(0, edid->productId);
+    EXPECT_EQ(29, edid->manufactureOrModelYear);
+    EXPECT_EQ(18, edid->manufactureWeek);
+    ASSERT_TRUE(edid->cea861Block);
+    ASSERT_TRUE(edid->cea861Block->hdmiVendorDataBlock);
+    physicalAddress = edid->cea861Block->hdmiVendorDataBlock->physicalAddress;
+    EXPECT_EQ(1, physicalAddress.a);
+    EXPECT_EQ(2, physicalAddress.b);
+    EXPECT_EQ(3, physicalAddress.c);
+    EXPECT_EQ(4, physicalAddress.d);
+
+    edid = parseEdid(getCtlDisplayEdid());
+    ASSERT_TRUE(edid);
+    EXPECT_EQ(3724, edid->manufacturerId);
+    EXPECT_STREQ("CTL", edid->pnpId.data());
+    EXPECT_EQ(hash("LP2361"), edid->modelHash);
+    EXPECT_EQ("LP2361", edid->displayName);
+    EXPECT_EQ(9373, edid->productId);
+    EXPECT_EQ(23, edid->manufactureOrModelYear);
+    EXPECT_EQ(0xff, edid->manufactureWeek);
+    ASSERT_TRUE(edid->cea861Block);
+    EXPECT_FALSE(edid->cea861Block->hdmiVendorDataBlock);
 }
 
 TEST(DisplayIdentificationTest, parseInvalidEdid) {
@@ -122,13 +272,15 @@
     auto edid = parseEdid(data);
     ASSERT_TRUE(edid);
     // Serial number should be used as fallback if display name is invalid.
-    EXPECT_EQ("CN4202137Q", edid->displayName);
+    const auto modelHash = hash("CN4202137Q");
+    EXPECT_EQ(modelHash, edid->modelHash);
+    EXPECT_TRUE(edid->displayName.empty());
 
     // Parsing should succeed even if EDID is truncated.
     data.pop_back();
     edid = parseEdid(data);
     ASSERT_TRUE(edid);
-    EXPECT_EQ("CN4202137Q", edid->displayName);
+    EXPECT_EQ(modelHash, edid->modelHash);
 }
 
 TEST(DisplayIdentificationTest, getPnpId) {
@@ -156,6 +308,93 @@
     EXPECT_NE(secondaryInfo->id, tertiaryInfo->id);
 }
 
+TEST(DisplayIdentificationTest, deviceProductInfo) {
+    using ManufactureYear = DeviceProductInfo::ManufactureYear;
+    using ManufactureWeekAndYear = DeviceProductInfo::ManufactureWeekAndYear;
+    using ModelYear = DeviceProductInfo::ModelYear;
+    using RelativeAddress = DeviceProductInfo::RelativeAddress;
+
+    {
+        const auto displayIdInfo = parseDisplayIdentificationData(0, getInternalEdid());
+        ASSERT_TRUE(displayIdInfo);
+        ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+        const auto& info = *displayIdInfo->deviceProductInfo;
+        EXPECT_STREQ("", info.name.data());
+        EXPECT_STREQ("SEC", info.manufacturerPnpId.data());
+        EXPECT_STREQ("12610", info.productId.data());
+        ASSERT_TRUE(std::holds_alternative<ManufactureYear>(info.manufactureOrModelDate));
+        EXPECT_EQ(2011, std::get<ManufactureYear>(info.manufactureOrModelDate).year);
+        EXPECT_EQ(DeviceProductInfo::NO_RELATIVE_ADDRESS, info.relativeAddress);
+    }
+    {
+        const auto displayIdInfo = parseDisplayIdentificationData(0, getExternalEdid());
+        ASSERT_TRUE(displayIdInfo);
+        ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+        const auto& info = *displayIdInfo->deviceProductInfo;
+        EXPECT_STREQ("HP ZR30w", info.name.data());
+        EXPECT_STREQ("HWP", info.manufacturerPnpId.data());
+        EXPECT_STREQ("10348", info.productId.data());
+        ASSERT_TRUE(std::holds_alternative<ManufactureWeekAndYear>(info.manufactureOrModelDate));
+        const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
+        EXPECT_EQ(2012, date.year);
+        EXPECT_EQ(2, date.week);
+        EXPECT_EQ(DeviceProductInfo::NO_RELATIVE_ADDRESS, info.relativeAddress);
+    }
+    {
+        const auto displayIdInfo = parseDisplayIdentificationData(0, getExternalEedid());
+        ASSERT_TRUE(displayIdInfo);
+        ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+        const auto& info = *displayIdInfo->deviceProductInfo;
+        EXPECT_STREQ("SAMSUNG", info.name.data());
+        EXPECT_STREQ("SAM", info.manufacturerPnpId.data());
+        EXPECT_STREQ("2302", info.productId.data());
+        ASSERT_TRUE(std::holds_alternative<ManufactureWeekAndYear>(info.manufactureOrModelDate));
+        const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
+        EXPECT_EQ(2011, date.year);
+        EXPECT_EQ(41, date.week);
+        EXPECT_EQ((RelativeAddress{{2, 0, 0, 0}}), info.relativeAddress);
+    }
+    {
+        const auto displayIdInfo = parseDisplayIdentificationData(0, getPanasonicTvEdid());
+        ASSERT_TRUE(displayIdInfo);
+        ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+        const auto& info = *displayIdInfo->deviceProductInfo;
+        EXPECT_STREQ("Panasonic-TV", info.name.data());
+        EXPECT_STREQ("MEI", info.manufacturerPnpId.data());
+        EXPECT_STREQ("41622", info.productId.data());
+        ASSERT_TRUE(std::holds_alternative<ManufactureYear>(info.manufactureOrModelDate));
+        const auto& date = std::get<ManufactureYear>(info.manufactureOrModelDate);
+        EXPECT_EQ(2019, date.year);
+        EXPECT_EQ((RelativeAddress{{2, 0, 0, 0}}), info.relativeAddress);
+    }
+    {
+        const auto displayIdInfo = parseDisplayIdentificationData(0, getHisenseTvEdid());
+        ASSERT_TRUE(displayIdInfo);
+        ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+        const auto& info = *displayIdInfo->deviceProductInfo;
+        EXPECT_STREQ("Hisense", info.name.data());
+        EXPECT_STREQ("HEC", info.manufacturerPnpId.data());
+        EXPECT_STREQ("0", info.productId.data());
+        ASSERT_TRUE(std::holds_alternative<ManufactureWeekAndYear>(info.manufactureOrModelDate));
+        const auto& date = std::get<ManufactureWeekAndYear>(info.manufactureOrModelDate);
+        EXPECT_EQ(2019, date.year);
+        EXPECT_EQ(18, date.week);
+        EXPECT_EQ((RelativeAddress{{1, 2, 3, 4}}), info.relativeAddress);
+    }
+    {
+        const auto displayIdInfo = parseDisplayIdentificationData(0, getCtlDisplayEdid());
+        ASSERT_TRUE(displayIdInfo);
+        ASSERT_TRUE(displayIdInfo->deviceProductInfo);
+        const auto& info = *displayIdInfo->deviceProductInfo;
+        EXPECT_STREQ("LP2361", info.name.data());
+        EXPECT_STREQ("CTL", info.manufacturerPnpId.data());
+        EXPECT_STREQ("9373", info.productId.data());
+        ASSERT_TRUE(std::holds_alternative<ModelYear>(info.manufactureOrModelDate));
+        EXPECT_EQ(2013, std::get<ModelYear>(info.manufactureOrModelDate).year);
+        EXPECT_EQ(DeviceProductInfo::NO_RELATIVE_ADDRESS, info.relativeAddress);
+    }
+}
+
 TEST(DisplayIdentificationTest, getFallbackDisplayId) {
     // Manufacturer ID should be invalid.
     ASSERT_FALSE(getPnpId(getFallbackDisplayId(0)));
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index f40996e..ce5f35c 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "LibSurfaceFlingerUnittests"
 
@@ -21,45 +25,60 @@
 
 #include <compositionengine/Display.h>
 #include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/impl/Display.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/mock/Display.h>
+#include <compositionengine/mock/DisplayColorProfile.h>
 #include <compositionengine/mock/DisplaySurface.h>
+#include <compositionengine/mock/RenderSurface.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <gui/mock/GraphicBufferConsumer.h>
+#include <gui/mock/GraphicBufferProducer.h>
 #include <log/log.h>
 #include <renderengine/mock/RenderEngine.h>
 #include <ui/DebugUtils.h>
 
 #include "DisplayIdentificationTest.h"
-#include "Scheduler/RefreshRateConfigs.h"
 #include "TestableScheduler.h"
 #include "TestableSurfaceFlinger.h"
 #include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockPowerAdvisor.h"
 #include "mock/MockDispSync.h"
 #include "mock/MockEventControlThread.h"
 #include "mock/MockEventThread.h"
 #include "mock/MockMessageQueue.h"
 #include "mock/MockNativeWindowSurface.h"
 #include "mock/MockSurfaceInterceptor.h"
-#include "mock/gui/MockGraphicBufferConsumer.h"
-#include "mock/gui/MockGraphicBufferProducer.h"
 #include "mock/system/window/MockNativeWindow.h"
 
 namespace android {
 namespace {
 
+namespace hal = android::hardware::graphics::composer::hal;
+
 using testing::_;
+using testing::AnyNumber;
 using testing::DoAll;
 using testing::Mock;
 using testing::ResultOf;
 using testing::Return;
+using testing::ReturnRefOfCopy;
 using testing::SetArgPointee;
+using testing::StrictMock;
 
-using android::Hwc2::ColorMode;
-using android::Hwc2::Error;
-using android::Hwc2::Hdr;
-using android::Hwc2::IComposer;
-using android::Hwc2::IComposerClient;
-using android::Hwc2::PerFrameMetadataKey;
-using android::Hwc2::RenderIntent;
+using hal::ColorMode;
+using hal::Connection;
+using hal::DisplayCapability;
+using hal::DisplayType;
+using hal::Error;
+using hal::Hdr;
+using hal::HWDisplayId;
+using hal::IComposer;
+using hal::IComposerClient;
+using hal::PerFrameMetadataKey;
+using hal::PowerMode;
+using hal::RenderIntent;
 
 using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
 using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
@@ -70,7 +89,7 @@
 constexpr int32_t DEFAULT_DPI = 320;
 constexpr int DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT = HAL_PIXEL_FORMAT_RGB_565;
 
-constexpr int HWC_POWER_MODE_LEET = 1337; // An out of range power mode value
+constexpr int POWER_MODE_LEET = 1337; // An out of range power mode value
 
 /* ------------------------------------------------------------------------
  * Boolean avoidance
@@ -96,19 +115,19 @@
     DisplayTransactionTest();
     ~DisplayTransactionTest() override;
 
-    void setupScheduler();
-
     // --------------------------------------------------------------------
     // Mock/Fake injection
 
+    void injectMockScheduler();
     void injectMockComposer(int virtualDisplayCount);
     void injectFakeBufferQueueFactory();
     void injectFakeNativeWindowSurfaceFactory();
+    sp<DisplayDevice> injectDefaultInternalDisplay(std::function<void(FakeDisplayDeviceInjector&)>);
 
     // --------------------------------------------------------------------
     // Postcondition helpers
 
-    bool hasPhysicalHwcDisplay(hwc2_display_t hwcDisplayId);
+    bool hasPhysicalHwcDisplay(HWDisplayId hwcDisplayId);
     bool hasTransactionFlagSet(int flag);
     bool hasDisplayDevice(sp<IBinder> displayToken);
     sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken);
@@ -120,13 +139,10 @@
     // --------------------------------------------------------------------
     // Test instances
 
-    TestableScheduler* mScheduler;
     TestableSurfaceFlinger mFlinger;
-    mock::EventThread* mEventThread = new mock::EventThread();
-    mock::EventThread* mSFEventThread = new mock::EventThread();
-    mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
     sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
     sp<GraphicBuffer> mBuffer = new GraphicBuffer();
+    Hwc2::mock::PowerAdvisor mPowerAdvisor;
 
     // These mocks are created by the test, but are destroyed by SurfaceFlinger
     // by virtue of being stored into a std::unique_ptr. However we still need
@@ -135,7 +151,11 @@
     Hwc2::mock::Composer* mComposer = nullptr;
     mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
     mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor();
-    mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+
+    mock::DispSync* mPrimaryDispSync = new mock::DispSync;
+    mock::EventControlThread* mEventControlThread = new mock::EventControlThread;
+    mock::EventThread* mEventThread = new mock::EventThread;
+    mock::EventThread* mSFEventThread = new mock::EventThread;
 
     // These mocks are created only when expected to be created via a factory.
     sp<mock::GraphicBufferConsumer> mConsumer;
@@ -151,7 +171,7 @@
     // Default to no wide color display support configured
     mFlinger.mutableHasWideColorDisplay() = false;
     mFlinger.mutableUseColorManagement() = false;
-    mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+    mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
 
     // Default to using HWC virtual displays
     mFlinger.mutableUseHwcVirtualDisplays() = true;
@@ -165,7 +185,7 @@
         return nullptr;
     });
 
-    setupScheduler();
+    injectMockScheduler();
     mFlinger.mutableEventQueue().reset(mMessageQueue);
     mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
     mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
@@ -179,35 +199,25 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
-void DisplayTransactionTest::setupScheduler() {
-    std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}};
-    mFlinger.mutableRefreshRateConfigs() =
-            std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
-                                                            /*currentConfig=*/0);
-    mFlinger.mutableRefreshRateStats() =
-            std::make_unique<scheduler::RefreshRateStats>(*mFlinger.mutableRefreshRateConfigs(),
-                                                          *mFlinger.mutableTimeStats(),
-                                                          /*currentConfig=*/0,
-                                                          /*powerMode=*/HWC_POWER_MODE_OFF);
-    mScheduler = new TestableScheduler(*mFlinger.mutableRefreshRateConfigs());
-    mScheduler->mutableEventControlThread().reset(mEventControlThread);
-    mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
+void DisplayTransactionTest::injectMockScheduler() {
     EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_));
-    EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_));
+    EXPECT_CALL(*mEventThread, createEventConnection(_, _))
+            .WillOnce(Return(new EventThreadConnection(mEventThread, ResyncCallback(),
+                                                       ISurfaceComposer::eConfigChangedSuppress)));
 
-    sp<Scheduler::ConnectionHandle> sfConnectionHandle =
-            mScheduler->addConnection(std::unique_ptr<EventThread>(mSFEventThread));
-    mFlinger.mutableSfConnectionHandle() = std::move(sfConnectionHandle);
-    sp<Scheduler::ConnectionHandle> appConnectionHandle =
-            mScheduler->addConnection(std::unique_ptr<EventThread>(mEventThread));
-    mFlinger.mutableAppConnectionHandle() = std::move(appConnectionHandle);
-    mFlinger.mutableScheduler().reset(mScheduler);
+    EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_));
+    EXPECT_CALL(*mSFEventThread, createEventConnection(_, _))
+            .WillOnce(Return(new EventThreadConnection(mSFEventThread, ResyncCallback(),
+                                                       ISurfaceComposer::eConfigChangedSuppress)));
+
+    mFlinger.setupScheduler(std::unique_ptr<DispSync>(mPrimaryDispSync),
+                            std::unique_ptr<EventControlThread>(mEventControlThread),
+                            std::unique_ptr<EventThread>(mEventThread),
+                            std::unique_ptr<EventThread>(mSFEventThread));
 }
 
 void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) {
     mComposer = new Hwc2::mock::Composer();
-    EXPECT_CALL(*mComposer, getCapabilities())
-            .WillOnce(Return(std::vector<IComposer::Capability>()));
     EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
     mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
 
@@ -238,7 +248,51 @@
     });
 }
 
-bool DisplayTransactionTest::hasPhysicalHwcDisplay(hwc2_display_t hwcDisplayId) {
+sp<DisplayDevice> DisplayTransactionTest::injectDefaultInternalDisplay(
+        std::function<void(FakeDisplayDeviceInjector&)> injectExtra) {
+    constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777};
+    constexpr int DEFAULT_DISPLAY_WIDTH = 1080;
+    constexpr int DEFAULT_DISPLAY_HEIGHT = 1920;
+    constexpr HWDisplayId DEFAULT_DISPLAY_HWC_DISPLAY_ID = 0;
+
+    // The DisplayDevice is required to have a framebuffer (behind the
+    // ANativeWindow interface) which uses the actual hardware display
+    // size.
+    EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
+    EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_HEIGHT), Return(0)));
+    EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT));
+    EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT));
+    EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64));
+    EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(AnyNumber());
+
+    auto compositionDisplay = compositionengine::impl::
+            createDisplay(mFlinger.getCompositionEngine(),
+                          compositionengine::DisplayCreationArgsBuilder()
+                                  .setPhysical(
+                                          {DEFAULT_DISPLAY_ID, DisplayConnectionType::Internal})
+                                  .setPixels({DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT})
+                                  .setPowerAdvisor(&mPowerAdvisor)
+                                  .build());
+
+    auto injector =
+            FakeDisplayDeviceInjector(mFlinger, compositionDisplay, DisplayConnectionType::Internal,
+                                      DEFAULT_DISPLAY_HWC_DISPLAY_ID, true /* isPrimary */);
+
+    injector.setNativeWindow(mNativeWindow);
+    if (injectExtra) {
+        injectExtra(injector);
+    }
+
+    auto displayDevice = injector.inject();
+
+    Mock::VerifyAndClear(mNativeWindow.get());
+
+    return displayDevice;
+}
+
+bool DisplayTransactionTest::hasPhysicalHwcDisplay(HWDisplayId hwcDisplayId) {
     return mFlinger.mutableHwcPhysicalDisplayIdMap().count(hwcDisplayId) == 1;
 }
 
@@ -296,8 +350,8 @@
     static std::optional<DisplayId> get() {
         if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
             return getFallbackDisplayId(static_cast<bool>(PhysicalDisplay::PRIMARY)
-                                                ? HWC_DISPLAY_PRIMARY
-                                                : HWC_DISPLAY_EXTERNAL);
+                                                ? LEGACY_DISPLAY_TYPE_PRIMARY
+                                                : LEGACY_DISPLAY_TYPE_EXTERNAL);
         }
 
         const auto info =
@@ -317,6 +371,33 @@
     static std::optional<DisplayId> get() { return {}; }
 };
 
+template <typename>
+struct DisplayConnectionTypeGetter {
+    static constexpr std::optional<DisplayConnectionType> value;
+};
+
+template <typename PhysicalDisplay>
+struct DisplayConnectionTypeGetter<PhysicalDisplayId<PhysicalDisplay>> {
+    static constexpr std::optional<DisplayConnectionType> value = PhysicalDisplay::CONNECTION_TYPE;
+};
+
+template <typename>
+struct HwcDisplayIdGetter {
+    static constexpr std::optional<HWDisplayId> value;
+};
+
+constexpr HWDisplayId HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID = 1010;
+
+template <DisplayId::Type displayId>
+struct HwcDisplayIdGetter<VirtualDisplayId<displayId>> {
+    static constexpr std::optional<HWDisplayId> value = HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID;
+};
+
+template <typename PhysicalDisplay>
+struct HwcDisplayIdGetter<PhysicalDisplayId<PhysicalDisplay>> {
+    static constexpr std::optional<HWDisplayId> value = PhysicalDisplay::HWC_DISPLAY_ID;
+};
+
 // DisplayIdType can be:
 //     1) PhysicalDisplayId<...> for generated ID of physical display backed by HWC.
 //     2) VirtualDisplayId<...> for hard-coded ID of virtual display backed by HWC.
@@ -325,6 +406,8 @@
           Secure secure, Primary primary, int grallocUsage>
 struct DisplayVariant {
     using DISPLAY_ID = DisplayIdGetter<DisplayIdType>;
+    using CONNECTION_TYPE = DisplayConnectionTypeGetter<DisplayIdType>;
+    using HWC_DISPLAY_ID_OPT = HwcDisplayIdGetter<DisplayIdType>;
 
     // The display width and height
     static constexpr int WIDTH = width;
@@ -349,9 +432,21 @@
     static constexpr Primary PRIMARY = primary;
 
     static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
-        auto injector =
-                FakeDisplayDeviceInjector(test->mFlinger, DISPLAY_ID::get(),
-                                          static_cast<bool>(VIRTUAL), static_cast<bool>(PRIMARY));
+        auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder();
+        if (auto displayId = DISPLAY_ID::get()) {
+            ceDisplayArgs.setPhysical({*displayId, DisplayConnectionType::Internal});
+        } else {
+            ceDisplayArgs.setUseHwcVirtualDisplays(false);
+        }
+        ceDisplayArgs.setPixels({WIDTH, HEIGHT}).setPowerAdvisor(&test->mPowerAdvisor).build();
+
+        auto compositionDisplay =
+                compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+                                                       ceDisplayArgs.build());
+
+        auto injector = FakeDisplayDeviceInjector(test->mFlinger, compositionDisplay,
+                                                  CONNECTION_TYPE::value, HWC_DISPLAY_ID_OPT::value,
+                                                  static_cast<bool>(PRIMARY));
 
         injector.setSecure(static_cast<bool>(SECURE));
         injector.setNativeWindow(test->mNativeWindow);
@@ -409,21 +504,20 @@
     }
 };
 
-template <hwc2_display_t hwcDisplayId, HWC2::DisplayType hwcDisplayType, typename DisplayVariant,
+template <HWDisplayId hwcDisplayId, DisplayType hwcDisplayType, typename DisplayVariant,
           typename PhysicalDisplay = void>
 struct HwcDisplayVariant {
     // The display id supplied by the HWC
-    static constexpr hwc2_display_t HWC_DISPLAY_ID = hwcDisplayId;
+    static constexpr HWDisplayId HWC_DISPLAY_ID = hwcDisplayId;
 
     // The HWC display type
-    static constexpr HWC2::DisplayType HWC_DISPLAY_TYPE = hwcDisplayType;
+    static constexpr DisplayType HWC_DISPLAY_TYPE = hwcDisplayType;
 
     // The HWC active configuration id
     static constexpr int HWC_ACTIVE_CONFIG_ID = 2001;
-    static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
+    static constexpr PowerMode INIT_POWER_MODE = PowerMode::ON;
 
-    static void injectPendingHotplugEvent(DisplayTransactionTest* test,
-                                          HWC2::Connection connection) {
+    static void injectPendingHotplugEvent(DisplayTransactionTest* test, Connection connection) {
         test->mFlinger.mutablePendingHotplugEvents().emplace_back(
                 HotplugEvent{HWC_DISPLAY_ID, connection});
     }
@@ -445,21 +539,43 @@
     // Called by tests to inject a HWC display setup
     static void injectHwcDisplay(DisplayTransactionTest* test) {
         EXPECT_CALL(*test->mComposer, getDisplayCapabilities(HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<DisplayCapability>({})),
                                 Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    setPowerMode(HWC_DISPLAY_ID,
-                                 static_cast<Hwc2::IComposerClient::PowerMode>(INIT_POWER_MODE)))
+        EXPECT_CALL(*test->mComposer, setPowerMode(HWC_DISPLAY_ID, INIT_POWER_MODE))
                 .WillOnce(Return(Error::NONE));
         injectHwcDisplayWithNoDefaultCapabilities(test);
     }
 
+    static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
+            DisplayTransactionTest* test) {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+
+        auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
+                                     .setPhysical({*DisplayVariant::DISPLAY_ID::get(),
+                                                   PhysicalDisplay::CONNECTION_TYPE})
+                                     .setPixels({DisplayVariant::WIDTH, DisplayVariant::HEIGHT})
+                                     .setIsSecure(static_cast<bool>(DisplayVariant::SECURE))
+                                     .setPowerAdvisor(&test->mPowerAdvisor)
+                                     .setName(std::string("Injected display for ") +
+                                              test_info->test_case_name() + "." + test_info->name())
+                                     .build();
+
+        return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+                                                      ceDisplayArgs);
+    }
+
     static void setupHwcHotplugCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getDisplayType(HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(static_cast<IComposerClient::DisplayType>(
-                                        HWC_DISPLAY_TYPE)),
-                                Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
+        constexpr auto CONNECTION_TYPE =
+                PhysicalDisplay::CONNECTION_TYPE == DisplayConnectionType::Internal
+                ? IComposerClient::DisplayConnectionType::INTERNAL
+                : IComposerClient::DisplayConnectionType::EXTERNAL;
+
+        EXPECT_CALL(*test->mComposer, getDisplayConnectionType(HWC_DISPLAY_ID, _))
+                .WillOnce(DoAll(SetArgPointee<1>(CONNECTION_TYPE), Return(hal::V2_4::Error::NONE)));
+
+        EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_))
+                .WillOnce(Return(hal::Error::NONE));
         EXPECT_CALL(*test->mComposer, getDisplayConfigs(HWC_DISPLAY_ID, _))
                 .WillOnce(DoAll(SetArgPointee<1>(std::vector<unsigned>{HWC_ACTIVE_CONFIG_ID}),
                                 Return(Error::NONE)));
@@ -483,6 +599,10 @@
                     getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
                                         IComposerClient::Attribute::DPI_Y, _))
                 .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                        IComposerClient::Attribute::CONFIG_GROUP, _))
+                .WillOnce(DoAll(SetArgPointee<3>(-1), Return(Error::NONE)));
 
         if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
             EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
@@ -506,12 +626,11 @@
 constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY =
         GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
 
-template <hwc2_display_t hwcDisplayId, typename PhysicalDisplay, int width, int height,
-          Critical critical>
+template <typename PhysicalDisplay, int width, int height, Critical critical>
 struct PhysicalDisplayVariant
       : DisplayVariant<PhysicalDisplayId<PhysicalDisplay>, width, height, critical, Async::FALSE,
                        Secure::TRUE, PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
-        HwcDisplayVariant<hwcDisplayId, HWC2::DisplayType::Physical,
+        HwcDisplayVariant<PhysicalDisplay::HWC_DISPLAY_ID, DisplayType::PHYSICAL,
                           DisplayVariant<PhysicalDisplayId<PhysicalDisplay>, width, height,
                                          critical, Async::FALSE, Secure::TRUE,
                                          PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
@@ -519,16 +638,20 @@
 
 template <bool hasIdentificationData>
 struct PrimaryDisplay {
+    static constexpr auto CONNECTION_TYPE = DisplayConnectionType::Internal;
     static constexpr Primary PRIMARY = Primary::TRUE;
     static constexpr uint8_t PORT = 255;
+    static constexpr HWDisplayId HWC_DISPLAY_ID = 1001;
     static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
     static constexpr auto GET_IDENTIFICATION_DATA = getInternalEdid;
 };
 
 template <bool hasIdentificationData>
 struct ExternalDisplay {
+    static constexpr auto CONNECTION_TYPE = DisplayConnectionType::External;
     static constexpr Primary PRIMARY = Primary::FALSE;
     static constexpr uint8_t PORT = 254;
+    static constexpr HWDisplayId HWC_DISPLAY_ID = 1002;
     static constexpr bool HAS_IDENTIFICATION_DATA = hasIdentificationData;
     static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
 };
@@ -536,19 +659,19 @@
 struct TertiaryDisplay {
     static constexpr Primary PRIMARY = Primary::FALSE;
     static constexpr uint8_t PORT = 253;
+    static constexpr HWDisplayId HWC_DISPLAY_ID = 1003;
     static constexpr auto GET_IDENTIFICATION_DATA = getExternalEdid;
 };
 
 // A primary display is a physical display that is critical
 using PrimaryDisplayVariant =
-        PhysicalDisplayVariant<1001, PrimaryDisplay<false>, 3840, 2160, Critical::TRUE>;
+        PhysicalDisplayVariant<PrimaryDisplay<false>, 3840, 2160, Critical::TRUE>;
 
 // An external display is physical display that is not critical.
 using ExternalDisplayVariant =
-        PhysicalDisplayVariant<1002, ExternalDisplay<false>, 1920, 1280, Critical::FALSE>;
+        PhysicalDisplayVariant<ExternalDisplay<false>, 1920, 1280, Critical::FALSE>;
 
-using TertiaryDisplayVariant =
-        PhysicalDisplayVariant<1003, TertiaryDisplay, 1600, 1200, Critical::FALSE>;
+using TertiaryDisplayVariant = PhysicalDisplayVariant<TertiaryDisplay, 1600, 1200, Critical::FALSE>;
 
 // A virtual display not supported by the HWC.
 constexpr uint32_t GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY = 0;
@@ -562,6 +685,23 @@
 
     static void injectHwcDisplay(DisplayTransactionTest*) {}
 
+    static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
+            DisplayTransactionTest* test) {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+
+        auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
+                                     .setPixels({Base::WIDTH, Base::HEIGHT})
+                                     .setIsSecure(static_cast<bool>(Base::SECURE))
+                                     .setPowerAdvisor(&test->mPowerAdvisor)
+                                     .setName(std::string("Injected display for ") +
+                                              test_info->test_case_name() + "." + test_info->name())
+                                     .build();
+
+        return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+                                                      ceDisplayArgs);
+    }
+
     static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
         EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
     }
@@ -580,13 +720,40 @@
       : DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE, secure,
                        Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
         HwcDisplayVariant<
-                1010, HWC2::DisplayType::Virtual,
+                HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID, DisplayType::VIRTUAL,
                 DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE,
                                secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>> {
     using Base = DisplayVariant<VirtualDisplayId<42>, width, height, Critical::FALSE, Async::TRUE,
                                 secure, Primary::FALSE, GRALLOC_USAGE_HW_COMPOSER>;
     using Self = HwcVirtualDisplayVariant<width, height, secure>;
 
+    static std::shared_ptr<compositionengine::Display> injectCompositionDisplay(
+            DisplayTransactionTest* test) {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+
+        auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder()
+                                     .setUseHwcVirtualDisplays(false)
+                                     .setPixels({Base::WIDTH, Base::HEIGHT})
+                                     .setIsSecure(static_cast<bool>(Base::SECURE))
+                                     .setPowerAdvisor(&test->mPowerAdvisor)
+                                     .setName(std::string("Injected display for ") +
+                                              test_info->test_case_name() + "." + test_info->name())
+                                     .build();
+
+        auto compositionDisplay =
+                compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+                                                       ceDisplayArgs);
+        compositionDisplay->setDisplayIdForTesting(Base::DISPLAY_ID::get());
+
+        // Insert display data so that the HWC thinks it created the virtual display.
+        if (const auto displayId = Base::DISPLAY_ID::get()) {
+            test->mFlinger.mutableHwcDisplayData().try_emplace(*displayId);
+        }
+
+        return compositionDisplay;
+    }
+
     static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
         Base::setupNativeWindowSurfaceCreationCallExpectations(test);
         EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1);
@@ -608,7 +775,7 @@
     static void injectConfigChange(DisplayTransactionTest* test) {
         test->mFlinger.mutableHasWideColorDisplay() = false;
         test->mFlinger.mutableUseColorManagement() = false;
-        test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+        test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
     }
 
     static void setupComposerCallExpectations(DisplayTransactionTest* test) {
@@ -628,7 +795,7 @@
     static void injectConfigChange(DisplayTransactionTest* test) {
         test->mFlinger.mutableUseColorManagement() = true;
         test->mFlinger.mutableHasWideColorDisplay() = true;
-        test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+        test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
     }
 
     static void setupComposerCallExpectations(DisplayTransactionTest* test) {
@@ -883,8 +1050,8 @@
 
 TEST_F(DisplayTransactionTest, hotplugEnqueuesEventsForDisplayTransaction) {
     constexpr int currentSequenceId = 123;
-    constexpr hwc2_display_t hwcDisplayId1 = 456;
-    constexpr hwc2_display_t hwcDisplayId2 = 654;
+    constexpr HWDisplayId hwcDisplayId1 = 456;
+    constexpr HWDisplayId hwcDisplayId2 = 654;
 
     // --------------------------------------------------------------------
     // Preconditions
@@ -907,8 +1074,8 @@
     // Invocation
 
     // Simulate two hotplug events (a connect and a disconnect)
-    mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId1, HWC2::Connection::Connected);
-    mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId2, HWC2::Connection::Disconnected);
+    mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId1, Connection::CONNECTED);
+    mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId2, Connection::DISCONNECTED);
 
     // --------------------------------------------------------------------
     // Postconditions
@@ -920,15 +1087,15 @@
     const auto& pendingEvents = mFlinger.mutablePendingHotplugEvents();
     ASSERT_EQ(2u, pendingEvents.size());
     EXPECT_EQ(hwcDisplayId1, pendingEvents[0].hwcDisplayId);
-    EXPECT_EQ(HWC2::Connection::Connected, pendingEvents[0].connection);
+    EXPECT_EQ(Connection::CONNECTED, pendingEvents[0].connection);
     EXPECT_EQ(hwcDisplayId2, pendingEvents[1].hwcDisplayId);
-    EXPECT_EQ(HWC2::Connection::Disconnected, pendingEvents[1].connection);
+    EXPECT_EQ(Connection::DISCONNECTED, pendingEvents[1].connection);
 }
 
 TEST_F(DisplayTransactionTest, hotplugDiscardsUnexpectedEvents) {
     constexpr int currentSequenceId = 123;
     constexpr int otherSequenceId = 321;
-    constexpr hwc2_display_t displayId = 456;
+    constexpr HWDisplayId displayId = 456;
 
     // --------------------------------------------------------------------
     // Preconditions
@@ -950,7 +1117,7 @@
     // Invocation
 
     // Call with an unexpected sequence id
-    mFlinger.onHotplugReceived(otherSequenceId, displayId, HWC2::Connection::Invalid);
+    mFlinger.onHotplugReceived(otherSequenceId, displayId, Connection::INVALID);
 
     // --------------------------------------------------------------------
     // Postconditions
@@ -964,7 +1131,7 @@
 
 TEST_F(DisplayTransactionTest, hotplugProcessesEnqueuedEventsIfCalledOnMainThread) {
     constexpr int currentSequenceId = 123;
-    constexpr hwc2_display_t displayId1 = 456;
+    constexpr HWDisplayId displayId1 = 456;
 
     // --------------------------------------------------------------------
     // Note:
@@ -998,7 +1165,7 @@
     // Simulate a disconnect on a display id that is not connected. This should
     // be enqueued by onHotplugReceived(), and dequeued by
     // processDisplayHotplugEventsLocked(), but then ignored as invalid.
-    mFlinger.onHotplugReceived(currentSequenceId, displayId1, HWC2::Connection::Disconnected);
+    mFlinger.onHotplugReceived(currentSequenceId, displayId1, Connection::DISCONNECTED);
 
     // --------------------------------------------------------------------
     // Postconditions
@@ -1141,8 +1308,8 @@
     // Preconditions
 
     // vsync is enabled and available
-    mScheduler->mutablePrimaryHWVsyncEnabled() = true;
-    mScheduler->mutableHWVsyncAvailable() = true;
+    mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = true;
+    mFlinger.scheduler()->mutableHWVsyncAvailable() = true;
 
     // A display exists
     auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
@@ -1166,8 +1333,8 @@
     // Postconditions
 
     // vsyncs should be off and not available.
-    EXPECT_FALSE(mScheduler->mutablePrimaryHWVsyncEnabled());
-    EXPECT_FALSE(mScheduler->mutableHWVsyncAvailable());
+    EXPECT_FALSE(mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled());
+    EXPECT_FALSE(mFlinger.scheduler()->mutableHWVsyncAvailable());
 
     // The display should have been removed from the display map.
     EXPECT_FALSE(hasDisplayDevice(existing.token()));
@@ -1184,13 +1351,6 @@
  */
 class GetBestColorModeTest : public DisplayTransactionTest {
 public:
-    static constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{777};
-
-    GetBestColorModeTest()
-          : DisplayTransactionTest(),
-            mInjector(FakeDisplayDeviceInjector(mFlinger, DEFAULT_DISPLAY_ID, false /* isVirtual */,
-                                                true /* isPrimary */)) {}
-
     void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
 
     void addHwcColorModesMapping(ui::ColorMode colorMode,
@@ -1203,21 +1363,12 @@
     void setInputRenderIntent(ui::RenderIntent renderIntent) { mInputRenderIntent = renderIntent; }
 
     void getBestColorMode() {
-        mInjector.setHwcColorModes(mHwcColorModes);
-        mInjector.setHasWideColorGamut(mHasWideColorGamut);
-        mInjector.setNativeWindow(mNativeWindow);
-
-        // Creating a DisplayDevice requires getting default dimensions from the
-        // native window.
-        EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
-                .WillRepeatedly(DoAll(SetArgPointee<1>(1080 /* arbitrary */), Return(0)));
-        EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
-                .WillRepeatedly(DoAll(SetArgPointee<1>(1920 /* arbitrary */), Return(0)));
-        EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
-        EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
-        EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
-        EXPECT_CALL(*mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1);
-        auto displayDevice = mInjector.inject();
+        auto displayDevice =
+                injectDefaultInternalDisplay([this](FakeDisplayDeviceInjector& injector) {
+                    injector.setHwcColorModes(mHwcColorModes);
+                    injector.setHasWideColorGamut(mHasWideColorGamut);
+                    injector.setNativeWindow(mNativeWindow);
+                });
 
         displayDevice->getCompositionDisplay()
                 ->getDisplayColorProfile()
@@ -1234,7 +1385,6 @@
     ui::RenderIntent mInputRenderIntent;
     bool mHasWideColorGamut = false;
     std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> mHwcColorModes;
-    FakeDisplayDeviceInjector mInjector;
 };
 
 TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeSRGB) {
@@ -1284,6 +1434,230 @@
 }
 
 /* ------------------------------------------------------------------------
+ * DisplayDevice::setProjection
+ */
+
+class DisplayDeviceSetProjectionTest : public DisplayTransactionTest {
+public:
+    static constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1080;  // arbitrary
+    static constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1920; // arbitrary
+
+    static constexpr int32_t TRANSFORM_FLAGS_ROT_0 = 0;
+    static constexpr int32_t TRANSFORM_FLAGS_ROT_90 = HAL_TRANSFORM_ROT_90;
+    static constexpr int32_t TRANSFORM_FLAGS_ROT_180 = HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_FLIP_V;
+    static constexpr int32_t TRANSFORM_FLAGS_ROT_270 =
+            HAL_TRANSFORM_FLIP_H | HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_ROT_90;
+
+    DisplayDeviceSetProjectionTest(ui::Size flingerDisplaySize, ui::Size hardwareDisplaySize,
+                                   ui::Rotation physicalOrientation)
+          : mFlingerDisplaySize(flingerDisplaySize),
+            mHardwareDisplaySize(hardwareDisplaySize),
+            mPhysicalOrientation(physicalOrientation),
+            mDisplayDevice(createDisplayDevice()) {}
+
+    sp<DisplayDevice> createDisplayDevice() {
+        return injectDefaultInternalDisplay([this](FakeDisplayDeviceInjector& injector) {
+            injector.setPhysicalOrientation(mPhysicalOrientation);
+        });
+    }
+
+    ui::Size SwapWH(const ui::Size size) const { return ui::Size(size.height, size.width); }
+
+    void setProjectionForRotation0() {
+        // A logical rotation of 0 uses the SurfaceFlinger display size
+        mDisplayDevice->setProjection(ui::ROTATION_0, Rect(mFlingerDisplaySize),
+                                      Rect(mFlingerDisplaySize));
+    }
+
+    void setProjectionForRotation90() {
+        // A logical rotation of 90 uses the SurfaceFlinger display size with
+        // the width/height swapped.
+        mDisplayDevice->setProjection(ui::ROTATION_90, Rect(SwapWH(mFlingerDisplaySize)),
+                                      Rect(SwapWH(mFlingerDisplaySize)));
+    }
+
+    void setProjectionForRotation180() {
+        // A logical rotation of 180 uses the SurfaceFlinger display size
+        mDisplayDevice->setProjection(ui::ROTATION_180, Rect(mFlingerDisplaySize),
+                                      Rect(mFlingerDisplaySize));
+    }
+
+    void setProjectionForRotation270() {
+        // A logical rotation of 270 uses the SurfaceFlinger display size with
+        // the width/height swapped.
+        mDisplayDevice->setProjection(ui::ROTATION_270, Rect(SwapWH(mFlingerDisplaySize)),
+                                      Rect(SwapWH(mFlingerDisplaySize)));
+    }
+
+    void expectStateForHardwareTransform0() {
+        const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+        EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_0, mHardwareDisplaySize.width,
+                                mHardwareDisplaySize.height),
+                  compositionState.transform);
+        EXPECT_EQ(TRANSFORM_FLAGS_ROT_0, compositionState.orientation);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.sourceClip);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.frame);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.viewport);
+        EXPECT_EQ(false, compositionState.needsFiltering);
+    }
+
+    void expectStateForHardwareTransform90() {
+        const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+        EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_90, mHardwareDisplaySize.width,
+                                mHardwareDisplaySize.height),
+                  compositionState.transform);
+        EXPECT_EQ(TRANSFORM_FLAGS_ROT_90, compositionState.orientation);
+        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.sourceClip);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
+        // For 90, the frame and viewport have the hardware display size width and height swapped
+        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame);
+        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.viewport);
+        EXPECT_EQ(false, compositionState.needsFiltering);
+    }
+
+    void expectStateForHardwareTransform180() {
+        const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+        EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_180, mHardwareDisplaySize.width,
+                                mHardwareDisplaySize.height),
+                  compositionState.transform);
+        EXPECT_EQ(TRANSFORM_FLAGS_ROT_180, compositionState.orientation);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.sourceClip);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.frame);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.viewport);
+        EXPECT_EQ(false, compositionState.needsFiltering);
+    }
+
+    void expectStateForHardwareTransform270() {
+        const auto& compositionState = mDisplayDevice->getCompositionDisplay()->getState();
+        EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_270, mHardwareDisplaySize.width,
+                                mHardwareDisplaySize.height),
+                  compositionState.transform);
+        EXPECT_EQ(TRANSFORM_FLAGS_ROT_270, compositionState.orientation);
+        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.sourceClip);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.destinationClip);
+        // For 270, the frame and viewport have the hardware display size width and height swapped
+        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.frame);
+        EXPECT_EQ(Rect(SwapWH(mHardwareDisplaySize)), compositionState.viewport);
+        EXPECT_EQ(false, compositionState.needsFiltering);
+    }
+
+    const ui::Size mFlingerDisplaySize;
+    const ui::Size mHardwareDisplaySize;
+    const ui::Rotation mPhysicalOrientation;
+    const sp<DisplayDevice> mDisplayDevice;
+};
+
+struct DisplayDeviceSetProjectionTest_Installed0 : public DisplayDeviceSetProjectionTest {
+    DisplayDeviceSetProjectionTest_Installed0()
+          : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                           ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                           ui::ROTATION_0) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith0OutputRotation) {
+    setProjectionForRotation0();
+    expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith90OutputRotation) {
+    setProjectionForRotation90();
+    expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith180OutputRotation) {
+    setProjectionForRotation180();
+    expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed0, checkWith270OutputRotation) {
+    setProjectionForRotation270();
+    expectStateForHardwareTransform270();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed90 : public DisplayDeviceSetProjectionTest {
+    DisplayDeviceSetProjectionTest_Installed90()
+          : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_WIDTH),
+                                           ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                           ui::ROTATION_90) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith0OutputRotation) {
+    setProjectionForRotation0();
+    expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith90OutputRotation) {
+    setProjectionForRotation90();
+    expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith180OutputRotation) {
+    setProjectionForRotation180();
+    expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed90, checkWith270OutputRotation) {
+    setProjectionForRotation270();
+    expectStateForHardwareTransform0();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed180 : public DisplayDeviceSetProjectionTest {
+    DisplayDeviceSetProjectionTest_Installed180()
+          : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                           ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                           ui::ROTATION_180) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith0OutputRotation) {
+    setProjectionForRotation0();
+    expectStateForHardwareTransform180();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith90OutputRotation) {
+    setProjectionForRotation90();
+    expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith180OutputRotation) {
+    setProjectionForRotation180();
+    expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed180, checkWith270OutputRotation) {
+    setProjectionForRotation270();
+    expectStateForHardwareTransform90();
+}
+
+struct DisplayDeviceSetProjectionTest_Installed270 : public DisplayDeviceSetProjectionTest {
+    DisplayDeviceSetProjectionTest_Installed270()
+          : DisplayDeviceSetProjectionTest(ui::Size(DEFAULT_DISPLAY_HEIGHT, DEFAULT_DISPLAY_WIDTH),
+                                           ui::Size(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                           ui::ROTATION_270) {}
+};
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith0OutputRotation) {
+    setProjectionForRotation0();
+    expectStateForHardwareTransform270();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith90OutputRotation) {
+    setProjectionForRotation90();
+    expectStateForHardwareTransform0();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith180OutputRotation) {
+    setProjectionForRotation180();
+    expectStateForHardwareTransform90();
+}
+
+TEST_F(DisplayDeviceSetProjectionTest_Installed270, checkWith270OutputRotation) {
+    setProjectionForRotation270();
+    expectStateForHardwareTransform180();
+}
+
+/* ------------------------------------------------------------------------
  * SurfaceFlinger::getDisplayNativePrimaries
  */
 
@@ -1361,7 +1735,8 @@
 
     ui::DisplayPrimaries primaries;
     populateDummyDisplayNativePrimaries(primaries);
-    EXPECT_EQ(BAD_VALUE, mFlinger.getDisplayNativePrimaries(notInternalDisplayToken, primaries));
+    EXPECT_EQ(NAME_NOT_FOUND,
+              mFlinger.getDisplayNativePrimaries(notInternalDisplayToken, primaries));
 
     // Check primaries argument wasn't modified in case of failure
     checkDummyDisplayNativePrimaries(primaries);
@@ -1397,6 +1772,9 @@
     // surfaces.
     injectFakeNativeWindowSurfaceFactory();
 
+    // A compositionengine::Display has already been created
+    auto compositionDisplay = Case::Display::injectCompositionDisplay(this);
+
     // --------------------------------------------------------------------
     // Call Expectations
 
@@ -1411,19 +1789,25 @@
     // Invocation
 
     DisplayDeviceState state;
-    state.displayId = static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
-                                                                : Case::Display::DISPLAY_ID::get();
+    if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+        const auto displayId = Case::Display::DISPLAY_ID::get();
+        ASSERT_TRUE(displayId);
+        const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
+        ASSERT_TRUE(hwcDisplayId);
+        state.physical = {*displayId, *connectionType, *hwcDisplayId};
+    }
+
     state.isSecure = static_cast<bool>(Case::Display::SECURE);
 
-    auto device =
-            mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::DISPLAY_ID::get(),
-                                                   state, displaySurface, producer);
+    auto device = mFlinger.setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
+                                                         displaySurface, producer);
 
     // --------------------------------------------------------------------
     // Postconditions
 
     ASSERT_TRUE(device != nullptr);
     EXPECT_EQ(Case::Display::DISPLAY_ID::get(), device->getId());
+    EXPECT_EQ(Case::Display::CONNECTION_TYPE::value, device->getConnectionType());
     EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), device->isVirtual());
     EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
     EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
@@ -1437,7 +1821,7 @@
     // Note: This is not Case::Display::HWC_ACTIVE_CONFIG_ID as the ids are
     // remapped, and the test only ever sets up one config. If there were an error
     // looking up the remapped index, device->getActiveConfig() would be -1 instead.
-    EXPECT_EQ(0, device->getActiveConfig());
+    EXPECT_EQ(0, device->getActiveConfig().value());
     EXPECT_EQ(Case::PerFrameMetadataSupport::PER_FRAME_METADATA_KEYS,
               device->getSupportedPerFrameMetadata());
 }
@@ -1455,14 +1839,7 @@
 }
 
 TEST_F(SetupNewDisplayDeviceInternalTest, createHwcVirtualDisplay) {
-    using Case = HwcVirtualDisplayCase;
-
-    // Insert display data so that the HWC thinks it created the virtual display.
-    const auto displayId = Case::Display::DISPLAY_ID::get();
-    ASSERT_TRUE(displayId);
-    mFlinger.mutableHwcDisplayData().try_emplace(*displayId);
-
-    setupNewDisplayDeviceInternalTest<Case>();
+    setupNewDisplayDeviceInternalTest<HwcVirtualDisplayCase>();
 }
 
 TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) {
@@ -1587,21 +1964,26 @@
     EXPECT_EQ(static_cast<bool>(Case::Display::SECURE), device->isSecure());
     EXPECT_EQ(static_cast<bool>(Case::Display::PRIMARY), device->isPrimary());
 
+    std::optional<DisplayDeviceState::Physical> expectedPhysical;
+    if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+        const auto displayId = Case::Display::DISPLAY_ID::get();
+        ASSERT_TRUE(displayId);
+        const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
+        ASSERT_TRUE(hwcDisplayId);
+        expectedPhysical = {*displayId, *connectionType, *hwcDisplayId};
+    }
+
     // The display should have been set up in the current display state
     ASSERT_TRUE(hasCurrentDisplayState(displayToken));
     const auto& current = getCurrentDisplayState(displayToken);
     EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), current.isVirtual());
-    EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
-                                                        : Case::Display::DISPLAY_ID::get(),
-              current.displayId);
+    EXPECT_EQ(expectedPhysical, current.physical);
 
     // The display should have been set up in the drawing display state
     ASSERT_TRUE(hasDrawingDisplayState(displayToken));
     const auto& draw = getDrawingDisplayState(displayToken);
     EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
-    EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL) ? std::nullopt
-                                                        : Case::Display::DISPLAY_ID::get(),
-              draw.displayId);
+    EXPECT_EQ(expectedPhysical, draw.physical);
 }
 
 template <typename Case>
@@ -1632,7 +2014,7 @@
     setupCommonPreconditions<Case>();
 
     // A hotplug connect event is enqueued for a display
-    Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Connected);
+    Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
 
     // --------------------------------------------------------------------
     // Call Expectations
@@ -1668,7 +2050,7 @@
     setupCommonPreconditions<Case>();
 
     // A hotplug connect event is enqueued for a display
-    Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Connected);
+    Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
 
     // --------------------------------------------------------------------
     // Invocation
@@ -1690,7 +2072,7 @@
     setupCommonPreconditions<Case>();
 
     // A hotplug disconnect event is enqueued for a display
-    Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Disconnected);
+    Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
 
     // The display is already completely set up.
     Case::Display::injectHwcDisplay(this);
@@ -1771,11 +2153,11 @@
     ignoresHotplugConnectCommon<SimpleExternalDisplayCase>();
 }
 
-TEST_F(HandleTransactionLockedTest, processHotplugDisconnectPrimaryDisplay) {
+TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectPrimaryDisplay) {
     processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>();
 }
 
-TEST_F(HandleTransactionLockedTest, processHotplugDisconnectExternalDisplay) {
+TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectExternalDisplay) {
     processesHotplugDisconnectCommon<SimpleExternalDisplayCase>();
 }
 
@@ -1788,9 +2170,9 @@
     setupCommonPreconditions<Case>();
 
     // A hotplug connect event is enqueued for a display
-    Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Connected);
+    Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
     // A hotplug disconnect event is also enqueued for the same display
-    Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Disconnected);
+    Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
 
     // --------------------------------------------------------------------
     // Call Expectations
@@ -1836,9 +2218,9 @@
     existing.inject();
 
     // A hotplug disconnect event is enqueued for a display
-    Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Disconnected);
+    Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
     // A hotplug connect event is also enqueued for the same display
-    Case::Display::injectPendingHotplugEvent(this, HWC2::Connection::Connected);
+    Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
 
     // --------------------------------------------------------------------
     // Call Expectations
@@ -2050,8 +2432,8 @@
 TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) {
     using Case = NonHwcVirtualDisplayCase;
 
-    constexpr int oldTransform = 0;
-    constexpr int newTransform = 2;
+    constexpr ui::Rotation oldTransform = ui::ROTATION_0;
+    constexpr ui::Rotation newTransform = ui::ROTATION_180;
 
     // --------------------------------------------------------------------
     // Preconditions
@@ -2424,7 +2806,7 @@
 
 TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfProjectionDidNotChange) {
     using Case = SimplePrimaryDisplayCase;
-    constexpr int initialOrientation = 180;
+    constexpr ui::Rotation initialOrientation = ui::ROTATION_180;
     const Rect initialFrame = {1, 2, 3, 4};
     const Rect initialViewport = {5, 6, 7, 8};
 
@@ -2468,8 +2850,8 @@
 
 TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfOrientationChanged) {
     using Case = SimplePrimaryDisplayCase;
-    constexpr int initialOrientation = 90;
-    constexpr int desiredOrientation = 180;
+    constexpr ui::Rotation initialOrientation = ui::ROTATION_90;
+    constexpr ui::Rotation desiredOrientation = ui::ROTATION_180;
 
     // --------------------------------------------------------------------
     // Preconditions
@@ -2715,7 +3097,7 @@
     // processing.
     EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
 
-    EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
+    EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_)).WillRepeatedly(Return(0));
 
     // --------------------------------------------------------------------
     // Invocation
@@ -2731,7 +3113,7 @@
     // The layer stack state should be set to zero
     EXPECT_EQ(0u, primaryDisplayState.layerStack);
     // The orientation state should be set to zero
-    EXPECT_EQ(0, primaryDisplayState.orientation);
+    EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation);
 
     // The frame state should be set to INVALID
     EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.frame);
@@ -2743,10 +3125,10 @@
     EXPECT_EQ(0u, primaryDisplayState.width);
     EXPECT_EQ(0u, primaryDisplayState.height);
 
-    // The display should be set to HWC_POWER_MODE_NORMAL
+    // The display should be set to PowerMode::ON
     ASSERT_TRUE(hasDisplayDevice(primaryDisplay.token()));
     auto displayDevice = primaryDisplay.mutableDisplayDevice();
-    EXPECT_EQ(HWC_POWER_MODE_NORMAL, displayDevice->getPowerMode());
+    EXPECT_EQ(PowerMode::ON, displayDevice->getPowerMode());
 
     // The display refresh period should be set in the frame tracker.
     FrameStats stats;
@@ -2778,8 +3160,8 @@
 
     static void setupComposerCallExpectations(DisplayTransactionTest* test) {
         EXPECT_CALL(*test->mComposer, getDisplayCapabilities(Display::HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>(
-                                        {Hwc2::DisplayCapability::DOZE})),
+                .WillOnce(DoAll(SetArgPointee<1>(
+                                        std::vector<DisplayCapability>({DisplayCapability::DOZE})),
                                 Return(Error::NONE)));
     }
 };
@@ -2795,7 +3177,7 @@
 
     static void setupComposerCallExpectations(DisplayTransactionTest* test) {
         EXPECT_CALL(*test->mComposer, getDisplayCapabilities(Display::HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::DisplayCapability>({})),
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<DisplayCapability>({})),
                                 Return(Error::NONE)));
     }
 };
@@ -2869,7 +3251,7 @@
 // selected subset which provides complete test coverage of the implementation.
 // --------------------------------------------------------------------
 
-template <int initialPowerMode, int targetPowerMode>
+template <PowerMode initialPowerMode, PowerMode targetPowerMode>
 struct TransitionVariantCommon {
     static constexpr auto INITIAL_POWER_MODE = initialPowerMode;
     static constexpr auto TARGET_POWER_MODE = targetPowerMode;
@@ -2877,8 +3259,7 @@
     static void verifyPostconditions(DisplayTransactionTest*) {}
 };
 
-struct TransitionOffToOnVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_OFF, HWC_POWER_MODE_NORMAL> {
+struct TransitionOffToOnVariant : public TransitionVariantCommon<PowerMode::OFF, PowerMode::ON> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
@@ -2894,7 +3275,7 @@
 };
 
 struct TransitionOffToDozeSuspendVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_OFF, HWC_POWER_MODE_DOZE_SUSPEND> {
+      : public TransitionVariantCommon<PowerMode::OFF, PowerMode::DOZE_SUSPEND> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
@@ -2908,8 +3289,7 @@
     }
 };
 
-struct TransitionOnToOffVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_OFF> {
+struct TransitionOnToOffVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::OFF> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
@@ -2923,7 +3303,7 @@
 };
 
 struct TransitionDozeSuspendToOffVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_DOZE_SUSPEND, HWC_POWER_MODE_OFF> {
+      : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::OFF> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
@@ -2935,8 +3315,7 @@
     }
 };
 
-struct TransitionOnToDozeVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_DOZE> {
+struct TransitionOnToDozeVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
@@ -2945,7 +3324,7 @@
 };
 
 struct TransitionDozeSuspendToDozeVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_DOZE_SUSPEND, HWC_POWER_MODE_DOZE> {
+      : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::DOZE> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
@@ -2954,8 +3333,7 @@
     }
 };
 
-struct TransitionDozeToOnVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_DOZE, HWC_POWER_MODE_NORMAL> {
+struct TransitionDozeToOnVariant : public TransitionVariantCommon<PowerMode::DOZE, PowerMode::ON> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
@@ -2964,7 +3342,7 @@
 };
 
 struct TransitionDozeSuspendToOnVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_DOZE_SUSPEND, HWC_POWER_MODE_NORMAL> {
+      : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::ON> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
@@ -2974,7 +3352,7 @@
 };
 
 struct TransitionOnToDozeSuspendVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_DOZE_SUSPEND> {
+      : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE_SUSPEND> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
@@ -2984,7 +3362,7 @@
 };
 
 struct TransitionOnToUnknownVariant
-      : public TransitionVariantCommon<HWC_POWER_MODE_NORMAL, HWC_POWER_MODE_LEET> {
+      : public TransitionVariantCommon<PowerMode::ON, static_cast<PowerMode>(POWER_MODE_LEET)> {
     template <typename Case>
     static void setupCallExpectations(DisplayTransactionTest* test) {
         Case::EventThread::setupEventAndEventControlThreadNoCallExpectations(test);
@@ -3009,7 +3387,7 @@
     using DispSync = DispSyncVariant;
     using Transition = TransitionVariant;
 
-    static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, int mode) {
+    static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, PowerMode mode) {
         Display::injectHwcDisplayWithNoDefaultCapabilities(test);
         auto display = Display::makeFakeExistingDisplayInjector(test);
         display.inject();
@@ -3018,20 +3396,21 @@
     }
 
     static void setInitialPrimaryHWVsyncEnabled(DisplayTransactionTest* test, bool enabled) {
-        test->mScheduler->mutablePrimaryHWVsyncEnabled() = enabled;
+        test->mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = enabled;
     }
 
     static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
         EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
     }
 
-    static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test, int mode) {
+    static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test,
+                                                        PowerMode mode) {
         EXPECT_CALL(*test->mSurfaceInterceptor, isEnabled()).WillOnce(Return(true));
-        EXPECT_CALL(*test->mSurfaceInterceptor, savePowerModeUpdate(_, mode)).Times(1);
+        EXPECT_CALL(*test->mSurfaceInterceptor, savePowerModeUpdate(_, static_cast<int32_t>(mode)))
+                .Times(1);
     }
 
-    static void setupComposerCallExpectations(DisplayTransactionTest* test,
-                                              IComposerClient::PowerMode mode) {
+    static void setupComposerCallExpectations(DisplayTransactionTest* test, PowerMode mode) {
         // Any calls to get the active config will return a default value.
         EXPECT_CALL(*test->mComposer, getActiveConfig(Display::HWC_DISPLAY_ID, _))
                 .WillRepeatedly(DoAll(SetArgPointee<1>(Display::HWC_ACTIVE_CONFIG_ID),
@@ -3073,14 +3452,14 @@
     void transitionDisplayCommon();
 };
 
-template <int PowerMode>
+template <PowerMode PowerMode>
 struct PowerModeInitialVSyncEnabled : public std::false_type {};
 
 template <>
-struct PowerModeInitialVSyncEnabled<HWC_POWER_MODE_NORMAL> : public std::true_type {};
+struct PowerModeInitialVSyncEnabled<PowerMode::ON> : public std::true_type {};
 
 template <>
-struct PowerModeInitialVSyncEnabled<HWC_POWER_MODE_DOZE> : public std::true_type {};
+struct PowerModeInitialVSyncEnabled<PowerMode::DOZE> : public std::true_type {};
 
 template <typename Case>
 void SetPowerModeInternalTest::transitionDisplayCommon() {
@@ -3123,18 +3502,18 @@
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.inject();
 
-    // The display is already set to HWC_POWER_MODE_NORMAL
-    display.mutableDisplayDevice()->setPowerMode(HWC_POWER_MODE_NORMAL);
+    // The display is already set to PowerMode::ON
+    display.mutableDisplayDevice()->setPowerMode(PowerMode::ON);
 
     // --------------------------------------------------------------------
     // Invocation
 
-    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), HWC_POWER_MODE_NORMAL);
+    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::ON);
 
     // --------------------------------------------------------------------
     // Postconditions
 
-    EXPECT_EQ(HWC_POWER_MODE_NORMAL, display.mutableDisplayDevice()->getPowerMode());
+    EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
 }
 
 TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay) {
@@ -3153,18 +3532,18 @@
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.inject();
 
-    // The display is set to HWC_POWER_MODE_NORMAL
-    getDisplayDevice(display.token())->setPowerMode(HWC_POWER_MODE_NORMAL);
+    // The display is set to PowerMode::ON
+    getDisplayDevice(display.token())->setPowerMode(PowerMode::ON);
 
     // --------------------------------------------------------------------
     // Invocation
 
-    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), HWC_POWER_MODE_OFF);
+    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::OFF);
 
     // --------------------------------------------------------------------
     // Postconditions
 
-    EXPECT_EQ(HWC_POWER_MODE_NORMAL, display.mutableDisplayDevice()->getPowerMode());
+    EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
 }
 
 TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnPrimaryDisplay) {
@@ -3249,3 +3628,6 @@
 
 } // namespace
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index dbd9b84..b90b566 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -19,13 +19,12 @@
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-
 #include <log/log.h>
-
 #include <utils/Errors.h>
 
 #include "AsyncCallRecorder.h"
 #include "Scheduler/EventThread.h"
+#include "Scheduler/HwcStrongTypes.h"
 
 using namespace std::chrono_literals;
 using namespace std::placeholders;
@@ -34,6 +33,7 @@
 using testing::Invoke;
 
 namespace android {
+
 namespace {
 
 constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = 111;
@@ -42,10 +42,13 @@
 
 class MockVSyncSource : public VSyncSource {
 public:
+    const char* getName() const override { return "test"; }
+
     MOCK_METHOD1(setVSyncEnabled, void(bool));
     MOCK_METHOD1(setCallback, void(VSyncSource::Callback*));
     MOCK_METHOD1(setPhaseOffset, void(nsecs_t));
     MOCK_METHOD1(pauseVsyncCallback, void(bool));
+    MOCK_CONST_METHOD1(dump, void(std::string&));
 };
 
 } // namespace
@@ -54,8 +57,7 @@
 protected:
     class MockEventThreadConnection : public EventThreadConnection {
     public:
-        MockEventThreadConnection(android::impl::EventThread* eventThread,
-                                  ResyncCallback&& resyncCallback,
+        MockEventThreadConnection(impl::EventThread* eventThread, ResyncCallback&& resyncCallback,
                                   ISurfaceComposer::ConfigChanged configChanged)
               : EventThreadConnection(eventThread, std::move(resyncCallback), configChanged) {}
         MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
@@ -67,7 +69,7 @@
     EventThreadTest();
     ~EventThreadTest() override;
 
-    void createThread();
+    void createThread(std::unique_ptr<VSyncSource>);
     sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder,
                                                    ISurfaceComposer::ConfigChanged configChanged);
 
@@ -82,7 +84,8 @@
     void expectHotplugEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
                                                 bool expectedConnected);
     void expectConfigChangedEventReceivedByConnection(PhysicalDisplayId expectedDisplayId,
-                                                      int32_t expectedConfigId);
+                                                      int32_t expectedConfigId,
+                                                      nsecs_t expectedVsyncPeriod);
 
     AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
     AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
@@ -91,9 +94,9 @@
     AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
     ConnectionEventRecorder mConnectionEventCallRecorder{0};
 
-    MockVSyncSource mVSyncSource;
+    MockVSyncSource* mVSyncSource;
     VSyncSource::Callback* mCallback = nullptr;
-    std::unique_ptr<android::impl::EventThread> mThread;
+    std::unique_ptr<impl::EventThread> mThread;
     sp<MockEventThreadConnection> mConnection;
 };
 
@@ -102,16 +105,19 @@
             ::testing::UnitTest::GetInstance()->current_test_info();
     ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
 
-    EXPECT_CALL(mVSyncSource, setVSyncEnabled(_))
+    auto vsyncSource = std::make_unique<MockVSyncSource>();
+    mVSyncSource = vsyncSource.get();
+
+    EXPECT_CALL(*mVSyncSource, setVSyncEnabled(_))
             .WillRepeatedly(Invoke(mVSyncSetEnabledCallRecorder.getInvocable()));
 
-    EXPECT_CALL(mVSyncSource, setCallback(_))
+    EXPECT_CALL(*mVSyncSource, setCallback(_))
             .WillRepeatedly(Invoke(mVSyncSetCallbackCallRecorder.getInvocable()));
 
-    EXPECT_CALL(mVSyncSource, setPhaseOffset(_))
+    EXPECT_CALL(*mVSyncSource, setPhaseOffset(_))
             .WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable()));
 
-    createThread();
+    createThread(std::move(vsyncSource));
     mConnection = createConnection(mConnectionEventCallRecorder,
                                    ISurfaceComposer::eConfigChangedDispatch);
 
@@ -129,11 +135,9 @@
     EXPECT_TRUE(!mVSyncSetCallbackCallRecorder.waitForUnexpectedCall().has_value());
 }
 
-void EventThreadTest::createThread() {
-    mThread =
-            std::make_unique<android::impl::EventThread>(&mVSyncSource,
-                                                         mInterceptVSyncCallRecorder.getInvocable(),
-                                                         "unit-test-event-thread");
+void EventThreadTest::createThread(std::unique_ptr<VSyncSource> source) {
+    mThread = std::make_unique<impl::EventThread>(std::move(source),
+                                                  mInterceptVSyncCallRecorder.getInvocable());
 
     // EventThread should register itself as VSyncSource callback.
     mCallback = expectVSyncSetCallbackCallReceived();
@@ -205,13 +209,15 @@
 }
 
 void EventThreadTest::expectConfigChangedEventReceivedByConnection(
-        PhysicalDisplayId expectedDisplayId, int32_t expectedConfigId) {
+        PhysicalDisplayId expectedDisplayId, int32_t expectedConfigId,
+        nsecs_t expectedVsyncPeriod) {
     auto args = mConnectionEventCallRecorder.waitForCall();
     ASSERT_TRUE(args.has_value());
     const auto& event = std::get<0>(args.value());
     EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, event.header.type);
     EXPECT_EQ(expectedDisplayId, event.header.displayId);
     EXPECT_EQ(expectedConfigId, event.config.configId);
+    EXPECT_EQ(expectedVsyncPeriod, event.config.vsyncPeriod);
 }
 
 namespace {
@@ -252,14 +258,14 @@
 
     // Use the received callback to signal a first vsync event.
     // The interceptor should receive the event, as well as the connection.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection(123, 1u);
 
     // Use the received callback to signal a second vsync event.
     // The interceptor should receive the event, but the the connection should
     // not as it was only interested in the first.
-    mCallback->onVSyncEvent(456);
+    mCallback->onVSyncEvent(456, 123);
     expectInterceptCallReceived(456);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
 
@@ -293,7 +299,7 @@
     // Send a vsync event. EventThread should then make a call to the
     // interceptor, and the second connection. The first connection should not
     // get the event.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     EXPECT_FALSE(firstConnectionEventRecorder.waitForUnexpectedCall().has_value());
     expectVsyncEventReceivedByConnection("secondConnection", secondConnectionEventRecorder, 123,
@@ -308,17 +314,17 @@
 
     // Send a vsync event. EventThread should then make a call to the
     // interceptor, and the connection.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection(123, 1u);
 
     // A second event should go to the same places.
-    mCallback->onVSyncEvent(456);
+    mCallback->onVSyncEvent(456, 123);
     expectInterceptCallReceived(456);
     expectVsyncEventReceivedByConnection(456, 2u);
 
     // A third event should go to the same places.
-    mCallback->onVSyncEvent(789);
+    mCallback->onVSyncEvent(789, 777);
     expectInterceptCallReceived(789);
     expectVsyncEventReceivedByConnection(789, 3u);
 }
@@ -330,22 +336,22 @@
     expectVSyncSetEnabledCallReceived(true);
 
     // The first event will be seen by the interceptor, and not the connection.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
 
     // The second event will be seen by the interceptor and the connection.
-    mCallback->onVSyncEvent(456);
+    mCallback->onVSyncEvent(456, 123);
     expectInterceptCallReceived(456);
     expectVsyncEventReceivedByConnection(456, 2u);
 
     // The third event will be seen by the interceptor, and not the connection.
-    mCallback->onVSyncEvent(789);
+    mCallback->onVSyncEvent(789, 777);
     expectInterceptCallReceived(789);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
 
     // The fourth event will be seen by the interceptor and the connection.
-    mCallback->onVSyncEvent(101112);
+    mCallback->onVSyncEvent(101112, 7847);
     expectInterceptCallReceived(101112);
     expectVsyncEventReceivedByConnection(101112, 4u);
 }
@@ -360,7 +366,7 @@
     mConnection = nullptr;
 
     // The first event will be seen by the interceptor, and not the connection.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
 
@@ -380,13 +386,13 @@
 
     // The first event will be seen by the interceptor, and by the connection,
     // which then returns an error.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
 
     // A subsequent event will be seen by the interceptor and not by the
     // connection.
-    mCallback->onVSyncEvent(456);
+    mCallback->onVSyncEvent(456, 123);
     expectInterceptCallReceived(456);
     EXPECT_FALSE(errorConnectionEventRecorder.waitForUnexpectedCall().has_value());
 
@@ -394,6 +400,34 @@
     expectVSyncSetEnabledCallReceived(false);
 }
 
+TEST_F(EventThreadTest, tracksEventConnections) {
+    EXPECT_EQ(1, mThread->getEventThreadConnectionCount());
+    ConnectionEventRecorder errorConnectionEventRecorder{NO_MEMORY};
+    sp<MockEventThreadConnection> errorConnection =
+            createConnection(errorConnectionEventRecorder,
+                             ISurfaceComposer::eConfigChangedSuppress);
+    mThread->setVsyncRate(1, errorConnection);
+    EXPECT_EQ(2, mThread->getEventThreadConnectionCount());
+    ConnectionEventRecorder secondConnectionEventRecorder{0};
+    sp<MockEventThreadConnection> secondConnection =
+            createConnection(secondConnectionEventRecorder,
+                             ISurfaceComposer::eConfigChangedSuppress);
+    mThread->setVsyncRate(1, secondConnection);
+    EXPECT_EQ(3, mThread->getEventThreadConnectionCount());
+
+    // EventThread should enable vsync callbacks.
+    expectVSyncSetEnabledCallReceived(true);
+
+    // The first event will be seen by the interceptor, and by the connection,
+    // which then returns an error.
+    mCallback->onVSyncEvent(123, 456);
+    expectInterceptCallReceived(123);
+    expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
+    expectVsyncEventReceivedByConnection("successConnection", secondConnectionEventRecorder, 123,
+                                         1u);
+    EXPECT_EQ(2, mThread->getEventThreadConnectionCount());
+}
+
 TEST_F(EventThreadTest, eventsDroppedIfNonfatalEventDeliveryError) {
     ConnectionEventRecorder errorConnectionEventRecorder{WOULD_BLOCK};
     sp<MockEventThreadConnection> errorConnection =
@@ -406,13 +440,13 @@
 
     // The first event will be seen by the interceptor, and by the connection,
     // which then returns an non-fatal error.
-    mCallback->onVSyncEvent(123);
+    mCallback->onVSyncEvent(123, 456);
     expectInterceptCallReceived(123);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 123, 1u);
 
     // A subsequent event will be seen by the interceptor, and by the connection,
     // which still then returns an non-fatal error.
-    mCallback->onVSyncEvent(456);
+    mCallback->onVSyncEvent(456, 123);
     expectInterceptCallReceived(456);
     expectVsyncEventReceivedByConnection("errorConnection", errorConnectionEventRecorder, 456, 2u);
 
@@ -446,18 +480,18 @@
 }
 
 TEST_F(EventThreadTest, postConfigChangedPrimary) {
-    mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 7);
-    expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7);
+    mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(7), 16666666);
+    expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7, 16666666);
 }
 
 TEST_F(EventThreadTest, postConfigChangedExternal) {
-    mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, 5);
-    expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5);
+    mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, HwcConfigIndexType(5), 16666666);
+    expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5, 16666666);
 }
 
 TEST_F(EventThreadTest, postConfigChangedPrimary64bit) {
-    mThread->onConfigChanged(DISPLAY_ID_64BIT, 7);
-    expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7);
+    mThread->onConfigChanged(DISPLAY_ID_64BIT, HwcConfigIndexType(7), 16666666);
+    expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7, 16666666);
 }
 
 TEST_F(EventThreadTest, suppressConfigChanged) {
@@ -466,8 +500,8 @@
             createConnection(suppressConnectionEventRecorder,
                              ISurfaceComposer::eConfigChangedSuppress);
 
-    mThread->onConfigChanged(INTERNAL_DISPLAY_ID, 9);
-    expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9);
+    mThread->onConfigChanged(INTERNAL_DISPLAY_ID, HwcConfigIndexType(9), 16666666);
+    expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9, 16666666);
 
     auto args = suppressConnectionEventRecorder.waitForCall();
     ASSERT_FALSE(args.has_value());
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
index 1d75011..b50ddf5 100644
--- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -20,42 +20,21 @@
 
 #include "Scheduler/PhaseOffsets.h"
 
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
 
-using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+struct FakePhaseOffsets : PhaseConfiguration {
+    static constexpr nsecs_t FAKE_PHASE_OFFSET_NS = 0;
 
-class FakePhaseOffsets : public android::scheduler::PhaseOffsets {
-    nsecs_t FAKE_PHASE_OFFSET_NS = 0;
+    Offsets getOffsetsForRefreshRate(float) const override { return getCurrentOffsets(); }
 
-public:
-    FakePhaseOffsets() = default;
-    ~FakePhaseOffsets() = default;
-
-    nsecs_t getCurrentAppOffset() override { return FAKE_PHASE_OFFSET_NS; }
-    nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; }
-
-    PhaseOffsets::Offsets getOffsetsForRefreshRate(
-            RefreshRateType /*refreshRateType*/) const override {
-        return getCurrentOffsets();
+    Offsets getCurrentOffsets() const override {
+        return {{FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+                {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+                {FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
     }
 
-    // Returns early, early GL, and late offsets for Apps and SF.
-    PhaseOffsets::Offsets getCurrentOffsets() const override {
-        return Offsets{{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
-                       {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
-                       {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
-    }
-
-    // This function should be called when the device is switching between different
-    // refresh rates, to properly update the offsets.
-    void setRefreshRateType(RefreshRateType /*refreshRateType*/) override {}
-
-    nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; }
-
-    // Returns current offsets in human friendly format.
-    void dump(std::string& /*result*/) const override {}
+    void setRefreshRateFps(float) override {}
+    void dump(std::string&) const override {}
 };
 
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
new file mode 100644
index 0000000..a119e27
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
@@ -0,0 +1,384 @@
+/*
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <FrameTracer/FrameTracer.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <perfetto/trace/trace.pb.h>
+
+#include "libsurfaceflinger_unittest_main.h"
+
+using namespace google::protobuf;
+
+namespace android {
+namespace {
+
+class FrameTracerTest : public testing::Test {
+public:
+    FrameTracerTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+        // Need to initialize tracing in process for testing, and only once per test suite.
+        static bool wasInitialized = false;
+        if (!wasInitialized) {
+            perfetto::TracingInitArgs args;
+            args.backends = perfetto::kInProcessBackend;
+            perfetto::Tracing::Initialize(args);
+            wasInitialized = true;
+        }
+    }
+
+    ~FrameTracerTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+
+    void SetUp() override {
+        mFrameTracer = std::make_unique<FrameTracer>();
+        mFrameTracer->registerDataSource();
+    }
+
+    void TearDown() override { mFrameTracer.reset(); }
+
+    // Each tracing session can be used for a single block of Start -> Stop.
+    static std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest() {
+        perfetto::TraceConfig cfg;
+        cfg.set_duration_ms(500);
+        cfg.add_buffers()->set_size_kb(1024);
+        auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+        ds_cfg->set_name(FrameTracer::kFrameTracerDataSource);
+
+        auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
+        tracingSession->Setup(cfg);
+        return tracingSession;
+    }
+
+    std::vector<perfetto::protos::TracePacket> readGraphicsFramePacketsBlocking(
+            perfetto::TracingSession* tracingSession) {
+        std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+        perfetto::protos::Trace trace;
+        EXPECT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+
+        std::vector<perfetto::protos::TracePacket> packets;
+        for (const auto& packet : trace.packet()) {
+            if (!packet.has_graphics_frame_event()) {
+                continue;
+            }
+            packets.emplace_back(packet);
+        }
+        return packets;
+    }
+
+    std::unique_ptr<FrameTracer> mFrameTracer;
+    FenceToFenceTimeMap fenceFactory;
+};
+
+TEST_F(FrameTracerTest, traceNewLayerStartsTrackingLayerWhenTracing) {
+    EXPECT_EQ(mFrameTracer->miniDump(),
+              "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+    const std::string layerName = "co.layername#0";
+    const int32_t layerId = 5;
+    mFrameTracer->traceNewLayer(layerId, layerName);
+
+    EXPECT_EQ(mFrameTracer->miniDump(),
+              "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+    auto tracingSession = getTracingSessionForTest();
+    tracingSession->StartBlocking();
+    EXPECT_EQ(mFrameTracer->miniDump(),
+              "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+    mFrameTracer->traceNewLayer(layerId, layerName);
+    EXPECT_EQ(mFrameTracer->miniDump(),
+              "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+    tracingSession->StopBlocking();
+}
+
+TEST_F(FrameTracerTest, onDestroyRemovesTheTrackedLayer) {
+    EXPECT_EQ(mFrameTracer->miniDump(),
+              "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+    const std::string layerName = "co.layername#0";
+    const int32_t layerId = 5;
+    const int32_t secondlayerId = 6;
+
+    auto tracingSession = getTracingSessionForTest();
+    tracingSession->StartBlocking();
+    mFrameTracer->traceNewLayer(layerId, layerName);
+    mFrameTracer->traceNewLayer(secondlayerId, layerName);
+    EXPECT_EQ(mFrameTracer->miniDump(),
+              "FrameTracer miniDump:\nNumber of layers currently being traced is 2\n");
+    tracingSession->StopBlocking();
+
+    mFrameTracer->onDestroy(layerId);
+    EXPECT_EQ(mFrameTracer->miniDump(),
+              "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+    mFrameTracer->onDestroy(layerId);
+    EXPECT_EQ(mFrameTracer->miniDump(),
+              "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+    mFrameTracer->onDestroy(secondlayerId);
+    EXPECT_EQ(mFrameTracer->miniDump(),
+              "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+}
+
+TEST_F(FrameTracerTest, canTraceAfterAddingLayer) {
+    const std::string layerName = "co.layername#0";
+    const int32_t layerId = 1;
+    const uint32_t bufferID = 2;
+    const uint64_t frameNumber = 3;
+    const nsecs_t timestamp = 4;
+    const nsecs_t duration = 5;
+    const auto type = FrameTracer::FrameEvent::POST;
+
+    {
+        auto tracingSession = getTracingSessionForTest();
+
+        tracingSession->StartBlocking();
+        mFrameTracer->traceTimestamp(layerId, bufferID, frameNumber, timestamp, type, duration);
+        // Create second trace packet to finalize the previous one.
+        mFrameTracer->traceTimestamp(layerId, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+        tracingSession->StopBlocking();
+
+        auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+        EXPECT_EQ(packets.size(), 0);
+    }
+
+    {
+        auto tracingSession = getTracingSessionForTest();
+
+        tracingSession->StartBlocking();
+        mFrameTracer->traceNewLayer(layerId, layerName);
+        mFrameTracer->traceTimestamp(layerId, bufferID, frameNumber, timestamp, type, duration);
+        // Create second trace packet to finalize the previous one.
+        mFrameTracer->traceTimestamp(layerId, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+        tracingSession->StopBlocking();
+
+        auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+        EXPECT_EQ(packets.size(), 1);
+
+        const auto& packet = packets[0];
+        ASSERT_TRUE(packet.has_timestamp());
+        EXPECT_EQ(packet.timestamp(), timestamp);
+        ASSERT_TRUE(packet.has_graphics_frame_event());
+        const auto& frame_event = packet.graphics_frame_event();
+        ASSERT_TRUE(frame_event.has_buffer_event());
+        const auto& buffer_event = frame_event.buffer_event();
+        ASSERT_TRUE(buffer_event.has_buffer_id());
+        EXPECT_EQ(buffer_event.buffer_id(), bufferID);
+        ASSERT_TRUE(buffer_event.has_frame_number());
+        EXPECT_EQ(buffer_event.frame_number(), frameNumber);
+        ASSERT_TRUE(buffer_event.has_type());
+        EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
+        ASSERT_TRUE(buffer_event.has_duration_ns());
+        EXPECT_EQ(buffer_event.duration_ns(), duration);
+    }
+}
+
+TEST_F(FrameTracerTest, traceFenceTriggersOnNextTraceAfterFenceFired) {
+    const std::string layerName = "co.layername#0";
+    const int32_t layerId = 5;
+    const uint32_t bufferID = 4;
+    const uint64_t frameNumber = 3;
+    const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+
+    {
+        auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+        fenceFactory.signalAllForTest(Fence::NO_FENCE, Fence::SIGNAL_TIME_PENDING);
+        auto tracingSession = getTracingSessionForTest();
+        tracingSession->StartBlocking();
+        // Trace.
+        mFrameTracer->traceNewLayer(layerId, layerName);
+        mFrameTracer->traceFence(layerId, bufferID, frameNumber, fenceTime, type);
+        // Create extra trace packet to (hopefully not) trigger and finalize the fence packet.
+        mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+        tracingSession->StopBlocking();
+
+        auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+        EXPECT_EQ(packets.size(), 0);
+    }
+
+    {
+        auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+        auto tracingSession = getTracingSessionForTest();
+        tracingSession->StartBlocking();
+        mFrameTracer->traceNewLayer(layerId, layerName);
+        mFrameTracer->traceFence(layerId, bufferID, frameNumber, fenceTime, type);
+        const nsecs_t timestamp = systemTime();
+        fenceFactory.signalAllForTest(Fence::NO_FENCE, timestamp);
+        // Create extra trace packet to trigger and finalize fence trace packets.
+        mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+        tracingSession->StopBlocking();
+
+        auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+        EXPECT_EQ(packets.size(), 2); // Two packets because of the extra trace made above.
+
+        const auto& packet = packets[1];
+        ASSERT_TRUE(packet.has_timestamp());
+        EXPECT_EQ(packet.timestamp(), timestamp);
+        ASSERT_TRUE(packet.has_graphics_frame_event());
+        const auto& frame_event = packet.graphics_frame_event();
+        ASSERT_TRUE(frame_event.has_buffer_event());
+        const auto& buffer_event = frame_event.buffer_event();
+        ASSERT_TRUE(buffer_event.has_buffer_id());
+        EXPECT_EQ(buffer_event.buffer_id(), bufferID);
+        ASSERT_TRUE(buffer_event.has_frame_number());
+        EXPECT_EQ(buffer_event.frame_number(), frameNumber);
+        ASSERT_TRUE(buffer_event.has_type());
+        EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
+        EXPECT_FALSE(buffer_event.has_duration_ns());
+    }
+}
+
+TEST_F(FrameTracerTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDuration) {
+    const std::string layerName = "co.layername#0";
+    const int32_t layerId = 5;
+    const uint32_t bufferID = 4;
+    const uint64_t frameNumber = 3;
+    const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+
+    auto tracingSession = getTracingSessionForTest();
+
+    tracingSession->StartBlocking();
+    mFrameTracer->traceNewLayer(layerId, layerName);
+
+    // traceFence called after fence signalled.
+    const nsecs_t signalTime1 = systemTime();
+    const nsecs_t startTime1 = signalTime1 + 100000;
+    auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
+    mFrameTracer->traceFence(layerId, bufferID, frameNumber, fence1, type, startTime1);
+
+    // traceFence called before fence signalled.
+    const nsecs_t signalTime2 = systemTime();
+    const nsecs_t startTime2 = signalTime2 + 100000;
+    auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    mFrameTracer->traceFence(layerId, bufferID, frameNumber, fence2, type, startTime2);
+    fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
+
+    // Create extra trace packet to trigger and finalize fence trace packets.
+    mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+    tracingSession->StopBlocking();
+
+    auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+    EXPECT_EQ(packets.size(), 2);
+
+    const auto& packet1 = packets[0];
+    ASSERT_TRUE(packet1.has_timestamp());
+    EXPECT_EQ(packet1.timestamp(), signalTime1);
+    ASSERT_TRUE(packet1.has_graphics_frame_event());
+    ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
+    ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
+
+    const auto& packet2 = packets[1];
+    ASSERT_TRUE(packet2.has_timestamp());
+    EXPECT_EQ(packet2.timestamp(), signalTime2);
+    ASSERT_TRUE(packet2.has_graphics_frame_event());
+    ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
+    ASSERT_FALSE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
+}
+
+TEST_F(FrameTracerTest, traceFenceOlderThanDeadline_ShouldBeIgnored) {
+    const std::string layerName = "co.layername#0";
+    const int32_t layerId = 5;
+    const uint32_t bufferID = 4;
+    const uint64_t frameNumber = 3;
+    const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+    const nsecs_t signalTime = systemTime() - FrameTracer::kFenceSignallingDeadline;
+
+    auto tracingSession = getTracingSessionForTest();
+    auto fence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+
+    tracingSession->StartBlocking();
+    mFrameTracer->traceNewLayer(layerId, layerName);
+    mFrameTracer->traceFence(layerId, bufferID, frameNumber, fence, type);
+    fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime);
+    // Create extra trace packet to trigger and finalize any previous fence packets.
+    mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+    tracingSession->StopBlocking();
+
+    auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+    EXPECT_EQ(packets.size(), 0);
+}
+
+TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) {
+    const std::string layerName = "co.layername#0";
+    const int32_t layerId = 5;
+    const uint32_t bufferID = 4;
+    const uint64_t frameNumber = 3;
+    const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+    const nsecs_t duration = 1234;
+
+    auto tracingSession = getTracingSessionForTest();
+
+    tracingSession->StartBlocking();
+    mFrameTracer->traceNewLayer(layerId, layerName);
+
+    // traceFence called after fence signalled.
+    const nsecs_t signalTime1 = systemTime();
+    const nsecs_t startTime1 = signalTime1 - duration;
+    auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
+    mFrameTracer->traceFence(layerId, bufferID, frameNumber, fence1, type, startTime1);
+
+    // traceFence called before fence signalled.
+    const nsecs_t signalTime2 = systemTime();
+    const nsecs_t startTime2 = signalTime2 - duration;
+    auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+    mFrameTracer->traceFence(layerId, bufferID, frameNumber, fence2, type, startTime2);
+    fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
+
+    // Create extra trace packet to trigger and finalize fence trace packets.
+    mFrameTracer->traceTimestamp(layerId, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+    tracingSession->StopBlocking();
+
+    auto packets = readGraphicsFramePacketsBlocking(tracingSession.get());
+    EXPECT_EQ(packets.size(), 2);
+
+    const auto& packet1 = packets[0];
+    ASSERT_TRUE(packet1.has_timestamp());
+    EXPECT_EQ(packet1.timestamp(), startTime1);
+    ASSERT_TRUE(packet1.has_graphics_frame_event());
+    ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
+    ASSERT_TRUE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
+    const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event();
+    EXPECT_EQ(buffer_event1.duration_ns(), duration);
+
+    const auto& packet2 = packets[1];
+    ASSERT_TRUE(packet2.has_timestamp());
+    EXPECT_EQ(packet2.timestamp(), startTime2);
+    ASSERT_TRUE(packet2.has_graphics_frame_event());
+    ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
+    ASSERT_TRUE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
+    const auto& buffer_event2 = packet2.graphics_frame_event().buffer_event();
+    EXPECT_EQ(buffer_event2.duration_ns(), duration);
+}
+
+} // namespace
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
new file mode 100644
index 0000000..91b304c
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -0,0 +1,175 @@
+/*
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gui/LayerMetadata.h>
+#include <log/log.h>
+
+#include "DisplayHardware/HWComposer.h"
+#include "mock/DisplayHardware/MockComposer.h"
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+
+namespace android {
+namespace {
+
+namespace hal = android::hardware::graphics::composer::hal;
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::ElementsAreArray;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::StrictMock;
+
+struct MockHWC2ComposerCallback : public HWC2::ComposerCallback {
+    ~MockHWC2ComposerCallback() = default;
+
+    MOCK_METHOD3(onHotplugReceived,
+                 void(int32_t sequenceId, hal::HWDisplayId display, hal::Connection connection));
+    MOCK_METHOD2(onRefreshReceived, void(int32_t sequenceId, hal::HWDisplayId display));
+    MOCK_METHOD4(onVsyncReceived,
+                 void(int32_t sequenceId, hal::HWDisplayId display, int64_t timestamp,
+                      std::optional<hal::VsyncPeriodNanos> vsyncPeriod));
+    MOCK_METHOD3(onVsyncPeriodTimingChangedReceived,
+                 void(int32_t sequenceId, hal::HWDisplayId display,
+                      const hal::VsyncPeriodChangeTimeline& updatedTimeline));
+    MOCK_METHOD2(onSeamlessPossible, void(int32_t sequenceId, hal::HWDisplayId display));
+};
+
+struct HWComposerTest : public testing::Test {
+    Hwc2::mock::Composer* mHal = new StrictMock<Hwc2::mock::Composer>();
+};
+
+struct HWComposerSetConfigurationTest : public HWComposerTest {
+    StrictMock<MockHWC2ComposerCallback> mCallback;
+};
+
+TEST_F(HWComposerSetConfigurationTest, loadsLayerMetadataSupport) {
+    const std::string kMetadata1Name = "com.example.metadata.1";
+    constexpr bool kMetadata1Mandatory = false;
+    const std::string kMetadata2Name = "com.example.metadata.2";
+    constexpr bool kMetadata2Mandatory = true;
+
+    EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
+    EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
+    EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
+            .WillOnce(DoAll(SetArgPointee<0>(std::vector<hal::LayerGenericMetadataKey>{
+                                    {kMetadata1Name, kMetadata1Mandatory},
+                                    {kMetadata2Name, kMetadata2Mandatory},
+                            }),
+                            Return(hardware::graphics::composer::V2_4::Error::NONE)));
+    EXPECT_CALL(*mHal, registerCallback(_));
+    EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()).WillOnce(Return(false));
+
+    impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
+    hwc.setConfiguration(&mCallback, 123);
+
+    const auto& supported = hwc.getSupportedLayerGenericMetadata();
+    EXPECT_EQ(2u, supported.size());
+    EXPECT_EQ(1u, supported.count(kMetadata1Name));
+    EXPECT_EQ(kMetadata1Mandatory, supported.find(kMetadata1Name)->second);
+    EXPECT_EQ(1u, supported.count(kMetadata2Name));
+    EXPECT_EQ(kMetadata2Mandatory, supported.find(kMetadata2Name)->second);
+}
+
+TEST_F(HWComposerSetConfigurationTest, handlesUnsupportedCallToGetLayerGenericMetadataKeys) {
+    EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
+    EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
+    EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_))
+            .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
+    EXPECT_CALL(*mHal, registerCallback(_));
+    EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported()).WillOnce(Return(false));
+
+    impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
+    hwc.setConfiguration(&mCallback, 123);
+
+    const auto& supported = hwc.getSupportedLayerGenericMetadata();
+    EXPECT_EQ(0u, supported.size());
+}
+
+struct HWComposerLayerTest : public testing::Test {
+    static constexpr hal::HWDisplayId kDisplayId = static_cast<hal::HWDisplayId>(1001);
+    static constexpr hal::HWLayerId kLayerId = static_cast<hal::HWLayerId>(1002);
+
+    HWComposerLayerTest(const std::unordered_set<hal::Capability>& capabilities)
+          : mCapabilies(capabilities) {}
+
+    ~HWComposerLayerTest() override { EXPECT_CALL(*mHal, destroyLayer(kDisplayId, kLayerId)); }
+
+    std::unique_ptr<Hwc2::mock::Composer> mHal{new StrictMock<Hwc2::mock::Composer>()};
+    const std::unordered_set<hal::Capability> mCapabilies;
+    HWC2::impl::Layer mLayer{*mHal, mCapabilies, kDisplayId, kLayerId};
+};
+
+struct HWComposerLayerGenericMetadataTest : public HWComposerLayerTest {
+    static const std::string kLayerGenericMetadata1Name;
+    static constexpr bool kLayerGenericMetadata1Mandatory = false;
+    static const std::vector<uint8_t> kLayerGenericMetadata1Value;
+    static const std::string kLayerGenericMetadata2Name;
+    static constexpr bool kLayerGenericMetadata2Mandatory = true;
+    static const std::vector<uint8_t> kLayerGenericMetadata2Value;
+
+    HWComposerLayerGenericMetadataTest() : HWComposerLayerTest({}) {}
+};
+
+const std::string HWComposerLayerGenericMetadataTest::kLayerGenericMetadata1Name =
+        "com.example.metadata.1";
+
+const std::vector<uint8_t> HWComposerLayerGenericMetadataTest::kLayerGenericMetadata1Value = {1u,
+                                                                                              2u,
+                                                                                              3u};
+
+const std::string HWComposerLayerGenericMetadataTest::kLayerGenericMetadata2Name =
+        "com.example.metadata.2";
+
+const std::vector<uint8_t> HWComposerLayerGenericMetadataTest::kLayerGenericMetadata2Value = {45u,
+                                                                                              67u};
+
+TEST_F(HWComposerLayerGenericMetadataTest, forwardsSupportedMetadata) {
+    EXPECT_CALL(*mHal,
+                setLayerGenericMetadata(kDisplayId, kLayerId, kLayerGenericMetadata1Name,
+                                        kLayerGenericMetadata1Mandatory,
+                                        kLayerGenericMetadata1Value))
+            .WillOnce(Return(hardware::graphics::composer::V2_4::Error::NONE));
+    auto result = mLayer.setLayerGenericMetadata(kLayerGenericMetadata1Name,
+                                                 kLayerGenericMetadata1Mandatory,
+                                                 kLayerGenericMetadata1Value);
+    EXPECT_EQ(hal::Error::NONE, result);
+
+    EXPECT_CALL(*mHal,
+                setLayerGenericMetadata(kDisplayId, kLayerId, kLayerGenericMetadata2Name,
+                                        kLayerGenericMetadata2Mandatory,
+                                        kLayerGenericMetadata2Value))
+            .WillOnce(Return(hardware::graphics::composer::V2_4::Error::UNSUPPORTED));
+    result = mLayer.setLayerGenericMetadata(kLayerGenericMetadata2Name,
+                                            kLayerGenericMetadata2Mandatory,
+                                            kLayerGenericMetadata2Value);
+    EXPECT_EQ(hal::Error::UNSUPPORTED, result);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 8e7440c..cae317b 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -1,140 +1,271 @@
+/*
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
-#define LOG_TAG "LayerHistoryUnittests"
+#define LOG_TAG "LayerHistoryTest"
 
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-
 #include <log/log.h>
 
-#include <mutex>
-#include <thread>
-
 #include "Scheduler/LayerHistory.h"
+#include "Scheduler/LayerInfo.h"
+#include "TestableScheduler.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/MockLayer.h"
 
 using testing::_;
 using testing::Return;
 
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
 
 class LayerHistoryTest : public testing::Test {
-public:
-    LayerHistoryTest();
-    ~LayerHistoryTest() override;
-
 protected:
-    std::unique_ptr<LayerHistory> mLayerHistory;
+    static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfo::PresentTimeHistory::HISTORY_SIZE;
+    static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfo::MAX_FREQUENT_LAYER_PERIOD_NS;
 
-    static constexpr float MIN_REFRESH_RATE = 30.f;
-    static constexpr float MAX_REFRESH_RATE = 90.f;
-    static constexpr auto RELEVANT_FRAME_THRESHOLD = 90u;
-    static constexpr uint64_t THIRTY_FPS_INTERVAL = 33'333'333;
+    static constexpr float LO_FPS = 30.f;
+    static constexpr nsecs_t LO_FPS_PERIOD = 33'333'333;
 
-    void forceRelevancy(const std::unique_ptr<LayerHistory::LayerHandle>& testLayer) {
-        mLayerHistory->setVisibility(testLayer, true);
-        for (auto i = 0u; i < RELEVANT_FRAME_THRESHOLD; i++) {
-            mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
-        }
-    };
+    static constexpr float HI_FPS = 90.f;
+    static constexpr nsecs_t HI_FPS_PERIOD = 11'111'111;
+
+    LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); }
+
+    impl::LayerHistory& history() { return *mScheduler->mutableLayerHistory(); }
+    const impl::LayerHistory& history() const { return *mScheduler->mutableLayerHistory(); }
+
+    size_t layerCount() const { return mScheduler->layerHistorySize(); }
+    size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; }
+
+    size_t frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
+        const auto& infos = history().mLayerInfos;
+        return std::count_if(infos.begin(), infos.begin() + history().mActiveLayersEnd,
+                             [now](const auto& pair) { return pair.second->isFrequent(now); });
+    }
+
+    auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); }
+
+    Hwc2::mock::Display mDisplay;
+    RefreshRateConfigs mConfigs{{HWC2::Display::Config::Builder(mDisplay, 0)
+                                         .setVsyncPeriod(int32_t(LO_FPS_PERIOD))
+                                         .setConfigGroup(0)
+                                         .build(),
+                                 HWC2::Display::Config::Builder(mDisplay, 1)
+                                         .setVsyncPeriod(int32_t(HI_FPS_PERIOD))
+                                         .setConfigGroup(0)
+                                         .build()},
+                                HwcConfigIndexType(0)};
+    TestableScheduler* const mScheduler{new TestableScheduler(mConfigs, false)};
+    TestableSurfaceFlinger mFlinger;
+
+    const nsecs_t mTime = systemTime();
 };
 
-LayerHistoryTest::LayerHistoryTest() {
-    mLayerHistory = std::make_unique<LayerHistory>();
-}
-LayerHistoryTest::~LayerHistoryTest() {}
-
 namespace {
+
 TEST_F(LayerHistoryTest, oneLayer) {
-    std::unique_ptr<LayerHistory::LayerHandle> testLayer =
-            mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
-    mLayerHistory->setVisibility(testLayer, true);
-    for (auto i = 0u; i < RELEVANT_FRAME_THRESHOLD; i++) {
-        EXPECT_FLOAT_EQ(0.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
-        mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    // no layers are returned if no layers are active.
+    ASSERT_TRUE(history().summarize(mTime).empty());
+    EXPECT_EQ(0, activeLayerCount());
+
+    // no layers are returned if active layers have insufficient history.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+        history().record(layer.get(), 0, mTime, LayerHistory::LayerUpdateType::Buffer);
+        ASSERT_TRUE(history().summarize(mTime).empty());
+        EXPECT_EQ(1, activeLayerCount());
     }
 
-    // Add a few more. This time we should get MAX refresh rate as the layer
-    // becomes relevant
-    static constexpr auto A_FEW = 10;
-    for (auto i = 0u; i < A_FEW; i++) {
-        EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
-        mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+    // High FPS is returned once enough history has been recorded.
+    for (int i = 0; i < 10; i++) {
+        history().record(layer.get(), 0, mTime, LayerHistory::LayerUpdateType::Buffer);
+        ASSERT_EQ(1, history().summarize(mTime).size());
+        EXPECT_FLOAT_EQ(HI_FPS, history().summarize(mTime)[0].desiredRefreshRate);
+        EXPECT_EQ(1, activeLayerCount());
     }
 }
 
-TEST_F(LayerHistoryTest, oneHDRLayer) {
-    std::unique_ptr<LayerHistory::LayerHandle> testLayer =
-            mLayerHistory->createLayer("TestHDRLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
-    mLayerHistory->setVisibility(testLayer, true);
-
-    mLayerHistory->insert(testLayer, 0, true /*isHDR*/);
-    EXPECT_FLOAT_EQ(0.0f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
-    EXPECT_EQ(true, mLayerHistory->getDesiredRefreshRateAndHDR().second);
-
-    mLayerHistory->setVisibility(testLayer, false);
-    EXPECT_FLOAT_EQ(0.0f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
-    EXPECT_EQ(false, mLayerHistory->getDesiredRefreshRateAndHDR().second);
-}
-
 TEST_F(LayerHistoryTest, explicitTimestamp) {
-    std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
-            mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
-    mLayerHistory->setVisibility(test30FpsLayer, true);
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
 
-    nsecs_t startTime = systemTime();
-    for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
-        mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
-                              false /*isHDR*/);
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    nsecs_t time = mTime;
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += LO_FPS_PERIOD;
     }
 
-    EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
+    ASSERT_EQ(1, history().summarize(mTime).size());
+    EXPECT_FLOAT_EQ(LO_FPS, history().summarize(mTime)[0].desiredRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
 }
 
 TEST_F(LayerHistoryTest, multipleLayers) {
-    std::unique_ptr<LayerHistory::LayerHandle> testLayer =
-            mLayerHistory->createLayer("TestLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
-    mLayerHistory->setVisibility(testLayer, true);
-    std::unique_ptr<LayerHistory::LayerHandle> test30FpsLayer =
-            mLayerHistory->createLayer("30FpsLayer", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
-    mLayerHistory->setVisibility(test30FpsLayer, true);
-    std::unique_ptr<LayerHistory::LayerHandle> testLayer2 =
-            mLayerHistory->createLayer("TestLayer2", MIN_REFRESH_RATE, MAX_REFRESH_RATE);
-    mLayerHistory->setVisibility(testLayer2, true);
+    auto layer1 = createLayer();
+    auto layer2 = createLayer();
+    auto layer3 = createLayer();
 
-    nsecs_t startTime = systemTime();
-    for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
-        mLayerHistory->insert(testLayer, 0, false /*isHDR*/);
+    EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer1, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+    EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer2, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+    EXPECT_CALL(*layer2, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer3, getFrameSelectionPriority()).WillRepeatedly(Return(1));
+    EXPECT_CALL(*layer3, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+    nsecs_t time = mTime;
+
+    EXPECT_EQ(3, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+
+    // layer1 is active but infrequent.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
     }
-    EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
 
-    startTime = systemTime();
-    for (int i = 0; i < RELEVANT_FRAME_THRESHOLD; i++) {
-        mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
-                              false /*isHDR*/);
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+
+    // layer2 is frequent and has high refresh rate.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += HI_FPS_PERIOD;
     }
-    EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
 
-    for (int i = 10; i < RELEVANT_FRAME_THRESHOLD; i++) {
-        mLayerHistory->insert(test30FpsLayer, startTime + (i * THIRTY_FPS_INTERVAL),
-                              false /*isHDR*/);
+    // layer1 is still active but infrequent.
+    history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+
+    ASSERT_EQ(2, history().summarize(time).size());
+    EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+    EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
+    EXPECT_EQ(2, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer1 is no longer active.
+    // layer2 is frequent and has low refresh rate.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += LO_FPS_PERIOD;
     }
-    EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
 
-    // This frame is only around for 9 occurrences, so it doesn't throw
-    // anything off.
-    for (int i = 0; i < 9; i++) {
-        mLayerHistory->insert(testLayer2, 0, false /*isHDR*/);
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer2 still has low refresh rate.
+    // layer3 has high refresh rate but not enough history.
+    constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD;
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+        if (i % RATIO == 0) {
+            history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        }
+
+        history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += HI_FPS_PERIOD;
     }
-    EXPECT_FLOAT_EQ(MAX_REFRESH_RATE, mLayerHistory->getDesiredRefreshRateAndHDR().first);
-    // After 1200 ms frames become obsolete.
-    std::this_thread::sleep_for(std::chrono::milliseconds(1500));
 
-    mLayerHistory->insert(test30FpsLayer,
-                          startTime + (RELEVANT_FRAME_THRESHOLD * THIRTY_FPS_INTERVAL),
-                          false /*isHDR*/);
-    EXPECT_FLOAT_EQ(30.f, mLayerHistory->getDesiredRefreshRateAndHDR().first);
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+    EXPECT_EQ(2, activeLayerCount());
+    EXPECT_EQ(2, frequentLayerCount(time));
+
+    // layer3 becomes recently active.
+    history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+    ASSERT_EQ(2, history().summarize(time).size());
+    EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+    EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
+    EXPECT_EQ(2, activeLayerCount());
+    EXPECT_EQ(2, frequentLayerCount(time));
+
+    // layer1 expires.
+    layer1.clear();
+    ASSERT_EQ(2, history().summarize(time).size());
+    EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+    EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
+    EXPECT_EQ(2, layerCount());
+    EXPECT_EQ(2, activeLayerCount());
+    EXPECT_EQ(2, frequentLayerCount(time));
+
+    // layer2 still has low refresh rate.
+    // layer3 becomes inactive.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += LO_FPS_PERIOD;
+    }
+
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer2 expires.
+    layer2.clear();
+    ASSERT_TRUE(history().summarize(time).empty());
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+
+    // layer3 becomes active and has high refresh rate.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += HI_FPS_PERIOD;
+    }
+
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[0].desiredRefreshRate);
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer3 expires.
+    layer3.clear();
+    ASSERT_TRUE(history().summarize(time).empty());
+    EXPECT_EQ(0, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
 }
 
 } // namespace
-} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
new file mode 100644
index 0000000..afd2b71
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp
@@ -0,0 +1,748 @@
+/*
+ * 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 "LayerHistoryTestV2"
+
+#include <Layer.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+
+#include "Scheduler/LayerHistory.h"
+#include "Scheduler/LayerInfoV2.h"
+#include "TestableScheduler.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/MockLayer.h"
+
+using testing::_;
+using testing::Return;
+
+namespace android::scheduler {
+
+class LayerHistoryTestV2 : public testing::Test {
+protected:
+    static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfoV2::HISTORY_SIZE;
+    static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfoV2::MAX_FREQUENT_LAYER_PERIOD_NS;
+    static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfoV2::FREQUENT_LAYER_WINDOW_SIZE;
+    static constexpr auto PRESENT_TIME_HISTORY_DURATION = LayerInfoV2::HISTORY_DURATION;
+    static constexpr auto REFRESH_RATE_AVERAGE_HISTORY_DURATION =
+            LayerInfoV2::RefreshRateHistory::HISTORY_DURATION;
+
+    static constexpr float LO_FPS = 30.f;
+    static constexpr auto LO_FPS_PERIOD = static_cast<nsecs_t>(1e9f / LO_FPS);
+
+    static constexpr float HI_FPS = 90.f;
+    static constexpr auto HI_FPS_PERIOD = static_cast<nsecs_t>(1e9f / HI_FPS);
+
+    LayerHistoryTestV2() { mFlinger.resetScheduler(mScheduler); }
+
+    impl::LayerHistoryV2& history() { return *mScheduler->mutableLayerHistoryV2(); }
+    const impl::LayerHistoryV2& history() const { return *mScheduler->mutableLayerHistoryV2(); }
+
+    size_t layerCount() const { return mScheduler->layerHistorySize(); }
+    size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; }
+
+    auto frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
+        const auto& infos = history().mLayerInfos;
+        return std::count_if(infos.begin(),
+                             infos.begin() + static_cast<long>(history().mActiveLayersEnd),
+                             [now](const auto& pair) { return pair.second->isFrequent(now); });
+    }
+
+    auto animatingLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS {
+        const auto& infos = history().mLayerInfos;
+        return std::count_if(infos.begin(),
+                             infos.begin() + static_cast<long>(history().mActiveLayersEnd),
+                             [now](const auto& pair) { return pair.second->isAnimating(now); });
+    }
+
+    void setLayerInfoVote(Layer* layer,
+                          LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS {
+        for (auto& [weak, info] : history().mLayerInfos) {
+            if (auto strong = weak.promote(); strong && strong.get() == layer) {
+                info->setDefaultLayerVote(vote);
+                info->setLayerVote(vote, 0);
+                return;
+            }
+        }
+    }
+
+    auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); }
+    auto createLayer(std::string name) {
+        return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger(), std::move(name)));
+    }
+
+    void recordFramesAndExpect(const sp<mock::MockLayer>& layer, nsecs_t& time, float frameRate,
+                               float desiredRefreshRate, int numFrames) {
+        const nsecs_t framePeriod = static_cast<nsecs_t>(1e9f / frameRate);
+        impl::LayerHistoryV2::Summary summary;
+        for (int i = 0; i < numFrames; i++) {
+            history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+            time += framePeriod;
+
+            summary = history().summarize(time);
+        }
+
+        ASSERT_EQ(1, summary.size());
+        ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+        ASSERT_FLOAT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate)
+                << "Frame rate is " << frameRate;
+    }
+
+    Hwc2::mock::Display mDisplay;
+    RefreshRateConfigs mConfigs{{HWC2::Display::Config::Builder(mDisplay, 0)
+                                         .setVsyncPeriod(int32_t(LO_FPS_PERIOD))
+                                         .setConfigGroup(0)
+                                         .build(),
+                                 HWC2::Display::Config::Builder(mDisplay, 1)
+                                         .setVsyncPeriod(int32_t(HI_FPS_PERIOD))
+                                         .setConfigGroup(0)
+                                         .build()},
+                                HwcConfigIndexType(0)};
+    TestableScheduler* const mScheduler{new TestableScheduler(mConfigs, true)};
+    TestableSurfaceFlinger mFlinger;
+
+};
+
+namespace {
+
+TEST_F(LayerHistoryTestV2, oneLayer) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    const nsecs_t time = systemTime();
+
+    // No layers returned if no layers are active.
+    EXPECT_TRUE(history().summarize(time).empty());
+    EXPECT_EQ(0, activeLayerCount());
+
+    // Max returned if active layers have insufficient history.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+        history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
+        ASSERT_EQ(1, history().summarize(time).size());
+        EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+        EXPECT_EQ(1, activeLayerCount());
+    }
+
+    // Max is returned since we have enough history but there is no timestamp votes.
+    for (int i = 0; i < 10; i++) {
+        history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
+        ASSERT_EQ(1, history().summarize(time).size());
+        EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+        EXPECT_EQ(1, activeLayerCount());
+    }
+}
+
+TEST_F(LayerHistoryTestV2, oneInvisibleLayer) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    nsecs_t time = systemTime();
+
+    history().record(layer.get(), 0, time, LayerHistory::LayerUpdateType::Buffer);
+    auto summary = history().summarize(time);
+    ASSERT_EQ(1, history().summarize(time).size());
+    // Layer is still considered inactive so we expect to get Min
+    EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false));
+
+    summary = history().summarize(time);
+    EXPECT_TRUE(history().summarize(time).empty());
+    EXPECT_EQ(0, activeLayerCount());
+}
+
+TEST_F(LayerHistoryTestV2, explicitTimestamp) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    nsecs_t time = systemTime();
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += LO_FPS_PERIOD;
+    }
+
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
+    EXPECT_FLOAT_EQ(LO_FPS, history().summarize(time)[0].desiredRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerNoVote) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::NoVote);
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    nsecs_t time = systemTime();
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += HI_FPS_PERIOD;
+    }
+
+    ASSERT_TRUE(history().summarize(time).empty());
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer became inactive
+    time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+    ASSERT_TRUE(history().summarize(time).empty());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerMinVote) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Min);
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    nsecs_t time = systemTime();
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += HI_FPS_PERIOD;
+    }
+
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer became inactive
+    time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+    ASSERT_TRUE(history().summarize(time).empty());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerMaxVote) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Max);
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    nsecs_t time = systemTime();
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += LO_FPS_PERIOD;
+    }
+
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer became inactive
+    time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+    ASSERT_TRUE(history().summarize(time).empty());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) {
+    auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree())
+            .WillRepeatedly(
+                    Return(Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::Default)));
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    nsecs_t time = systemTime();
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += HI_FPS_PERIOD;
+    }
+
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote);
+    EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer became inactive, but the vote stays
+    setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
+    time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitDefault, history().summarize(time)[0].vote);
+    EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, oneLayerExplicitExactVote) {
+    auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree())
+            .WillRepeatedly(Return(
+                    Layer::FrameRate(73.4f, Layer::FrameRateCompatibility::ExactOrMultiple)));
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+
+    nsecs_t time = systemTime();
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += HI_FPS_PERIOD;
+    }
+
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
+              history().summarize(time)[0].vote);
+    EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer became inactive, but the vote stays
+    setLayerInfoVote(layer.get(), LayerHistory::LayerVoteType::Heuristic);
+    time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
+              history().summarize(time)[0].vote);
+    EXPECT_FLOAT_EQ(73.4f, history().summarize(time)[0].desiredRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, multipleLayers) {
+    auto layer1 = createLayer();
+    auto layer2 = createLayer();
+    auto layer3 = createLayer();
+
+    EXPECT_CALL(*layer1, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer1, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    EXPECT_CALL(*layer2, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer2, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer3, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    nsecs_t time = systemTime();
+
+    EXPECT_EQ(3, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+
+    impl::LayerHistoryV2::Summary summary;
+
+    // layer1 is active but infrequent.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+        summary = history().summarize(time);
+    }
+
+    ASSERT_EQ(1, summary.size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+
+    // layer2 is frequent and has high refresh rate.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += HI_FPS_PERIOD;
+        summary = history().summarize(time);
+    }
+
+    // layer1 is still active but infrequent.
+    history().record(layer1.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+
+    ASSERT_EQ(2, summary.size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Min, summary[0].vote);
+    ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
+    EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate);
+    EXPECT_EQ(2, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer1 is no longer active.
+    // layer2 is frequent and has low refresh rate.
+    for (int i = 0; i < 2 * PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += LO_FPS_PERIOD;
+        summary = history().summarize(time);
+    }
+
+    ASSERT_EQ(1, summary.size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+    EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer2 still has low refresh rate.
+    // layer3 has high refresh rate but not enough history.
+    constexpr int RATIO = LO_FPS_PERIOD / HI_FPS_PERIOD;
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) {
+        if (i % RATIO == 0) {
+            history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        }
+
+        history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += HI_FPS_PERIOD;
+        summary = history().summarize(time);
+    }
+
+    ASSERT_EQ(2, summary.size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+    EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+    EXPECT_EQ(LayerHistory::LayerVoteType::Max, summary[1].vote);
+    EXPECT_EQ(2, activeLayerCount());
+    EXPECT_EQ(2, frequentLayerCount(time));
+
+    // layer3 becomes recently active.
+    history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+    summary = history().summarize(time);
+    ASSERT_EQ(2, summary.size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+    EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+    EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
+    EXPECT_FLOAT_EQ(HI_FPS, summary[1].desiredRefreshRate);
+    EXPECT_EQ(2, activeLayerCount());
+    EXPECT_EQ(2, frequentLayerCount(time));
+
+    // layer1 expires.
+    layer1.clear();
+    summary = history().summarize(time);
+    ASSERT_EQ(2, summary.size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+    EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+    EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+    EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[1].vote);
+    EXPECT_FLOAT_EQ(HI_FPS, summary[1].desiredRefreshRate);
+    EXPECT_EQ(2, layerCount());
+    EXPECT_EQ(2, activeLayerCount());
+    EXPECT_EQ(2, frequentLayerCount(time));
+
+    // layer2 still has low refresh rate.
+    // layer3 becomes inactive.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer2.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += LO_FPS_PERIOD;
+        summary = history().summarize(time);
+    }
+
+    ASSERT_EQ(1, summary.size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+    EXPECT_FLOAT_EQ(LO_FPS, summary[0].desiredRefreshRate);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer2 expires.
+    layer2.clear();
+    summary = history().summarize(time);
+    EXPECT_TRUE(summary.empty());
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+
+    // layer3 becomes active and has high refresh rate.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE + FREQUENT_LAYER_WINDOW_SIZE + 1; i++) {
+        history().record(layer3.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += HI_FPS_PERIOD;
+        summary = history().summarize(time);
+    }
+
+    ASSERT_EQ(1, summary.size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summary[0].vote);
+    EXPECT_FLOAT_EQ(HI_FPS, summary[0].desiredRefreshRate);
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+
+    // layer3 expires.
+    layer3.clear();
+    summary = history().summarize(time);
+    EXPECT_TRUE(summary.empty());
+    EXPECT_EQ(0, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, inactiveLayers) {
+    auto layer = createLayer();
+
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    nsecs_t time = systemTime();
+
+    // the very first updates makes the layer frequent
+    for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+        EXPECT_EQ(1, layerCount());
+        ASSERT_EQ(1, history().summarize(time).size());
+        EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+        EXPECT_EQ(1, activeLayerCount());
+        EXPECT_EQ(1, frequentLayerCount(time));
+    }
+
+    // the next update with the MAX_FREQUENT_LAYER_PERIOD_NS will get us to infrequent
+    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+    time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+    EXPECT_EQ(1, layerCount());
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+
+    // advance the time for the previous frame to be inactive
+    time += MAX_ACTIVE_LAYER_PERIOD_NS.count();
+
+    // Now event if we post a quick few frame we should stay infrequent
+    for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE - 1; i++) {
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += HI_FPS_PERIOD;
+
+        EXPECT_EQ(1, layerCount());
+        ASSERT_EQ(1, history().summarize(time).size());
+        EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+        EXPECT_EQ(1, activeLayerCount());
+        EXPECT_EQ(0, frequentLayerCount(time));
+    }
+
+    // More quick frames will get us to frequent again
+    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+    time += HI_FPS_PERIOD;
+
+    EXPECT_EQ(1, layerCount());
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(1, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, invisibleExplicitLayer) {
+    auto explicitVisiblelayer = createLayer();
+    auto explicitInvisiblelayer = createLayer();
+
+    EXPECT_CALL(*explicitVisiblelayer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*explicitVisiblelayer, getFrameRateForLayerTree())
+            .WillRepeatedly(Return(
+                    Layer::FrameRate(60.0f, Layer::FrameRateCompatibility::ExactOrMultiple)));
+
+    EXPECT_CALL(*explicitInvisiblelayer, isVisible()).WillRepeatedly(Return(false));
+    EXPECT_CALL(*explicitInvisiblelayer, getFrameRateForLayerTree())
+            .WillRepeatedly(Return(
+                    Layer::FrameRate(90.0f, Layer::FrameRateCompatibility::ExactOrMultiple)));
+
+    nsecs_t time = systemTime();
+
+    // Post a buffer to the layers to make them active
+    history().record(explicitVisiblelayer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+    history().record(explicitInvisiblelayer.get(), time, time,
+                     LayerHistory::LayerUpdateType::Buffer);
+
+    EXPECT_EQ(2, layerCount());
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitExactOrMultiple,
+              history().summarize(time)[0].vote);
+    EXPECT_FLOAT_EQ(60.0f, history().summarize(time)[0].desiredRefreshRate);
+    EXPECT_EQ(2, activeLayerCount());
+    EXPECT_EQ(2, frequentLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, infrequentAnimatingLayer) {
+    auto layer = createLayer();
+
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    nsecs_t time = systemTime();
+
+    EXPECT_EQ(1, layerCount());
+    EXPECT_EQ(0, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+    EXPECT_EQ(0, animatingLayerCount(time));
+
+    // layer is active but infrequent.
+    for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
+        history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+        time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+    }
+
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+    EXPECT_EQ(0, animatingLayerCount(time));
+
+    // another update with the same cadence keep in infrequent
+    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+    time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+    EXPECT_EQ(0, animatingLayerCount(time));
+
+    // an update as animation will immediately vote for Max
+    history().record(layer.get(), time, time, LayerHistory::LayerUpdateType::AnimationTX);
+    time += MAX_FREQUENT_LAYER_PERIOD_NS.count();
+
+    ASSERT_EQ(1, history().summarize(time).size());
+    EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote);
+    EXPECT_EQ(1, activeLayerCount());
+    EXPECT_EQ(0, frequentLayerCount(time));
+    EXPECT_EQ(1, animatingLayerCount(time));
+}
+
+TEST_F(LayerHistoryTestV2, heuristicLayer60Hz) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    nsecs_t time = systemTime();
+    for (float fps = 54.0f; fps < 65.0f; fps += 0.1f) {
+        recordFramesAndExpect(layer, time, fps, 60.0f, PRESENT_TIME_HISTORY_SIZE);
+    }
+}
+
+TEST_F(LayerHistoryTestV2, heuristicLayer60_30Hz) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    nsecs_t time = systemTime();
+    recordFramesAndExpect(layer, time, 60.0f, 60.0f, PRESENT_TIME_HISTORY_SIZE);
+
+    recordFramesAndExpect(layer, time, 60.0f, 60.0f, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 30.0f, 60.0f, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 30.0f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 60.0f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 60.0f, 60.0f, PRESENT_TIME_HISTORY_SIZE);
+}
+
+TEST_F(LayerHistoryTestV2, heuristicLayerNotOscillating) {
+    const auto layer = createLayer();
+    EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
+
+    nsecs_t time = systemTime();
+
+    recordFramesAndExpect(layer, time, 27.10f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 26.90f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 26.00f, 24.0f, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 26.90f, 24.0f, PRESENT_TIME_HISTORY_SIZE);
+    recordFramesAndExpect(layer, time, 27.10f, 30.0f, PRESENT_TIME_HISTORY_SIZE);
+}
+
+class LayerHistoryTestV2Parameterized
+      : public LayerHistoryTestV2,
+        public testing::WithParamInterface<std::chrono::nanoseconds> {};
+
+TEST_P(LayerHistoryTestV2Parameterized, HeuristicLayerWithInfrequentLayer) {
+    std::chrono::nanoseconds infrequentUpdateDelta = GetParam();
+    auto heuristicLayer = createLayer("HeuristicLayer");
+
+    EXPECT_CALL(*heuristicLayer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*heuristicLayer, getFrameRateForLayerTree())
+            .WillRepeatedly(Return(Layer::FrameRate()));
+
+    auto infrequentLayer = createLayer("InfrequentLayer");
+    EXPECT_CALL(*infrequentLayer, isVisible()).WillRepeatedly(Return(true));
+    EXPECT_CALL(*infrequentLayer, getFrameRateForLayerTree())
+            .WillRepeatedly(Return(Layer::FrameRate()));
+
+    const nsecs_t startTime = systemTime();
+
+    const std::chrono::nanoseconds heuristicUpdateDelta = 41'666'667ns;
+    history().record(heuristicLayer.get(), startTime, startTime,
+                     LayerHistory::LayerUpdateType::Buffer);
+    history().record(infrequentLayer.get(), startTime, startTime,
+                     LayerHistory::LayerUpdateType::Buffer);
+
+    nsecs_t time = startTime;
+    nsecs_t lastInfrequentUpdate = startTime;
+    const int totalInfrequentLayerUpdates = FREQUENT_LAYER_WINDOW_SIZE * 5;
+    int infrequentLayerUpdates = 0;
+    while (infrequentLayerUpdates <= totalInfrequentLayerUpdates) {
+        time += heuristicUpdateDelta.count();
+        history().record(heuristicLayer.get(), time, time, LayerHistory::LayerUpdateType::Buffer);
+
+        if (time - lastInfrequentUpdate >= infrequentUpdateDelta.count()) {
+            ALOGI("submitting infrequent frame [%d/%d]", infrequentLayerUpdates,
+                  totalInfrequentLayerUpdates);
+            lastInfrequentUpdate = time;
+            history().record(infrequentLayer.get(), time, time,
+                             LayerHistory::LayerUpdateType::Buffer);
+            infrequentLayerUpdates++;
+        }
+
+        if (time - startTime > PRESENT_TIME_HISTORY_DURATION.count()) {
+            ASSERT_NE(0, history().summarize(time).size());
+            ASSERT_GE(2, history().summarize(time).size());
+
+            bool max = false;
+            bool min = false;
+            float heuristic = 0;
+            for (const auto& layer : history().summarize(time)) {
+                if (layer.vote == LayerHistory::LayerVoteType::Heuristic) {
+                    heuristic = layer.desiredRefreshRate;
+                } else if (layer.vote == LayerHistory::LayerVoteType::Max) {
+                    max = true;
+                } else if (layer.vote == LayerHistory::LayerVoteType::Min) {
+                    min = true;
+                }
+            }
+
+            if (infrequentLayerUpdates > FREQUENT_LAYER_WINDOW_SIZE) {
+                EXPECT_FLOAT_EQ(24.0f, heuristic);
+                EXPECT_FALSE(max);
+                if (history().summarize(time).size() == 2) {
+                    EXPECT_TRUE(min);
+                }
+            }
+        }
+    }
+}
+
+INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryTestV2Parameterized,
+                        ::testing::Values(1s, 2s, 3s, 4s, 5s));
+
+} // namespace
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
similarity index 75%
rename from services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
rename to services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index eff22b6..0208728 100644
--- a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -21,17 +21,17 @@
 #include <utils/Log.h>
 
 #include "AsyncCallRecorder.h"
-#include "Scheduler/IdleTimer.h"
+#include "Scheduler/OneShotTimer.h"
 
 using namespace std::chrono_literals;
 
 namespace android {
 namespace scheduler {
 
-class IdleTimerTest : public testing::Test {
+class OneShotTimerTest : public testing::Test {
 protected:
-    IdleTimerTest() = default;
-    ~IdleTimerTest() override = default;
+    OneShotTimerTest() = default;
+    ~OneShotTimerTest() override = default;
 
     // This timeout should be used when a 3ms callback is expected.
     // While the tests typically request a callback after 3ms, the scheduler
@@ -46,7 +46,7 @@
     AsyncCallRecorder<void (*)()> mResetTimerCallback;
     AsyncCallRecorder<void (*)()> mExpiredTimerCallback;
 
-    std::unique_ptr<IdleTimer> mIdleTimer;
+    std::unique_ptr<OneShotTimer> mIdleTimer;
 
     void clearPendingCallbacks() {
         while (mExpiredTimerCallback.waitForCall(0us).has_value()) {
@@ -55,13 +55,14 @@
 };
 
 namespace {
-TEST_F(IdleTimerTest, createAndDestroyTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, [] {}, [] {});
+TEST_F(OneShotTimerTest, createAndDestroyTest) {
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
+            3ms, [] {}, [] {});
 }
 
-TEST_F(IdleTimerTest, startStopTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mResetTimerCallback.getInvocable(),
-                                                        mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, startStopTest) {
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(30ms, mResetTimerCallback.getInvocable(),
+                                                           mExpiredTimerCallback.getInvocable());
     auto startTime = std::chrono::steady_clock::now();
     mIdleTimer->start();
     EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -70,7 +71,7 @@
     bool callbackCalled = mExpiredTimerCallback.waitForCall(25ms).has_value();
     // Under ideal conditions there should be no event. But occasionally
     // it is possible that the wait just prior takes more than 30ms, and
-    // a callback is observed. We check the elapsed time since before the IdleTimer
+    // a callback is observed. We check the elapsed time since before the OneShotTimer
     // thread was started as a sanity check to not have a flakey test.
     EXPECT_FALSE(callbackCalled && std::chrono::steady_clock::now() - startTime < 30ms);
 
@@ -79,9 +80,9 @@
     mIdleTimer->stop();
 }
 
-TEST_F(IdleTimerTest, resetTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(),
-                                                        mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, resetTest) {
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(),
+                                                           mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
     EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
     // Observe any event that happens in about 25ms. We don't care if one was
@@ -104,9 +105,9 @@
     EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
 }
 
-TEST_F(IdleTimerTest, resetBackToBackTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(),
-                                                        mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, resetBackToBackTest) {
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(),
+                                                           mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
     EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
 
@@ -135,9 +136,9 @@
     EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
 }
 
-TEST_F(IdleTimerTest, startNotCalledTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
-                                                        mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, startNotCalledTest) {
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+                                                           mExpiredTimerCallback.getInvocable());
     // The start hasn't happened, so the callback does not happen.
     EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
     EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
@@ -147,9 +148,9 @@
     EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
 }
 
-TEST_F(IdleTimerTest, idleTimerIdlesTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
-                                                        mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, idleTimerIdlesTest) {
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+                                                           mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
     EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
 
@@ -167,18 +168,18 @@
     EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
 }
 
-TEST_F(IdleTimerTest, timeoutCallbackExecutionTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
-                                                        mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) {
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+                                                           mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
     EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
     EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
     mIdleTimer->stop();
 }
 
-TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
-                                                        mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) {
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+                                                           mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
     EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
     EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
@@ -190,9 +191,9 @@
     EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
 }
 
-TEST_F(IdleTimerTest, noCallbacksAfterStopTest) {
-    mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
-                                                        mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, noCallbacksAfterStopTest) {
+    mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+                                                           mExpiredTimerCallback.getInvocable());
     mIdleTimer->start();
     EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
 
diff --git a/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
new file mode 100644
index 0000000..0b74682
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/PhaseOffsetsTest.cpp
@@ -0,0 +1,183 @@
+/*
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "SchedulerUnittests"
+
+#include <gmock/gmock.h>
+#include <log/log.h>
+#include <thread>
+
+#include "Scheduler/PhaseOffsets.h"
+
+using namespace testing;
+
+namespace android {
+namespace scheduler {
+
+class TestablePhaseOffsetsAsDurations : public impl::PhaseDurations {
+public:
+    TestablePhaseOffsetsAsDurations(float currentFps, nsecs_t sfDuration, nsecs_t appDuration,
+                                    nsecs_t sfEarlyDuration, nsecs_t appEarlyDuration,
+                                    nsecs_t sfEarlyGlDuration, nsecs_t appEarlyGlDuration)
+          : impl::PhaseDurations({60.0f, 90.0f}, currentFps, sfDuration, appDuration,
+                                 sfEarlyDuration, appEarlyDuration, sfEarlyGlDuration,
+                                 appEarlyGlDuration) {}
+};
+
+class PhaseDurationTest : public testing::Test {
+protected:
+    PhaseDurationTest()
+          : mPhaseDurations(60.0f, 10'500'000, 20'500'000, 16'000'000, 16'500'000, 13'500'000,
+                            21'000'000) {}
+
+    ~PhaseDurationTest() = default;
+
+    TestablePhaseOffsetsAsDurations mPhaseDurations;
+};
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_60Hz) {
+    mPhaseDurations.setRefreshRateFps(60.0f);
+    auto currentOffsets = mPhaseDurations.getCurrentOffsets();
+    auto offsets = mPhaseDurations.getOffsetsForRefreshRate(60.0f);
+
+    EXPECT_EQ(currentOffsets, offsets);
+    EXPECT_EQ(offsets.late.sf, 6'166'667);
+
+    EXPECT_EQ(offsets.late.app, 2'333'334);
+
+    EXPECT_EQ(offsets.early.sf, 666'667);
+
+    EXPECT_EQ(offsets.early.app, 833'334);
+
+    EXPECT_EQ(offsets.earlyGl.sf, 3'166'667);
+
+    EXPECT_EQ(offsets.earlyGl.app, 15'500'001);
+}
+
+TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_90Hz) {
+    mPhaseDurations.setRefreshRateFps(90.0f);
+    auto currentOffsets = mPhaseDurations.getCurrentOffsets();
+    auto offsets = mPhaseDurations.getOffsetsForRefreshRate(90.0f);
+
+    EXPECT_EQ(currentOffsets, offsets);
+    EXPECT_EQ(offsets.late.sf, 611'111);
+
+    EXPECT_EQ(offsets.late.app, 2'333'333);
+
+    EXPECT_EQ(offsets.early.sf, -4'888'889);
+
+    EXPECT_EQ(offsets.early.app, 833'333);
+
+    EXPECT_EQ(offsets.earlyGl.sf, -2'388'889);
+
+    EXPECT_EQ(offsets.earlyGl.app, 9'944'444);
+}
+
+TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_DefaultOffsets) {
+    TestablePhaseOffsetsAsDurations phaseOffsetsWithDefaultValues(60.0f, -1, -1, -1, -1, -1, -1);
+
+    auto validateOffsets = [](auto& offsets) {
+        EXPECT_EQ(offsets.late.sf, 1'000'000);
+
+        EXPECT_EQ(offsets.late.app, 1'000'000);
+
+        EXPECT_EQ(offsets.early.sf, 1'000'000);
+
+        EXPECT_EQ(offsets.early.app, 1'000'000);
+
+        EXPECT_EQ(offsets.earlyGl.sf, 1'000'000);
+
+        EXPECT_EQ(offsets.earlyGl.app, 1'000'000);
+    };
+
+    phaseOffsetsWithDefaultValues.setRefreshRateFps(90.0f);
+    auto currentOffsets = phaseOffsetsWithDefaultValues.getCurrentOffsets();
+    auto offsets = phaseOffsetsWithDefaultValues.getOffsetsForRefreshRate(90.0f);
+    EXPECT_EQ(currentOffsets, offsets);
+    validateOffsets(offsets);
+
+    phaseOffsetsWithDefaultValues.setRefreshRateFps(60.0f);
+    currentOffsets = phaseOffsetsWithDefaultValues.getCurrentOffsets();
+    offsets = phaseOffsetsWithDefaultValues.getOffsetsForRefreshRate(90.0f);
+    EXPECT_EQ(currentOffsets, offsets);
+    validateOffsets(offsets);
+}
+
+TEST_F(PhaseDurationTest, getOffsetsForRefreshRate_unknownRefreshRate) {
+    auto offsets = mPhaseDurations.getOffsetsForRefreshRate(14.7f);
+
+    EXPECT_EQ(offsets.late.sf, 57'527'208);
+
+    EXPECT_EQ(offsets.late.app, 37'027'208);
+
+    EXPECT_EQ(offsets.early.sf, 52'027'208);
+
+    EXPECT_EQ(offsets.early.app, 35'527'208);
+
+    EXPECT_EQ(offsets.earlyGl.sf, 54'527'208);
+
+    EXPECT_EQ(offsets.earlyGl.app, 33'527'208);
+}
+
+} // namespace
+
+class TestablePhaseOffsets : public impl::PhaseOffsets {
+public:
+    TestablePhaseOffsets()
+          : impl::PhaseOffsets({60.0f, 90.0f}, 60.0f, 1'000'000, 1'000'000, {}, {}, {}, {},
+                               10'000'000) {}
+};
+
+class PhaseOffsetsTest : public testing::Test {
+protected:
+    PhaseOffsetsTest() = default;
+    ~PhaseOffsetsTest() = default;
+
+    TestablePhaseOffsets mPhaseOffsets;
+};
+
+namespace {
+TEST_F(PhaseOffsetsTest, getOffsetsForRefreshRate_unknownRefreshRate) {
+    auto offsets = mPhaseOffsets.getOffsetsForRefreshRate(14.7f);
+
+    EXPECT_EQ(offsets.late.sf, 1'000'000);
+
+    EXPECT_EQ(offsets.late.app, 1'000'000);
+
+    EXPECT_EQ(offsets.early.sf, 1'000'000);
+
+    EXPECT_EQ(offsets.early.app, 1'000'000);
+
+    EXPECT_EQ(offsets.earlyGl.sf, 1'000'000);
+
+    EXPECT_EQ(offsets.earlyGl.app, 1'000'000);
+}
+
+} // namespace
+} // namespace scheduler
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/PromiseTest.cpp b/services/surfaceflinger/tests/unittests/PromiseTest.cpp
new file mode 100644
index 0000000..e4dc1fe
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/PromiseTest.cpp
@@ -0,0 +1,88 @@
+/*
+ * 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.
+ */
+
+#include <algorithm>
+#include <future>
+#include <string>
+#include <thread>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "Promise.h"
+
+namespace android {
+namespace {
+
+using Bytes = std::vector<uint8_t>;
+
+Bytes decrement(Bytes bytes) {
+    std::transform(bytes.begin(), bytes.end(), bytes.begin(), [](auto b) { return b - 1; });
+    return bytes;
+}
+
+} // namespace
+
+TEST(PromiseTest, yield) {
+    EXPECT_EQ(42, promise::yield(42).get());
+
+    auto ptr = std::make_unique<char>('!');
+    auto future = promise::yield(std::move(ptr));
+    EXPECT_EQ('!', *future.get());
+}
+
+TEST(PromiseTest, chain) {
+    std::packaged_task<const char*()> fetchString([] { return "ifmmp-"; });
+
+    std::packaged_task<Bytes(std::string)> appendString([](std::string str) {
+        str += "!xpsme";
+        return Bytes{str.begin(), str.end()};
+    });
+
+    std::packaged_task<std::future<Bytes>(Bytes)> decrementBytes(
+            [](Bytes bytes) { return promise::defer(decrement, std::move(bytes)); });
+
+    auto fetch = fetchString.get_future();
+    std::thread fetchThread(std::move(fetchString));
+
+    std::thread appendThread, decrementThread;
+
+    EXPECT_EQ("hello, world",
+              promise::chain(std::move(fetch))
+                      .then([](const char* str) { return std::string(str); })
+                      .then([&](std::string str) {
+                          auto append = appendString.get_future();
+                          appendThread = std::thread(std::move(appendString), std::move(str));
+                          return append;
+                      })
+                      .then([&](Bytes bytes) {
+                          auto decrement = decrementBytes.get_future();
+                          decrementThread = std::thread(std::move(decrementBytes),
+                                                        std::move(bytes));
+                          return decrement;
+                      })
+                      .then([](std::future<Bytes> bytes) { return bytes; })
+                      .then([](const Bytes& bytes) {
+                          return std::string(bytes.begin(), bytes.end());
+                      })
+                      .get());
+
+    fetchThread.join();
+    appendThread.join();
+    decrementThread.join();
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index f315a8a..1f6f166 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -21,8 +21,10 @@
 #include <log/log.h>
 #include <thread>
 
+#include "../../Scheduler/RefreshRateConfigs.h"
 #include "DisplayHardware/HWC2.h"
 #include "Scheduler/RefreshRateConfigs.h"
+#include "mock/DisplayHardware/MockDisplay.h"
 
 using namespace std::chrono_literals;
 using testing::_;
@@ -30,29 +32,111 @@
 namespace android {
 namespace scheduler {
 
-using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+namespace hal = android::hardware::graphics::composer::hal;
+
 using RefreshRate = RefreshRateConfigs::RefreshRate;
+using LayerVoteType = RefreshRateConfigs::LayerVoteType;
+using LayerRequirement = RefreshRateConfigs::LayerRequirement;
 
 class RefreshRateConfigsTest : public testing::Test {
 protected:
-    static constexpr int CONFIG_ID_60 = 0;
-    static constexpr hwc2_config_t HWC2_CONFIG_ID_60 = 0;
-    static constexpr int CONFIG_ID_90 = 1;
-    static constexpr hwc2_config_t HWC2_CONFIG_ID_90 = 1;
-    static constexpr int64_t VSYNC_60 = 16666667;
-    static constexpr int64_t VSYNC_90 = 11111111;
-
     RefreshRateConfigsTest();
     ~RefreshRateConfigsTest();
 
-    void assertRatesEqual(const RefreshRate& left, const RefreshRate& right) {
-        ASSERT_EQ(left.configId, right.configId);
-        ASSERT_EQ(left.name, right.name);
-        ASSERT_EQ(left.fps, right.fps);
-        ASSERT_EQ(left.vsyncPeriod, right.vsyncPeriod);
+    float findClosestKnownFrameRate(const RefreshRateConfigs& refreshRateConfigs, float frameRate) {
+        return refreshRateConfigs.findClosestKnownFrameRate(frameRate);
     }
+
+    std::vector<float> getKnownFrameRate(const RefreshRateConfigs& refreshRateConfigs) {
+        return refreshRateConfigs.mKnownFrameRates;
+    }
+
+    // Test config IDs
+    static inline const HwcConfigIndexType HWC_CONFIG_ID_60 = HwcConfigIndexType(0);
+    static inline const HwcConfigIndexType HWC_CONFIG_ID_90 = HwcConfigIndexType(1);
+    static inline const HwcConfigIndexType HWC_CONFIG_ID_72 = HwcConfigIndexType(2);
+    static inline const HwcConfigIndexType HWC_CONFIG_ID_120 = HwcConfigIndexType(3);
+    static inline const HwcConfigIndexType HWC_CONFIG_ID_30 = HwcConfigIndexType(4);
+
+    // Test configs
+    std::shared_ptr<const HWC2::Display::Config> mConfig60 =
+            createConfig(HWC_CONFIG_ID_60, 0, static_cast<int64_t>(1e9f / 60));
+    std::shared_ptr<const HWC2::Display::Config> mConfig90 =
+            createConfig(HWC_CONFIG_ID_90, 0, static_cast<int64_t>(1e9f / 90));
+    std::shared_ptr<const HWC2::Display::Config> mConfig90DifferentGroup =
+            createConfig(HWC_CONFIG_ID_90, 1, static_cast<int64_t>(1e9f / 90));
+    std::shared_ptr<const HWC2::Display::Config> mConfig90DifferentResolution =
+            createConfig(HWC_CONFIG_ID_90, 0, static_cast<int64_t>(1e9f / 90), 111, 222);
+    std::shared_ptr<const HWC2::Display::Config> mConfig72 =
+            createConfig(HWC_CONFIG_ID_72, 0, static_cast<int64_t>(1e9f / 72));
+    std::shared_ptr<const HWC2::Display::Config> mConfig72DifferentGroup =
+            createConfig(HWC_CONFIG_ID_72, 1, static_cast<int64_t>(1e9f / 72));
+    std::shared_ptr<const HWC2::Display::Config> mConfig120 =
+            createConfig(HWC_CONFIG_ID_120, 0, static_cast<int64_t>(1e9f / 120));
+    std::shared_ptr<const HWC2::Display::Config> mConfig120DifferentGroup =
+            createConfig(HWC_CONFIG_ID_120, 1, static_cast<int64_t>(1e9f / 120));
+    std::shared_ptr<const HWC2::Display::Config> mConfig30 =
+            createConfig(HWC_CONFIG_ID_30, 0, static_cast<int64_t>(1e9f / 30));
+
+    // Test device configurations
+    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};
+
+    // Expected RefreshRate objects
+    RefreshRate mExpected60Config = {HWC_CONFIG_ID_60, mConfig60, "60fps", 60,
+                                     RefreshRate::ConstructorTag(0)};
+    RefreshRate mExpectedAlmost60Config = {HWC_CONFIG_ID_60,
+                                           createConfig(HWC_CONFIG_ID_60, 0, 16666665), "60fps", 60,
+                                           RefreshRate::ConstructorTag(0)};
+    RefreshRate mExpected90Config = {HWC_CONFIG_ID_90, mConfig90, "90fps", 90,
+                                     RefreshRate::ConstructorTag(0)};
+    RefreshRate mExpected90DifferentGroupConfig = {HWC_CONFIG_ID_90, mConfig90DifferentGroup,
+                                                   "90fps", 90, RefreshRate::ConstructorTag(0)};
+    RefreshRate mExpected90DifferentResolutionConfig = {HWC_CONFIG_ID_90,
+                                                        mConfig90DifferentResolution, "90fps", 90,
+                                                        RefreshRate::ConstructorTag(0)};
+    RefreshRate mExpected72Config = {HWC_CONFIG_ID_72, mConfig72, "72fps", 72,
+                                     RefreshRate::ConstructorTag(0)};
+    RefreshRate mExpected30Config = {HWC_CONFIG_ID_30, mConfig30, "30fps", 30,
+                                     RefreshRate::ConstructorTag(0)};
+    RefreshRate mExpected120Config = {HWC_CONFIG_ID_120, mConfig120, "120fps", 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);
 };
 
+using Builder = HWC2::Display::Config::Builder;
+
 RefreshRateConfigsTest::RefreshRateConfigsTest() {
     const ::testing::TestInfo* const test_info =
             ::testing::UnitTest::GetInstance()->current_test_info();
@@ -65,44 +149,1328 @@
     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()))
+            .setVsyncPeriod(int32_t(vsyncPeriod))
+            .setConfigGroup(configGroup)
+            .setHeight(hight)
+            .setWidth(width)
+            .build();
+}
+
 namespace {
 /* ------------------------------------------------------------------------
  * Test cases
  */
-TEST_F(RefreshRateConfigsTest, oneDeviceConfig_isRejected) {
-    std::vector<RefreshRateConfigs::InputConfig> configs{{HWC2_CONFIG_ID_60, VSYNC_60}};
+TEST_F(RefreshRateConfigsTest, oneDeviceConfig_SwitchingSupported) {
     auto refreshRateConfigs =
-            std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
-                                                 /*currentConfig=*/0);
-    ASSERT_FALSE(refreshRateConfigs->refreshRateSwitchingSupported());
+            std::make_unique<RefreshRateConfigs>(m60OnlyConfigDevice,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+}
+
+TEST_F(RefreshRateConfigsTest, invalidPolicy) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60OnlyConfigDevice,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+    ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HwcConfigIndexType(10), {60, 60}}), 0);
+    ASSERT_LT(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {20, 40}}), 0);
 }
 
 TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) {
-    std::vector<RefreshRateConfigs::InputConfig> configs{{HWC2_CONFIG_ID_60, VSYNC_60},
-                                                         {HWC2_CONFIG_ID_90, VSYNC_90}};
     auto refreshRateConfigs =
-            std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
-                                                 /*currentConfig=*/0);
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
 
-    ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
-    const auto& rates = refreshRateConfigs->getRefreshRateMap();
-    ASSERT_EQ(2, rates.size());
-    const auto& defaultRate = rates.find(RefreshRateType::DEFAULT);
-    const auto& performanceRate = rates.find(RefreshRateType::PERFORMANCE);
-    ASSERT_NE(rates.end(), defaultRate);
-    ASSERT_NE(rates.end(), performanceRate);
+    const auto& minRate = refreshRateConfigs->getMinRefreshRate();
+    const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate();
 
-    RefreshRate expectedDefaultConfig = {CONFIG_ID_60, "60fps", 60, VSYNC_60, HWC2_CONFIG_ID_60};
-    assertRatesEqual(expectedDefaultConfig, defaultRate->second);
-    RefreshRate expectedPerformanceConfig = {CONFIG_ID_90, "90fps", 90, VSYNC_90,
-                                             HWC2_CONFIG_ID_90};
-    assertRatesEqual(expectedPerformanceConfig, performanceRate->second);
+    ASSERT_EQ(mExpected60Config, minRate);
+    ASSERT_EQ(mExpected90Config, performanceRate);
 
-    assertRatesEqual(expectedDefaultConfig,
-                     refreshRateConfigs->getRefreshRateFromType(RefreshRateType::DEFAULT));
-    assertRatesEqual(expectedPerformanceConfig,
-                     refreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE));
+    const auto& minRateByPolicy = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRateByPolicy = refreshRateConfigs->getMaxRefreshRateByPolicy();
+    ASSERT_EQ(minRateByPolicy, minRate);
+    ASSERT_EQ(performanceRateByPolicy, performanceRate);
 }
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differentGroups) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentGroups,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    const auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate();
+    const auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+
+    ASSERT_EQ(mExpected60Config, minRate);
+    ASSERT_EQ(mExpected60Config, minRate60);
+    ASSERT_EQ(mExpected60Config, performanceRate60);
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0);
+    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+
+    const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+
+    ASSERT_EQ(mExpected90DifferentGroupConfig, performanceRate);
+    ASSERT_EQ(mExpected90DifferentGroupConfig, minRate90);
+    ASSERT_EQ(mExpected90DifferentGroupConfig, performanceRate90);
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap_differentResolutions) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentResolutions,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    const auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRate = refreshRateConfigs->getMaxRefreshRate();
+    const auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+
+    ASSERT_EQ(mExpected60Config, minRate);
+    ASSERT_EQ(mExpected60Config, minRate60);
+    ASSERT_EQ(mExpected60Config, performanceRate60);
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {60, 90}}), 0);
+    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+
+    const auto& minRate90 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    const auto& performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+
+    ASSERT_EQ(mExpected90DifferentResolutionConfig, performanceRate);
+    ASSERT_EQ(mExpected90DifferentResolutionConfig, minRate90);
+    ASSERT_EQ(mExpected90DifferentResolutionConfig, performanceRate90);
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_policyChange) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto& minRate = refreshRateConfigs->getMinRefreshRateByPolicy();
+    auto& performanceRate = refreshRateConfigs->getMaxRefreshRateByPolicy();
+
+    ASSERT_EQ(mExpected60Config, minRate);
+    ASSERT_EQ(mExpected90Config, performanceRate);
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+
+    auto& minRate60 = refreshRateConfigs->getMinRefreshRateByPolicy();
+    auto& performanceRate60 = refreshRateConfigs->getMaxRefreshRateByPolicy();
+    ASSERT_EQ(mExpected60Config, minRate60);
+    ASSERT_EQ(mExpected60Config, performanceRate60);
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getCurrentRefreshRate) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+    {
+        auto& current = refreshRateConfigs->getCurrentRefreshRate();
+        EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_60);
+    }
+
+    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+    {
+        auto& current = refreshRateConfigs->getCurrentRefreshRate();
+        EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
+    }
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
+    {
+        auto& current = refreshRateConfigs->getCurrentRefreshRate();
+        EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
+    }
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    const auto makeLayerRequirements = [](float refreshRate) -> std::vector<LayerRequirement> {
+        return {{"testLayer", LayerVoteType::Heuristic, refreshRate, /*weight*/ 1.0f,
+                 /*focused*/ false}};
+    };
+
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(60.0f)));
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(45.0f)));
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(60.0f)));
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(45.0f)));
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(60.0f)));
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(45.0f)));
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0);
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(90.0f)));
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(60.0f)));
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(45.0f)));
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(30.0f)));
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getRefreshRateForContent(makeLayerRequirements(24.0f)));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_noLayers) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_72_90Device, /*currentConfigId=*/
+                                                 HWC_CONFIG_ID_72);
+
+    // If there are no layers we select the default frame rate, which is the max of the primary
+    // range.
+    auto layers = std::vector<LayerRequirement>{};
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_90) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    lr.vote = LayerVoteType::Min;
+    lr.name = "Min";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.vote = LayerVoteType::Max;
+    lr.name = "Max";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 90.0f;
+    lr.vote = LayerVoteType::Heuristic;
+    lr.name = "90Hz Heuristic";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz Heuristic";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 45.0f;
+    lr.name = "45Hz Heuristic";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 30.0f;
+    lr.name = "30Hz Heuristic";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 24.0f;
+    lr.name = "24Hz Heuristic";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.name = "";
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+
+    lr.vote = LayerVoteType::Min;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.vote = LayerVoteType::Max;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 90.0f;
+    lr.vote = LayerVoteType::Heuristic;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 60.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 45.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 30.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 24.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
+
+    lr.vote = LayerVoteType::Min;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.vote = LayerVoteType::Max;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 90.0f;
+    lr.vote = LayerVoteType::Heuristic;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 60.0f;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 45.0f;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 30.0f;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 24.0f;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {0, 120}}), 0);
+    lr.vote = LayerVoteType::Min;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.vote = LayerVoteType::Max;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 90.0f;
+    lr.vote = LayerVoteType::Heuristic;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 60.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 45.0f;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 30.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 24.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_60_72_90) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_72_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    lr.vote = LayerVoteType::Min;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.vote = LayerVoteType::Max;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 90.0f;
+    lr.vote = LayerVoteType::Heuristic;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 60.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 45.0f;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 30.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 24.0f;
+    EXPECT_EQ(mExpected72Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90_120) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+                                                LayerRequirement{.weight = 1.0f}};
+    auto& lr1 = layers[0];
+    auto& lr2 = layers[1];
+
+    lr1.desiredRefreshRate = 24.0f;
+    lr1.vote = LayerVoteType::Heuristic;
+    lr2.desiredRefreshRate = 60.0f;
+    lr2.vote = LayerVoteType::Heuristic;
+    EXPECT_EQ(mExpected120Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.desiredRefreshRate = 24.0f;
+    lr1.vote = LayerVoteType::Heuristic;
+    lr2.desiredRefreshRate = 48.0f;
+    lr2.vote = LayerVoteType::Heuristic;
+    EXPECT_EQ(mExpected72Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.desiredRefreshRate = 24.0f;
+    lr1.vote = LayerVoteType::Heuristic;
+    lr2.desiredRefreshRate = 48.0f;
+    lr2.vote = LayerVoteType::Heuristic;
+    EXPECT_EQ(mExpected72Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_90_120_DifferentTypes) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m30_60_72_90_120Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+                                                LayerRequirement{.weight = 1.0f}};
+    auto& lr1 = layers[0];
+    auto& lr2 = layers[1];
+
+    lr1.desiredRefreshRate = 24.0f;
+    lr1.vote = LayerVoteType::ExplicitDefault;
+    lr1.name = "24Hz ExplicitDefault";
+    lr2.desiredRefreshRate = 60.0f;
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.name = "60Hz Heuristic";
+    EXPECT_EQ(mExpected120Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.desiredRefreshRate = 24.0f;
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.name = "24Hz ExplicitExactOrMultiple";
+    lr2.desiredRefreshRate = 60.0f;
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.name = "60Hz Heuristic";
+    EXPECT_EQ(mExpected120Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.desiredRefreshRate = 24.0f;
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.name = "24Hz ExplicitExactOrMultiple";
+    lr2.desiredRefreshRate = 60.0f;
+    lr2.vote = LayerVoteType::ExplicitDefault;
+    lr2.name = "60Hz ExplicitDefault";
+    EXPECT_EQ(mExpected120Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.desiredRefreshRate = 24.0f;
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.name = "24Hz ExplicitExactOrMultiple";
+    lr2.desiredRefreshRate = 90.0f;
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.name = "90Hz Heuristic";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.desiredRefreshRate = 24.0f;
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.name = "24Hz ExplicitExactOrMultiple";
+    lr2.desiredRefreshRate = 90.0f;
+    lr2.vote = LayerVoteType::ExplicitDefault;
+    lr2.name = "90Hz Heuristic";
+    EXPECT_EQ(mExpected72Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.desiredRefreshRate = 24.0f;
+    lr1.vote = LayerVoteType::ExplicitDefault;
+    lr1.name = "24Hz ExplicitDefault";
+    lr2.desiredRefreshRate = 90.0f;
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.name = "90Hz Heuristic";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.desiredRefreshRate = 24.0f;
+    lr1.vote = LayerVoteType::Heuristic;
+    lr1.name = "24Hz Heuristic";
+    lr2.desiredRefreshRate = 90.0f;
+    lr2.vote = LayerVoteType::ExplicitDefault;
+    lr2.name = "90Hz ExplicitDefault";
+    EXPECT_EQ(mExpected72Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.desiredRefreshRate = 24.0f;
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.name = "24Hz ExplicitExactOrMultiple";
+    lr2.desiredRefreshRate = 90.0f;
+    lr2.vote = LayerVoteType::ExplicitDefault;
+    lr2.name = "90Hz ExplicitDefault";
+    EXPECT_EQ(mExpected72Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.desiredRefreshRate = 24.0f;
+    lr1.vote = LayerVoteType::ExplicitDefault;
+    lr1.name = "24Hz ExplicitDefault";
+    lr2.desiredRefreshRate = 90.0f;
+    lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr2.name = "90Hz ExplicitExactOrMultiple";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m30_60Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    lr.vote = LayerVoteType::Min;
+    EXPECT_EQ(mExpected30Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.vote = LayerVoteType::Max;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 90.0f;
+    lr.vote = LayerVoteType::Heuristic;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 60.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 45.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 30.0f;
+    EXPECT_EQ(mExpected30Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 24.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_30_60_72_90) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m30_60_72_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    lr.vote = LayerVoteType::Min;
+    lr.name = "Min";
+    EXPECT_EQ(mExpected30Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.vote = LayerVoteType::Max;
+    lr.name = "Max";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 90.0f;
+    lr.vote = LayerVoteType::Heuristic;
+    lr.name = "90Hz Heuristic";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz Heuristic";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+
+    lr.desiredRefreshRate = 45.0f;
+    lr.name = "45Hz Heuristic";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+
+    lr.desiredRefreshRate = 30.0f;
+    lr.name = "30Hz Heuristic";
+    EXPECT_EQ(mExpected30Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+
+    lr.desiredRefreshRate = 24.0f;
+    lr.name = "24Hz Heuristic";
+    EXPECT_EQ(mExpected72Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+
+    lr.desiredRefreshRate = 24.0f;
+    lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr.name = "24Hz ExplicitExactOrMultiple";
+    EXPECT_EQ(mExpected72Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_PriorityTest) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m30_60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+                                                LayerRequirement{.weight = 1.0f}};
+    auto& lr1 = layers[0];
+    auto& lr2 = layers[1];
+
+    lr1.vote = LayerVoteType::Min;
+    lr2.vote = LayerVoteType::Max;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.vote = LayerVoteType::Min;
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.desiredRefreshRate = 24.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.vote = LayerVoteType::Min;
+    lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr2.desiredRefreshRate = 24.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.vote = LayerVoteType::Max;
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.desiredRefreshRate = 60.0f;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.vote = LayerVoteType::Max;
+    lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr2.desiredRefreshRate = 60.0f;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.vote = LayerVoteType::Heuristic;
+    lr1.desiredRefreshRate = 15.0f;
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.desiredRefreshRate = 45.0f;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.vote = LayerVoteType::Heuristic;
+    lr1.desiredRefreshRate = 30.0f;
+    lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr2.desiredRefreshRate = 45.0f;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_24FpsVideo) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+    for (float fps = 23.0f; fps < 25.0f; fps += 0.1f) {
+        lr.desiredRefreshRate = fps;
+        const auto& refreshRate =
+                refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
+        EXPECT_EQ(mExpected60Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
+    }
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getRefreshRateForContent_Explicit) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+                                                LayerRequirement{.weight = 1.0f}};
+    auto& lr1 = layers[0];
+    auto& lr2 = layers[1];
+
+    lr1.vote = LayerVoteType::Heuristic;
+    lr1.desiredRefreshRate = 60.0f;
+    lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr2.desiredRefreshRate = 90.0f;
+    EXPECT_EQ(mExpected90Config, refreshRateConfigs->getRefreshRateForContent(layers));
+
+    lr1.vote = LayerVoteType::Heuristic;
+    lr1.desiredRefreshRate = 90.0f;
+    lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr2.desiredRefreshRate = 60.0f;
+    EXPECT_EQ(mExpected60Config, refreshRateConfigs->getRefreshRateForContent(layers));
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_getBestRefreshRate_Explicit) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+                                                LayerRequirement{.weight = 1.0f}};
+    auto& lr1 = layers[0];
+    auto& lr2 = layers[1];
+
+    lr1.vote = LayerVoteType::Heuristic;
+    lr1.desiredRefreshRate = 60.0f;
+    lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr2.desiredRefreshRate = 90.0f;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.vote = LayerVoteType::ExplicitDefault;
+    lr1.desiredRefreshRate = 90.0f;
+    lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr2.desiredRefreshRate = 60.0f;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.vote = LayerVoteType::Heuristic;
+    lr1.desiredRefreshRate = 90.0f;
+    lr2.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr2.desiredRefreshRate = 60.0f;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, testInPolicy) {
+    ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(60.000004f, 60.000004f));
+    ASSERT_TRUE(mExpectedAlmost60Config.inPolicy(59.0f, 60.1f));
+    ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(75.0f, 90.0f));
+    ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(60.0011f, 90.0f));
+    ASSERT_FALSE(mExpectedAlmost60Config.inPolicy(50.0f, 59.998f));
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_75HzContent) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+    for (float fps = 75.0f; fps < 100.0f; fps += 0.1f) {
+        lr.desiredRefreshRate = fps;
+        const auto& refreshRate =
+                refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
+        EXPECT_EQ(mExpected90Config, refreshRate) << fps << "Hz chooses " << refreshRate.getName();
+    }
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_Multiples) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+                                                LayerRequirement{.weight = 1.0f}};
+    auto& lr1 = layers[0];
+    auto& lr2 = layers[1];
+
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.desiredRefreshRate = 60.0f;
+    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.desiredRefreshRate = 90.0f;
+    lr2.name = "90Hz Heuristic";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.desiredRefreshRate = 60.0f;
+    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::ExplicitDefault;
+    lr2.desiredRefreshRate = 90.0f;
+    lr2.name = "90Hz ExplicitDefault";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.desiredRefreshRate = 60.0f;
+    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::Max;
+    lr2.name = "Max";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.desiredRefreshRate = 30.0f;
+    lr1.name = "30Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.desiredRefreshRate = 90.0f;
+    lr2.name = "90Hz Heuristic";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.desiredRefreshRate = 30.0f;
+    lr1.name = "30Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::Max;
+    lr2.name = "Max";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, scrollWhileWatching60fps_60_90) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+                                                LayerRequirement{.weight = 1.0f}};
+    auto& lr1 = layers[0];
+    auto& lr2 = layers[1];
+
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.desiredRefreshRate = 60.0f;
+    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::NoVote;
+    lr2.name = "NoVote";
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.desiredRefreshRate = 60.0f;
+    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::NoVote;
+    lr2.name = "NoVote";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.desiredRefreshRate = 60.0f;
+    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::Max;
+    lr2.name = "Max";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false}));
+
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.desiredRefreshRate = 60.0f;
+    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::Max;
+    lr2.name = "Max";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    // The other layer starts to provide buffers
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.desiredRefreshRate = 60.0f;
+    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.desiredRefreshRate = 90.0f;
+    lr2.name = "90Hz Heuristic";
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, touchConsidered) {
+    RefreshRateConfigs::GlobalSignals consideredSignals;
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false}, &consideredSignals);
+    EXPECT_EQ(false, consideredSignals.touch);
+
+    refreshRateConfigs->getBestRefreshRate({}, {.touch = true, .idle = false}, &consideredSignals);
+    EXPECT_EQ(true, consideredSignals.touch);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f},
+                                                LayerRequirement{.weight = 1.0f}};
+    auto& lr1 = layers[0];
+    auto& lr2 = layers[1];
+
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.desiredRefreshRate = 60.0f;
+    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.desiredRefreshRate = 60.0f;
+    lr2.name = "60Hz Heuristic";
+    refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
+                                           &consideredSignals);
+    EXPECT_EQ(true, consideredSignals.touch);
+
+    lr1.vote = LayerVoteType::ExplicitDefault;
+    lr1.desiredRefreshRate = 60.0f;
+    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.desiredRefreshRate = 60.0f;
+    lr2.name = "60Hz Heuristic";
+    refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
+                                           &consideredSignals);
+    EXPECT_EQ(false, consideredSignals.touch);
+
+    lr1.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr1.desiredRefreshRate = 60.0f;
+    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.desiredRefreshRate = 60.0f;
+    lr2.name = "60Hz Heuristic";
+    refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
+                                           &consideredSignals);
+    EXPECT_EQ(true, consideredSignals.touch);
+
+    lr1.vote = LayerVoteType::ExplicitDefault;
+    lr1.desiredRefreshRate = 60.0f;
+    lr1.name = "60Hz ExplicitExactOrMultiple";
+    lr2.vote = LayerVoteType::Heuristic;
+    lr2.desiredRefreshRate = 60.0f;
+    lr2.name = "60Hz Heuristic";
+    refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = false},
+                                           &consideredSignals);
+    EXPECT_EQ(false, consideredSignals.touch);
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_ExplicitDefault) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90_72_120Device, /*currentConfigId=*/
+                                                 HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    // Prepare a table with the vote and the expected refresh rate
+    const std::vector<std::pair<float, float>> testCases = {
+            {130, 120}, {120, 120}, {119, 120}, {110, 120},
+
+            {100, 90},  {90, 90},   {89, 90},
+
+            {80, 72},   {73, 72},   {72, 72},   {71, 72},   {70, 72},
+
+            {65, 60},   {60, 60},   {59, 60},   {58, 60},
+
+            {55, 90},   {50, 90},   {45, 90},
+
+            {42, 120},  {40, 120},  {39, 120},
+
+            {37, 72},   {36, 72},   {35, 72},
+
+            {30, 60},
+    };
+
+    for (const auto& test : testCases) {
+        lr.vote = LayerVoteType::ExplicitDefault;
+        lr.desiredRefreshRate = test.first;
+
+        std::stringstream ss;
+        ss << "ExplicitDefault " << test.first << " fps";
+        lr.name = ss.str();
+
+        const auto& refreshRate =
+                refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
+        EXPECT_FLOAT_EQ(refreshRate.getFps(), test.second)
+                << "Expecting " << test.first << "fps => " << test.second << "Hz";
+    }
+}
+
+TEST_F(RefreshRateConfigsTest,
+       getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresTouchFlag) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_90);
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_90, {90.f, 90.f}, {60.f, 90.f}}),
+              0);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    RefreshRateConfigs::GlobalSignals consideredSignals;
+    lr.vote = LayerVoteType::ExplicitDefault;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz ExplicitDefault";
+    lr.focused = true;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = true},
+                                                     &consideredSignals));
+    EXPECT_EQ(false, consideredSignals.touch);
+}
+
+TEST_F(RefreshRateConfigsTest,
+       getBestRefreshRate_withDisplayManagerRequestingSingleRate_ignoresIdleFlag) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 90.f}}),
+              0);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    lr.vote = LayerVoteType::ExplicitDefault;
+    lr.desiredRefreshRate = 90.0f;
+    lr.name = "90Hz ExplicitDefault";
+    lr.focused = true;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = true}));
+}
+
+TEST_F(RefreshRateConfigsTest,
+       getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitFocusedLayers) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_90);
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_90, {90.f, 90.f}, {60.f, 90.f}}),
+              0);
+
+    RefreshRateConfigs::GlobalSignals consideredSignals;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false},
+                                                     &consideredSignals));
+    EXPECT_EQ(false, consideredSignals.touch);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& lr = layers[0];
+
+    lr.vote = LayerVoteType::ExplicitExactOrMultiple;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz ExplicitExactOrMultiple";
+    lr.focused = false;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.focused = true;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.vote = LayerVoteType::ExplicitDefault;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz ExplicitDefault";
+    lr.focused = false;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.focused = true;
+    EXPECT_EQ(mExpected60Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.vote = LayerVoteType::Heuristic;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz Heuristic";
+    lr.focused = false;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.focused = true;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.vote = LayerVoteType::Max;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz Max";
+    lr.focused = false;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.focused = true;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.vote = LayerVoteType::Min;
+    lr.desiredRefreshRate = 60.0f;
+    lr.name = "60Hz Min";
+    lr.focused = false;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.focused = true;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+}
+
+TEST_F(RefreshRateConfigsTest, groupSwitching) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90DeviceWithDifferentGroups,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& layer = layers[0];
+    layer.vote = LayerVoteType::ExplicitDefault;
+    layer.desiredRefreshRate = 90.0f;
+    layer.name = "90Hz ExplicitDefault";
+
+    ASSERT_EQ(HWC_CONFIG_ID_60,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+                      .getConfigId());
+
+    RefreshRateConfigs::Policy policy;
+    policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig;
+    policy.allowGroupSwitching = true;
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
+    ASSERT_EQ(HWC_CONFIG_ID_90,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
+                      .getConfigId());
+}
+
+TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m30_60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    layers[0].name = "Test layer";
+
+    // Return the config ID from calling getBestRefreshRate() for a single layer with the
+    // given voteType and fps.
+    auto getFrameRate = [&](LayerVoteType voteType, float fps, bool touchActive = false,
+                            bool focused = true) -> HwcConfigIndexType {
+        layers[0].vote = voteType;
+        layers[0].desiredRefreshRate = fps;
+        layers[0].focused = focused;
+        return refreshRateConfigs->getBestRefreshRate(layers, {.touch = touchActive, .idle = false})
+                .getConfigId();
+    };
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_60, {30.f, 60.f}, {30.f, 90.f}}),
+              0);
+    EXPECT_EQ(HWC_CONFIG_ID_60,
+              refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false})
+                      .getConfigId());
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_30, getFrameRate(LayerVoteType::Min, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
+
+    // Layers not focused are not allowed to override primary config
+    EXPECT_EQ(HWC_CONFIG_ID_60,
+              getFrameRate(LayerVoteType::ExplicitDefault, 90.f, /*touch=*/false,
+                           /*focused=*/false));
+    EXPECT_EQ(HWC_CONFIG_ID_60,
+              getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f, /*touch=*/false,
+                           /*focused=*/false));
+
+    // Touch boost should be restricted to the primary range.
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f, /*touch=*/true));
+    // When we're higher than the primary range max due to a layer frame rate setting, touch boost
+    // shouldn't drag us back down to the primary range max.
+    EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f, /*touch=*/true));
+    EXPECT_EQ(HWC_CONFIG_ID_60,
+              getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f, /*touch=*/true));
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_60, {60.f, 60.f}, {60.f, 60.f}}),
+              0);
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Min, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Heuristic, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
+}
+
+TEST_F(RefreshRateConfigsTest, idle) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    layers[0].name = "Test layer";
+
+    const auto getIdleFrameRate = [&](LayerVoteType voteType,
+                                      bool touchActive) -> HwcConfigIndexType {
+        layers[0].vote = voteType;
+        layers[0].desiredRefreshRate = 90.f;
+        RefreshRateConfigs::GlobalSignals consideredSignals;
+        const auto configId =
+                refreshRateConfigs
+                        ->getBestRefreshRate(layers, {.touch = touchActive, .idle = true},
+                                             &consideredSignals)
+                        .getConfigId();
+        // Refresh rate will be chosen by either touch state or idle state
+        EXPECT_EQ(!touchActive, consideredSignals.idle);
+        return configId;
+    };
+
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
+                      {HWC_CONFIG_ID_60, {60.f, 90.f}, {60.f, 90.f}}),
+              0);
+
+    // Idle should be lower priority than touch boost.
+    EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::NoVote, /*touchActive=*/true));
+    EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::Min, /*touchActive=*/true));
+    EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::Max, /*touchActive=*/true));
+    EXPECT_EQ(HWC_CONFIG_ID_90, getIdleFrameRate(LayerVoteType::Heuristic, /*touchActive=*/true));
+    EXPECT_EQ(HWC_CONFIG_ID_90,
+              getIdleFrameRate(LayerVoteType::ExplicitDefault, /*touchActive=*/true));
+    EXPECT_EQ(HWC_CONFIG_ID_90,
+              getIdleFrameRate(LayerVoteType::ExplicitExactOrMultiple, /*touchActive=*/true));
+
+    // With no layers, idle should still be lower priority than touch boost.
+    EXPECT_EQ(HWC_CONFIG_ID_90,
+              refreshRateConfigs->getBestRefreshRate({}, {.touch = true, .idle = true})
+                      .getConfigId());
+
+    // Idle should be higher precedence than other layer frame rate considerations.
+    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+    EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::NoVote, /*touchActive=*/false));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::Min, /*touchActive=*/false));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::Max, /*touchActive=*/false));
+    EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::Heuristic, /*touchActive=*/false));
+    EXPECT_EQ(HWC_CONFIG_ID_60,
+              getIdleFrameRate(LayerVoteType::ExplicitDefault, /*touchActive=*/false));
+    EXPECT_EQ(HWC_CONFIG_ID_60,
+              getIdleFrameRate(LayerVoteType::ExplicitExactOrMultiple, /*touchActive=*/false));
+
+    // Idle should be applied rather than the current config when there are no layers.
+    EXPECT_EQ(HWC_CONFIG_ID_60,
+              refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = true})
+                      .getConfigId());
+}
+
+TEST_F(RefreshRateConfigsTest, findClosestKnownFrameRate) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    for (float fps = 1.0f; fps <= 120.0f; fps += 0.1f) {
+        const auto knownFrameRate = findClosestKnownFrameRate(*refreshRateConfigs, fps);
+        float expectedFrameRate;
+        if (fps < 26.91f) {
+            expectedFrameRate = 24.0f;
+        } else if (fps < 37.51f) {
+            expectedFrameRate = 30.0f;
+        } else if (fps < 52.51f) {
+            expectedFrameRate = 45.0f;
+        } else if (fps < 66.01f) {
+            expectedFrameRate = 60.0f;
+        } else if (fps < 81.01f) {
+            expectedFrameRate = 72.0f;
+        } else {
+            expectedFrameRate = 90.0f;
+        }
+        EXPECT_FLOAT_EQ(expectedFrameRate, knownFrameRate)
+                << "findClosestKnownFrameRate(" << fps << ") = " << knownFrameRate;
+    }
+}
+
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_KnownFrameRate) {
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_60);
+
+    struct ExpectedRate {
+        float rate;
+        const RefreshRate& expected;
+    };
+
+    /* clang-format off */
+    std::vector<ExpectedRate> knownFrameRatesExpectations = {
+        {24.0f, mExpected60Config},
+        {30.0f, mExpected60Config},
+        {45.0f, mExpected90Config},
+        {60.0f, mExpected60Config},
+        {72.0f, mExpected90Config},
+        {90.0f, mExpected90Config},
+    };
+    /* clang-format on */
+
+    // Make sure the test tests all the known frame rate
+    const auto knownFrameRateList = getKnownFrameRate(*refreshRateConfigs);
+    const auto equal = std::equal(knownFrameRateList.begin(), knownFrameRateList.end(),
+                                  knownFrameRatesExpectations.begin(),
+                                  [](float a, const ExpectedRate& b) { return a == b.rate; });
+    EXPECT_TRUE(equal);
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    auto& layer = layers[0];
+    layer.vote = LayerVoteType::Heuristic;
+    for (const auto& expectedRate : knownFrameRatesExpectations) {
+        layer.desiredRefreshRate = expectedRate.rate;
+        const auto& refreshRate =
+                refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false});
+        EXPECT_EQ(expectedRate.expected, refreshRate);
+    }
+}
+
+TEST_F(RefreshRateConfigsTest, testComparisonOperator) {
+    EXPECT_TRUE(mExpected60Config < mExpected90Config);
+    EXPECT_FALSE(mExpected60Config < mExpected60Config);
+    EXPECT_FALSE(mExpected90Config < mExpected90Config);
+}
+
+TEST_F(RefreshRateConfigsTest, testKernelIdleTimerAction) {
+    using KernelIdleTimerAction = scheduler::RefreshRateConfigs::KernelIdleTimerAction;
+
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(m60_90Device,
+                                                 /*currentConfigId=*/HWC_CONFIG_ID_90);
+    // SetPolicy(60, 90), current 90Hz => TurnOn.
+    EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
+
+    // SetPolicy(60, 90), current 60Hz => TurnOn.
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 90}}), 0);
+    EXPECT_EQ(KernelIdleTimerAction::TurnOn, refreshRateConfigs->getIdleTimerAction());
+
+    // SetPolicy(60, 60), current 60Hz => NoChange, avoid extra calls.
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_60, {60, 60}}), 0);
+    EXPECT_EQ(KernelIdleTimerAction::NoChange, refreshRateConfigs->getIdleTimerAction());
+
+    // SetPolicy(90, 90), current 90Hz => TurnOff.
+    ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {90, 90}}), 0);
+    EXPECT_EQ(KernelIdleTimerAction::TurnOff, refreshRateConfigs->getIdleTimerAction());
+}
+
 } // namespace
 } // namespace scheduler
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
new file mode 100644
index 0000000..43b8e01
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -0,0 +1,288 @@
+/*
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerMetadata.h>
+
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
+#include "EffectLayer.h"
+#include "Layer.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+
+namespace android {
+
+using testing::_;
+using testing::DoAll;
+using testing::Mock;
+using testing::Return;
+using testing::SetArgPointee;
+
+using android::Hwc2::IComposer;
+using android::Hwc2::IComposerClient;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+/**
+ * This class covers all the test that are related to refresh rate selection.
+ */
+class RefreshRateSelectionTest : public testing::Test {
+public:
+    RefreshRateSelectionTest();
+    ~RefreshRateSelectionTest() override;
+
+protected:
+    static constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
+    static constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
+    static constexpr uint32_t WIDTH = 100;
+    static constexpr uint32_t HEIGHT = 100;
+    static constexpr uint32_t LAYER_FLAGS = 0;
+    static constexpr int32_t PRIORITY_UNSET = -1;
+
+    void setupScheduler();
+    void setupComposer(int virtualDisplayCount);
+    sp<BufferQueueLayer> createBufferQueueLayer();
+    sp<BufferStateLayer> createBufferStateLayer();
+    sp<EffectLayer> createEffectLayer();
+
+    void setParent(Layer* child, Layer* parent);
+    void commitTransaction(Layer* layer);
+
+    TestableSurfaceFlinger mFlinger;
+    Hwc2::mock::Composer* mComposer = nullptr;
+
+    sp<Client> mClient;
+    sp<Layer> mParent;
+    sp<Layer> mChild;
+    sp<Layer> mGrandChild;
+};
+
+RefreshRateSelectionTest::RefreshRateSelectionTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+    setupScheduler();
+    setupComposer(0);
+}
+
+RefreshRateSelectionTest::~RefreshRateSelectionTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+sp<BufferQueueLayer> RefreshRateSelectionTest::createBufferQueueLayer() {
+    sp<Client> client;
+    LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+                           LAYER_FLAGS, LayerMetadata());
+    return new BufferQueueLayer(args);
+}
+
+sp<BufferStateLayer> RefreshRateSelectionTest::createBufferStateLayer() {
+    sp<Client> client;
+    LayerCreationArgs args(mFlinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+                           LAYER_FLAGS, LayerMetadata());
+    return new BufferStateLayer(args);
+}
+
+sp<EffectLayer> RefreshRateSelectionTest::createEffectLayer() {
+    sp<Client> client;
+    LayerCreationArgs args(mFlinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS,
+                           LayerMetadata());
+    return new EffectLayer(args);
+}
+
+void RefreshRateSelectionTest::setParent(Layer* child, Layer* parent) {
+    child->setParent(parent);
+}
+
+void RefreshRateSelectionTest::commitTransaction(Layer* layer) {
+    layer->commitTransaction(layer->getCurrentState());
+}
+
+void RefreshRateSelectionTest::setupScheduler() {
+    auto eventThread = std::make_unique<mock::EventThread>();
+    auto sfEventThread = std::make_unique<mock::EventThread>();
+
+    EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+    EXPECT_CALL(*eventThread, createEventConnection(_, _))
+            .WillOnce(Return(new EventThreadConnection(eventThread.get(), ResyncCallback(),
+                                                       ISurfaceComposer::eConfigChangedSuppress)));
+
+    EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+    EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+            .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
+                                                       ISurfaceComposer::eConfigChangedSuppress)));
+
+    auto primaryDispSync = std::make_unique<mock::DispSync>();
+
+    EXPECT_CALL(*primaryDispSync, computeNextRefresh(0, _)).WillRepeatedly(Return(0));
+    EXPECT_CALL(*primaryDispSync, getPeriod())
+            .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+    EXPECT_CALL(*primaryDispSync, expectedPresentTime(_)).WillRepeatedly(Return(0));
+    mFlinger.setupScheduler(std::move(primaryDispSync),
+                            std::make_unique<mock::EventControlThread>(), std::move(eventThread),
+                            std::move(sfEventThread));
+}
+
+void RefreshRateSelectionTest::setupComposer(int virtualDisplayCount) {
+    mComposer = new Hwc2::mock::Composer();
+    EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+    mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+    Mock::VerifyAndClear(mComposer);
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(RefreshRateSelectionTest, testPriorityOnBufferQueueLayers) {
+    mParent = createBufferQueueLayer();
+    mChild = createBufferQueueLayer();
+    setParent(mChild.get(), mParent.get());
+    mGrandChild = createBufferQueueLayer();
+    setParent(mGrandChild.get(), mChild.get());
+
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mGrandChild->getFrameRateSelectionPriority());
+
+    // Child has its own priority.
+    mGrandChild->setFrameRateSelectionPriority(1);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+    // Child inherits from his parent.
+    mChild->setFrameRateSelectionPriority(1);
+    commitTransaction(mChild.get());
+    mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mGrandChild.get());
+
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+    // Grandchild inherits from his grand parent.
+    mParent->setFrameRateSelectionPriority(1);
+    commitTransaction(mParent.get());
+    mChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mChild.get());
+    mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(1, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+}
+
+TEST_F(RefreshRateSelectionTest, testPriorityOnBufferStateLayers) {
+    mParent = createBufferStateLayer();
+    mChild = createBufferStateLayer();
+    setParent(mChild.get(), mParent.get());
+    mGrandChild = createBufferStateLayer();
+    setParent(mGrandChild.get(), mChild.get());
+
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mGrandChild->getFrameRateSelectionPriority());
+
+    // Child has its own priority.
+    mGrandChild->setFrameRateSelectionPriority(1);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+    // Child inherits from his parent.
+    mChild->setFrameRateSelectionPriority(1);
+    commitTransaction(mChild.get());
+    mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+    // Grandchild inherits from his grand parent.
+    mParent->setFrameRateSelectionPriority(1);
+    commitTransaction(mParent.get());
+    mChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mChild.get());
+    mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(1, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+}
+
+TEST_F(RefreshRateSelectionTest, testPriorityOnEffectLayers) {
+    mParent = createEffectLayer();
+    mChild = createEffectLayer();
+    setParent(mChild.get(), mParent.get());
+    mGrandChild = createEffectLayer();
+    setParent(mGrandChild.get(), mChild.get());
+
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mGrandChild->getFrameRateSelectionPriority());
+
+    // Child has its own priority.
+    mGrandChild->setFrameRateSelectionPriority(1);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(PRIORITY_UNSET, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+    // Child inherits from his parent.
+    mChild->setFrameRateSelectionPriority(1);
+    commitTransaction(mChild.get());
+    mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(PRIORITY_UNSET, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+
+    // Grandchild inherits from his grand parent.
+    mParent->setFrameRateSelectionPriority(1);
+    commitTransaction(mParent.get());
+    mChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mChild.get());
+    mGrandChild->setFrameRateSelectionPriority(PRIORITY_UNSET);
+    commitTransaction(mGrandChild.get());
+    ASSERT_EQ(1, mParent->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mChild->getFrameRateSelectionPriority());
+    ASSERT_EQ(1, mGrandChild->getFrameRateSelectionPriority());
+}
+
+} // namespace
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index cec0b32..de66f8f 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "SchedulerUnittests"
 
@@ -22,9 +26,11 @@
 #include <thread>
 
 #include "Scheduler/RefreshRateStats.h"
+#include "mock/DisplayHardware/MockDisplay.h"
 #include "mock/MockTimeStats.h"
 
 using namespace std::chrono_literals;
+using android::hardware::graphics::composer::hal::PowerMode;
 using testing::_;
 using testing::AtLeast;
 
@@ -33,26 +39,31 @@
 
 class RefreshRateStatsTest : public testing::Test {
 protected:
-    static constexpr int CONFIG_ID_90 = 0;
-    static constexpr int CONFIG_ID_60 = 1;
+    static inline const auto CONFIG_ID_0 = HwcConfigIndexType(0);
+    static inline const auto CONFIG_ID_1 = HwcConfigIndexType(1);
+    static inline const auto CONFIG_GROUP_0 = 0;
     static constexpr int64_t VSYNC_90 = 11111111;
     static constexpr int64_t VSYNC_60 = 16666667;
 
     RefreshRateStatsTest();
     ~RefreshRateStatsTest();
 
-    void init(const std::vector<RefreshRateConfigs::InputConfig>& configs) {
-        mRefreshRateConfigs = std::make_unique<RefreshRateConfigs>(
-                /*refreshRateSwitching=*/true, configs, /*currentConfig=*/0);
-        mRefreshRateStats =
-                std::make_unique<RefreshRateStats>(*mRefreshRateConfigs, mTimeStats,
-                                                   /*currentConfig=*/0,
-                                                   /*currentPowerMode=*/HWC_POWER_MODE_OFF);
+    void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
+        mRefreshRateConfigs =
+                std::make_unique<RefreshRateConfigs>(configs, /*currentConfig=*/CONFIG_ID_0);
+        mRefreshRateStats = std::make_unique<RefreshRateStats>(*mRefreshRateConfigs, mTimeStats,
+                                                               /*currentConfigId=*/CONFIG_ID_0,
+                                                               /*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);
 };
 
 RefreshRateStatsTest::RefreshRateStatsTest() {
@@ -67,12 +78,20 @@
     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, configId.value())
+            .setVsyncPeriod(int32_t(vsyncPeriod))
+            .setConfigGroup(configGroup)
+            .build();
+}
+
 namespace {
 /* ------------------------------------------------------------------------
  * Test cases
  */
 TEST_F(RefreshRateStatsTest, oneConfigTest) {
-    init({{CONFIG_ID_90, VSYNC_90}});
+    init({createConfig(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90)});
 
     EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
     EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
@@ -91,8 +110,8 @@
     EXPECT_LT(screenOff, times["ScreenOff"]);
     EXPECT_EQ(0u, times.count("90fps"));
 
-    mRefreshRateStats->setConfigMode(CONFIG_ID_90);
-    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    mRefreshRateStats->setConfigMode(CONFIG_ID_0);
+    mRefreshRateStats->setPowerMode(PowerMode::ON);
     screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
@@ -100,25 +119,26 @@
     ASSERT_EQ(1u, times.count("90fps"));
     EXPECT_LT(0, times["90fps"]);
 
-    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
+    mRefreshRateStats->setPowerMode(PowerMode::DOZE);
     int ninety = mRefreshRateStats->getTotalTimes()["90fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
     EXPECT_LT(screenOff, times["ScreenOff"]);
     EXPECT_EQ(ninety, times["90fps"]);
 
-    mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+    mRefreshRateStats->setConfigMode(CONFIG_ID_0);
     screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
-    // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
+    // Because the power mode is not PowerMode::ON, switching the config
     // does not update refresh rates that come from the config.
     EXPECT_LT(screenOff, times["ScreenOff"]);
     EXPECT_EQ(ninety, times["90fps"]);
 }
 
 TEST_F(RefreshRateStatsTest, twoConfigsTest) {
-    init({{CONFIG_ID_90, VSYNC_90}, {CONFIG_ID_60, VSYNC_60}});
+    init({createConfig(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90),
+          createConfig(CONFIG_ID_1, CONFIG_GROUP_0, VSYNC_60)});
 
     EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
     EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1));
@@ -137,8 +157,8 @@
     times = mRefreshRateStats->getTotalTimes();
     EXPECT_LT(screenOff, times["ScreenOff"]);
 
-    mRefreshRateStats->setConfigMode(CONFIG_ID_90);
-    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+    mRefreshRateStats->setConfigMode(CONFIG_ID_0);
+    mRefreshRateStats->setPowerMode(PowerMode::ON);
     screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
@@ -147,7 +167,7 @@
     EXPECT_LT(0, times["90fps"]);
 
     // When power mode is normal, time for configs updates.
-    mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+    mRefreshRateStats->setConfigMode(CONFIG_ID_1);
     int ninety = mRefreshRateStats->getTotalTimes()["90fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
@@ -156,7 +176,7 @@
     ASSERT_EQ(1u, times.count("60fps"));
     EXPECT_LT(0, times["60fps"]);
 
-    mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+    mRefreshRateStats->setConfigMode(CONFIG_ID_0);
     int sixty = mRefreshRateStats->getTotalTimes()["60fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
@@ -164,7 +184,7 @@
     EXPECT_LT(ninety, times["90fps"]);
     EXPECT_EQ(sixty, times["60fps"]);
 
-    mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+    mRefreshRateStats->setConfigMode(CONFIG_ID_1);
     ninety = mRefreshRateStats->getTotalTimes()["90fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
@@ -172,10 +192,10 @@
     EXPECT_EQ(ninety, times["90fps"]);
     EXPECT_LT(sixty, times["60fps"]);
 
-    // Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
+    // Because the power mode is not PowerMode::ON, switching the config
     // does not update refresh rates that come from the config.
-    mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
-    mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+    mRefreshRateStats->setPowerMode(PowerMode::DOZE);
+    mRefreshRateStats->setConfigMode(CONFIG_ID_0);
     sixty = mRefreshRateStats->getTotalTimes()["60fps"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
@@ -183,7 +203,7 @@
     EXPECT_EQ(ninety, times["90fps"]);
     EXPECT_EQ(sixty, times["60fps"]);
 
-    mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+    mRefreshRateStats->setConfigMode(CONFIG_ID_1);
     screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
     std::this_thread::sleep_for(std::chrono::milliseconds(2));
     times = mRefreshRateStats->getTotalTimes();
@@ -194,3 +214,6 @@
 } // namespace
 } // namespace scheduler
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
index 160f041..f19e554 100644
--- a/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RegionSamplingTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "RegionSamplingTest"
 
@@ -69,16 +73,16 @@
         n++;
         return pixel;
     });
+
     EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, whole_area),
-                testing::FloatNear(0.083f, 0.01f));
+                testing::FloatNear(0.16f, 0.01f));
 }
 
 TEST_F(RegionSamplingTest, bimodal_tiebreaker) {
     std::generate(buffer.begin(), buffer.end(),
                   [n = 0]() mutable { return (n++ % 2) ? kBlack : kWhite; });
-    // presently there's no tiebreaking strategy in place, accept either of the means
     EXPECT_THAT(sampleArea(buffer.data(), kWidth, kHeight, kStride, kOrientation, whole_area),
-                testing::AnyOf(testing::FloatEq(1.0), testing::FloatEq(0.0f)));
+                testing::FloatEq(0.5f));
 }
 
 TEST_F(RegionSamplingTest, bounds_checking) {
@@ -137,3 +141,6 @@
 }
 
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 571fdfd..1aa7320 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -1,3 +1,23 @@
+/*
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "SchedulerUnittests"
 
@@ -10,7 +30,8 @@
 #include "Scheduler/EventControlThread.h"
 #include "Scheduler/EventThread.h"
 #include "Scheduler/RefreshRateConfigs.h"
-#include "Scheduler/Scheduler.h"
+#include "TestableScheduler.h"
+#include "mock/DisplayHardware/MockDisplay.h"
 #include "mock/MockEventThread.h"
 
 using testing::_;
@@ -34,38 +55,16 @@
         MOCK_METHOD0(requestNextVsync, void());
     };
 
-    std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
-
-    /**
-     * This mock Scheduler class uses implementation of mock::EventThread but keeps everything else
-     * the same.
-     */
-    class MockScheduler : public android::Scheduler {
-    public:
-        MockScheduler(const scheduler::RefreshRateConfigs& refreshRateConfigs,
-                      std::unique_ptr<EventThread> eventThread)
-              : Scheduler([](bool) {}, refreshRateConfigs), mEventThread(std::move(eventThread)) {}
-
-        std::unique_ptr<EventThread> makeEventThread(
-                const char* /* connectionName */, DispSync* /* dispSync */,
-                nsecs_t /* phaseOffsetNs */, nsecs_t /* offsetThresholdForNextVsync */,
-                impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
-            return std::move(mEventThread);
-        }
-
-        MockScheduler() = default;
-        ~MockScheduler() override = default;
-
-        std::unique_ptr<EventThread> mEventThread;
-    };
-
     SchedulerTest();
     ~SchedulerTest() override;
 
-    sp<Scheduler::ConnectionHandle> mConnectionHandle;
+    std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
+    std::unique_ptr<TestableScheduler> mScheduler;
+
+    Scheduler::ConnectionHandle mConnectionHandle;
     mock::EventThread* mEventThread;
-    std::unique_ptr<MockScheduler> mScheduler;
     sp<MockEventThreadConnection> mEventThreadConnection;
+    Hwc2::mock::Display mDisplay;
 };
 
 SchedulerTest::SchedulerTest() {
@@ -73,14 +72,18 @@
             ::testing::UnitTest::GetInstance()->current_test_info();
     ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
 
-    std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}};
-    mRefreshRateConfigs =
-            std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
-                                                            /*currentConfig=*/0);
+    std::vector<std::shared_ptr<const HWC2::Display::Config>> configs{
+            HWC2::Display::Config::Builder(mDisplay, 0)
+                    .setVsyncPeriod(int32_t(16666667))
+                    .setConfigGroup(0)
+                    .build()};
+    mRefreshRateConfigs = std::make_unique<
+            scheduler::RefreshRateConfigs>(configs, /*currentConfig=*/HwcConfigIndexType(0));
 
-    std::unique_ptr<mock::EventThread> eventThread = std::make_unique<mock::EventThread>();
+    mScheduler = std::make_unique<TestableScheduler>(*mRefreshRateConfigs, false);
+
+    auto eventThread = std::make_unique<mock::EventThread>();
     mEventThread = eventThread.get();
-    mScheduler = std::make_unique<MockScheduler>(*mRefreshRateConfigs, std::move(eventThread));
     EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0));
 
     mEventThreadConnection = new MockEventThreadConnection(mEventThread);
@@ -90,9 +93,8 @@
     EXPECT_CALL(*mEventThread, createEventConnection(_, _))
             .WillRepeatedly(Return(mEventThreadConnection));
 
-    mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16,
-                                                     impl::EventThread::InterceptVSyncsCallback());
-    EXPECT_TRUE(mConnectionHandle != nullptr);
+    mConnectionHandle = mScheduler->createConnection(std::move(eventThread));
+    EXPECT_TRUE(mConnectionHandle);
 }
 
 SchedulerTest::~SchedulerTest() {
@@ -106,78 +108,48 @@
  * Test cases
  */
 
-TEST_F(SchedulerTest, testNullPtr) {
-    // Passing a null pointer for ConnectionHandle is a valid argument. The code doesn't throw any
-    // exceptions, just gracefully continues.
-    sp<IDisplayEventConnection> returnedValue;
-    ASSERT_NO_FATAL_FAILURE(
-            returnedValue =
-                    mScheduler->createDisplayEventConnection(nullptr,
-                                                             ISurfaceComposer::
-                                                                     eConfigChangedSuppress));
-    EXPECT_TRUE(returnedValue == nullptr);
-    EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
-    EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
-    ASSERT_NO_FATAL_FAILURE(mScheduler->hotplugReceived(nullptr, PHYSICAL_DISPLAY_ID, false));
-    ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(nullptr));
-    ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(nullptr));
-    std::string testString;
-    ASSERT_NO_FATAL_FAILURE(mScheduler->dump(nullptr, testString));
-    EXPECT_TRUE(testString == "");
-    ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(nullptr, 10));
-}
-
 TEST_F(SchedulerTest, invalidConnectionHandle) {
-    // Passing an invalid ConnectionHandle is a valid argument. The code doesn't throw any
-    // exceptions, just gracefully continues.
-    sp<Scheduler::ConnectionHandle> connectionHandle = new Scheduler::ConnectionHandle(20);
+    Scheduler::ConnectionHandle handle;
 
-    sp<IDisplayEventConnection> returnedValue;
+    sp<IDisplayEventConnection> connection;
     ASSERT_NO_FATAL_FAILURE(
-            returnedValue =
-                    mScheduler->createDisplayEventConnection(connectionHandle,
-                                                             ISurfaceComposer::
-                                                                     eConfigChangedSuppress));
-    EXPECT_TRUE(returnedValue == nullptr);
-    EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr);
-    EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr);
+            connection = mScheduler->createDisplayEventConnection(handle,
+                                                                  ISurfaceComposer::
+                                                                          eConfigChangedSuppress));
+    EXPECT_FALSE(connection);
+    EXPECT_FALSE(mScheduler->getEventConnection(handle));
 
     // The EXPECT_CALLS make sure we don't call the functions on the subsequent event threads.
     EXPECT_CALL(*mEventThread, onHotplugReceived(_, _)).Times(0);
-    ASSERT_NO_FATAL_FAILURE(
-            mScheduler->hotplugReceived(connectionHandle, PHYSICAL_DISPLAY_ID, false));
+    ASSERT_NO_FATAL_FAILURE(mScheduler->onHotplugReceived(handle, PHYSICAL_DISPLAY_ID, false));
 
     EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0);
-    ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(connectionHandle));
+    ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(handle));
 
     EXPECT_CALL(*mEventThread, onScreenReleased()).Times(0);
-    ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(connectionHandle));
+    ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(handle));
 
-    std::string testString;
+    std::string output;
     EXPECT_CALL(*mEventThread, dump(_)).Times(0);
-    ASSERT_NO_FATAL_FAILURE(mScheduler->dump(connectionHandle, testString));
-    EXPECT_TRUE(testString == "");
+    ASSERT_NO_FATAL_FAILURE(mScheduler->dump(handle, output));
+    EXPECT_TRUE(output.empty());
 
     EXPECT_CALL(*mEventThread, setPhaseOffset(_)).Times(0);
-    ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(connectionHandle, 10));
+    ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(handle, 10));
 }
 
 TEST_F(SchedulerTest, validConnectionHandle) {
-    sp<IDisplayEventConnection> returnedValue;
+    sp<IDisplayEventConnection> connection;
     ASSERT_NO_FATAL_FAILURE(
-            returnedValue =
-                    mScheduler->createDisplayEventConnection(mConnectionHandle,
-                                                             ISurfaceComposer::
-                                                                     eConfigChangedSuppress));
-    EXPECT_TRUE(returnedValue != nullptr);
-    ASSERT_EQ(returnedValue, mEventThreadConnection);
-
-    EXPECT_TRUE(mScheduler->getEventThread(mConnectionHandle) != nullptr);
-    EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle) != nullptr);
+            connection = mScheduler->createDisplayEventConnection(mConnectionHandle,
+                                                                  ISurfaceComposer::
+                                                                          eConfigChangedSuppress));
+    ASSERT_EQ(mEventThreadConnection, connection);
+    EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle));
 
     EXPECT_CALL(*mEventThread, onHotplugReceived(PHYSICAL_DISPLAY_ID, false)).Times(1);
     ASSERT_NO_FATAL_FAILURE(
-            mScheduler->hotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false));
+            mScheduler->onHotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false));
 
     EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1);
     ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(mConnectionHandle));
@@ -185,13 +157,22 @@
     EXPECT_CALL(*mEventThread, onScreenReleased()).Times(1);
     ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(mConnectionHandle));
 
-    std::string testString("dump");
-    EXPECT_CALL(*mEventThread, dump(testString)).Times(1);
-    ASSERT_NO_FATAL_FAILURE(mScheduler->dump(mConnectionHandle, testString));
-    EXPECT_TRUE(testString != "");
+    std::string output("dump");
+    EXPECT_CALL(*mEventThread, dump(output)).Times(1);
+    ASSERT_NO_FATAL_FAILURE(mScheduler->dump(mConnectionHandle, output));
+    EXPECT_FALSE(output.empty());
 
     EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1);
     ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(mConnectionHandle, 10));
+
+    static constexpr size_t kEventConnections = 5;
+    ON_CALL(*mEventThread, getEventThreadConnectionCount())
+            .WillByDefault(Return(kEventConnections));
+    EXPECT_EQ(kEventConnections, mScheduler->getEventThreadConnectionCount(mConnectionHandle));
 }
+
 } // namespace
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp
index 5865579..5f6a715 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerUtilsTest.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "SchedulerUnittests"
 
@@ -128,4 +132,6 @@
 
 } // namespace
 } // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
new file mode 100644
index 0000000..0d6c799
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -0,0 +1,473 @@
+/*
+ * 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 "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerMetadata.h>
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+#include "BufferQueueLayer.h"
+#include "BufferStateLayer.h"
+#include "EffectLayer.h"
+#include "Layer.h"
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockMessageQueue.h"
+
+namespace android {
+
+using testing::_;
+using testing::DoAll;
+using testing::Mock;
+using testing::Return;
+using testing::SetArgPointee;
+
+using android::Hwc2::IComposer;
+using android::Hwc2::IComposerClient;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+using FrameRate = Layer::FrameRate;
+using FrameRateCompatibility = Layer::FrameRateCompatibility;
+
+class LayerFactory {
+public:
+    virtual ~LayerFactory() = default;
+
+    virtual std::string name() = 0;
+    virtual sp<Layer> createLayer(TestableSurfaceFlinger& flinger) = 0;
+
+protected:
+    static constexpr uint32_t WIDTH = 100;
+    static constexpr uint32_t HEIGHT = 100;
+    static constexpr uint32_t LAYER_FLAGS = 0;
+};
+
+class BufferQueueLayerFactory : public LayerFactory {
+public:
+    std::string name() override { return "BufferQueueLayer"; }
+    sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override {
+        sp<Client> client;
+        LayerCreationArgs args(flinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+                               LAYER_FLAGS, LayerMetadata());
+        return new BufferQueueLayer(args);
+    }
+};
+
+class BufferStateLayerFactory : public LayerFactory {
+public:
+    std::string name() override { return "BufferStateLayer"; }
+    sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override {
+        sp<Client> client;
+        LayerCreationArgs args(flinger.flinger(), client, "buffer-queue-layer", WIDTH, HEIGHT,
+                               LAYER_FLAGS, LayerMetadata());
+        return new BufferStateLayer(args);
+    }
+};
+
+class EffectLayerFactory : public LayerFactory {
+public:
+    std::string name() override { return "EffectLayer"; }
+    sp<Layer> createLayer(TestableSurfaceFlinger& flinger) override {
+        sp<Client> client;
+        LayerCreationArgs args(flinger.flinger(), client, "color-layer", WIDTH, HEIGHT, LAYER_FLAGS,
+                               LayerMetadata());
+        return new EffectLayer(args);
+    }
+};
+
+std::string PrintToStringParamName(
+        const ::testing::TestParamInfo<std::shared_ptr<LayerFactory>>& info) {
+    return info.param->name();
+}
+
+/**
+ * This class tests the behaviour of Layer::SetFrameRate and Layer::GetFrameRate
+ */
+class SetFrameRateTest : public ::testing::TestWithParam<std::shared_ptr<LayerFactory>> {
+protected:
+    const FrameRate FRAME_RATE_VOTE1 = FrameRate(67.f, FrameRateCompatibility::Default);
+    const FrameRate FRAME_RATE_VOTE2 = FrameRate(14.f, FrameRateCompatibility::ExactOrMultiple);
+    const FrameRate FRAME_RATE_VOTE3 = FrameRate(99.f, FrameRateCompatibility::NoVote);
+    const FrameRate FRAME_RATE_TREE = FrameRate(0, FrameRateCompatibility::NoVote);
+    const FrameRate FRAME_RATE_NO_VOTE = FrameRate(0, FrameRateCompatibility::Default);
+
+    SetFrameRateTest();
+
+    void setupScheduler();
+    void setupComposer(uint32_t virtualDisplayCount);
+
+    void addChild(sp<Layer> layer, sp<Layer> child);
+    void removeChild(sp<Layer> layer, sp<Layer> child);
+    void reparentChildren(sp<Layer> layer, sp<Layer> child);
+    void commitTransaction();
+
+    TestableSurfaceFlinger mFlinger;
+    Hwc2::mock::Composer* mComposer = nullptr;
+    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+
+    std::vector<sp<Layer>> mLayers;
+};
+
+SetFrameRateTest::SetFrameRateTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+    mFlinger.mutableUseFrameRateApi() = true;
+
+    setupScheduler();
+    setupComposer(0);
+
+    mFlinger.mutableEventQueue().reset(mMessageQueue);
+}
+void SetFrameRateTest::addChild(sp<Layer> layer, sp<Layer> child) {
+    layer.get()->addChild(child.get());
+}
+
+void SetFrameRateTest::removeChild(sp<Layer> layer, sp<Layer> child) {
+    layer.get()->removeChild(child.get());
+}
+
+void SetFrameRateTest::reparentChildren(sp<Layer> parent, sp<Layer> newParent) {
+    parent.get()->reparentChildren(newParent);
+}
+
+void SetFrameRateTest::commitTransaction() {
+    for (auto layer : mLayers) {
+        layer.get()->commitTransaction(layer.get()->getCurrentState());
+    }
+}
+
+void SetFrameRateTest::setupScheduler() {
+    auto eventThread = std::make_unique<mock::EventThread>();
+    auto sfEventThread = std::make_unique<mock::EventThread>();
+
+    EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+    EXPECT_CALL(*eventThread, createEventConnection(_, _))
+            .WillOnce(Return(new EventThreadConnection(eventThread.get(), ResyncCallback(),
+                                                       ISurfaceComposer::eConfigChangedSuppress)));
+
+    EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+    EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+            .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
+                                                       ISurfaceComposer::eConfigChangedSuppress)));
+
+    auto primaryDispSync = std::make_unique<mock::DispSync>();
+
+    EXPECT_CALL(*primaryDispSync, computeNextRefresh(0, _)).WillRepeatedly(Return(0));
+    EXPECT_CALL(*primaryDispSync, getPeriod())
+            .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+    EXPECT_CALL(*primaryDispSync, expectedPresentTime(_)).WillRepeatedly(Return(0));
+    mFlinger.setupScheduler(std::move(primaryDispSync),
+                            std::make_unique<mock::EventControlThread>(), std::move(eventThread),
+                            std::move(sfEventThread));
+}
+
+void SetFrameRateTest::setupComposer(uint32_t virtualDisplayCount) {
+    mComposer = new Hwc2::mock::Composer();
+    EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+    mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+    Mock::VerifyAndClear(mComposer);
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_P(SetFrameRateTest, SetAndGet) {
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    const auto& layerFactory = GetParam();
+
+    auto layer = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    layer->setFrameRate(FRAME_RATE_VOTE1);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_VOTE1, layer->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetParent) {
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    const auto& layerFactory = GetParam();
+
+    auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+    addChild(parent, child1);
+    addChild(child1, child2);
+
+    child2->setFrameRate(FRAME_RATE_VOTE1);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+    child2->setFrameRate(FRAME_RATE_NO_VOTE);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetParentAllVote) {
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    const auto& layerFactory = GetParam();
+
+    auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+    addChild(parent, child1);
+    addChild(child1, child2);
+
+    child2->setFrameRate(FRAME_RATE_VOTE1);
+    child1->setFrameRate(FRAME_RATE_VOTE2);
+    parent->setFrameRate(FRAME_RATE_VOTE3);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+    child2->setFrameRate(FRAME_RATE_NO_VOTE);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+    child1->setFrameRate(FRAME_RATE_NO_VOTE);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+    parent->setFrameRate(FRAME_RATE_NO_VOTE);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetChild) {
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    const auto& layerFactory = GetParam();
+
+    auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+    addChild(parent, child1);
+    addChild(child1, child2);
+
+    parent->setFrameRate(FRAME_RATE_VOTE1);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+    parent->setFrameRate(FRAME_RATE_NO_VOTE);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetChildAllVote) {
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    const auto& layerFactory = GetParam();
+
+    auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+    addChild(parent, child1);
+    addChild(child1, child2);
+
+    child2->setFrameRate(FRAME_RATE_VOTE1);
+    child1->setFrameRate(FRAME_RATE_VOTE2);
+    parent->setFrameRate(FRAME_RATE_VOTE3);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_VOTE3, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+    parent->setFrameRate(FRAME_RATE_NO_VOTE);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_VOTE2, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+    child1->setFrameRate(FRAME_RATE_NO_VOTE);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+    child2->setFrameRate(FRAME_RATE_NO_VOTE);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetChildAddAfterVote) {
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    const auto& layerFactory = GetParam();
+
+    auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+    addChild(parent, child1);
+
+    parent->setFrameRate(FRAME_RATE_VOTE1);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+
+    addChild(child1, child2);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+    parent->setFrameRate(FRAME_RATE_NO_VOTE);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetChildRemoveAfterVote) {
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    const auto& layerFactory = GetParam();
+
+    auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+    addChild(parent, child1);
+    addChild(child1, child2);
+
+    parent->setFrameRate(FRAME_RATE_VOTE1);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child2->getFrameRateForLayerTree());
+
+    removeChild(child1, child2);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_VOTE1, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+
+    parent->setFrameRate(FRAME_RATE_NO_VOTE);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetParentNotInTree) {
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    const auto& layerFactory = GetParam();
+
+    auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child2_1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+    addChild(parent, child1);
+    addChild(child1, child2);
+    addChild(child1, child2_1);
+
+    child2->setFrameRate(FRAME_RATE_VOTE1);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2_1->getFrameRateForLayerTree());
+
+    child2->setFrameRate(FRAME_RATE_NO_VOTE);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2_1->getFrameRateForLayerTree());
+}
+
+TEST_P(SetFrameRateTest, SetAndGetRearentChildren) {
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    const auto& layerFactory = GetParam();
+
+    auto parent = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto parent2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child1 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+    auto child2 = mLayers.emplace_back(layerFactory->createLayer(mFlinger));
+
+    addChild(parent, child1);
+    addChild(child1, child2);
+
+    child2->setFrameRate(FRAME_RATE_VOTE1);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_TREE, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, parent2->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+    reparentChildren(parent, parent2);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, parent2->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_TREE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_VOTE1, child2->getFrameRateForLayerTree());
+
+    child2->setFrameRate(FRAME_RATE_NO_VOTE);
+    commitTransaction();
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, parent->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, parent2->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child1->getFrameRateForLayerTree());
+    EXPECT_EQ(FRAME_RATE_NO_VOTE, child2->getFrameRateForLayerTree());
+}
+
+INSTANTIATE_TEST_SUITE_P(PerLayerType, SetFrameRateTest,
+                         testing::Values(std::make_shared<BufferQueueLayerFactory>(),
+                                         std::make_shared<BufferStateLayerFactory>(),
+                                         std::make_shared<EffectLayerFactory>()),
+                         PrintToStringParamName);
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp b/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp
new file mode 100644
index 0000000..5406879
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/StrongTypingTest.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include "Scheduler/StrongTyping.h"
+
+using namespace testing;
+
+namespace android {
+
+TEST(StrongTypeTest, comparison) {
+    using SpunkyType = StrongTyping<int, struct SpunkyTypeTag, Compare>;
+    SpunkyType f2(22);
+    SpunkyType f1(10);
+
+    EXPECT_TRUE(f1 == f1);
+    EXPECT_TRUE(SpunkyType(10) != SpunkyType(11));
+    EXPECT_FALSE(SpunkyType(31) != SpunkyType(31));
+
+    EXPECT_TRUE(SpunkyType(10) < SpunkyType(11));
+    EXPECT_TRUE(SpunkyType(-1) < SpunkyType(0));
+    EXPECT_FALSE(SpunkyType(-10) < SpunkyType(-20));
+
+    EXPECT_TRUE(SpunkyType(10) <= SpunkyType(11));
+    EXPECT_TRUE(SpunkyType(10) <= SpunkyType(10));
+    EXPECT_TRUE(SpunkyType(-10) <= SpunkyType(1));
+    EXPECT_FALSE(SpunkyType(10) <= SpunkyType(9));
+
+    EXPECT_TRUE(SpunkyType(11) >= SpunkyType(11));
+    EXPECT_TRUE(SpunkyType(12) >= SpunkyType(11));
+    EXPECT_FALSE(SpunkyType(11) >= SpunkyType(12));
+
+    EXPECT_FALSE(SpunkyType(11) > SpunkyType(12));
+    EXPECT_TRUE(SpunkyType(-11) < SpunkyType(7));
+}
+
+TEST(StrongTypeTest, addition) {
+    using FunkyType = StrongTyping<int, struct FunkyTypeTag, Compare, Add>;
+    FunkyType f2(22);
+    FunkyType f1(10);
+
+    EXPECT_THAT(f1 + f2, Eq(FunkyType(32)));
+    EXPECT_THAT(f2 + f1, Eq(FunkyType(32)));
+
+    EXPECT_THAT(++f1.value(), Eq(11));
+    EXPECT_THAT(f1.value(), Eq(11));
+    EXPECT_THAT(f1++.value(), Eq(11));
+    EXPECT_THAT(f1++.value(), Eq(12));
+    EXPECT_THAT(f1.value(), Eq(13));
+
+    auto f3 = f1;
+    EXPECT_THAT(f1, Eq(f3));
+    EXPECT_THAT(f1, Lt(f2));
+
+    f3 += f1;
+    EXPECT_THAT(f1.value(), Eq(13));
+    EXPECT_THAT(f3.value(), Eq(26));
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index cb6980e..d5ecae8 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -19,30 +19,49 @@
 #include <gmock/gmock.h>
 #include <gui/ISurfaceComposer.h>
 
+#include "Scheduler/DispSync.h"
 #include "Scheduler/EventThread.h"
-#include "Scheduler/RefreshRateConfigs.h"
+#include "Scheduler/LayerHistory.h"
 #include "Scheduler/Scheduler.h"
 
 namespace android {
 
-class TestableScheduler : public Scheduler {
+class TestableScheduler : public Scheduler, private ISchedulerCallback {
 public:
-    TestableScheduler(const scheduler::RefreshRateConfigs& refreshRateConfig)
-          : Scheduler([](bool) {}, refreshRateConfig) {}
+    TestableScheduler(const scheduler::RefreshRateConfigs& configs, bool useContentDetectionV2)
+          : Scheduler([](bool) {}, configs, *this, useContentDetectionV2, true) {
+        if (mUseContentDetectionV2) {
+            mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>(configs);
+        } else {
+            mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
+        }
+    }
 
-    // Creates EventThreadConnection with the given eventThread. Creates Scheduler::Connection
-    // and adds it to the list of connectins. Returns the ConnectionHandle for the
-    // Scheduler::Connection. This allows plugging in mock::EventThread.
-    sp<Scheduler::ConnectionHandle> addConnection(std::unique_ptr<EventThread> eventThread) {
-        sp<EventThreadConnection> eventThreadConnection =
-                new EventThreadConnection(eventThread.get(), ResyncCallback(),
-                                          ISurfaceComposer::eConfigChangedSuppress);
-        const int64_t id = sNextId++;
-        mConnections.emplace(id,
-                             std::make_unique<Scheduler::Connection>(new ConnectionHandle(id),
-                                                                     eventThreadConnection,
-                                                                     std::move(eventThread)));
-        return mConnections[id]->handle;
+    TestableScheduler(std::unique_ptr<DispSync> primaryDispSync,
+                      std::unique_ptr<EventControlThread> eventControlThread,
+                      const scheduler::RefreshRateConfigs& configs, bool useContentDetectionV2)
+          : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs, *this,
+                      useContentDetectionV2, true) {
+        if (mUseContentDetectionV2) {
+            mLayerHistory = std::make_unique<scheduler::impl::LayerHistoryV2>(configs);
+        } else {
+            mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
+        }
+    }
+
+    // Used to inject mock event thread.
+    ConnectionHandle createConnection(std::unique_ptr<EventThread> eventThread) {
+        return Scheduler::createConnection(std::move(eventThread));
+    }
+
+    size_t layerHistorySize() const NO_THREAD_SAFETY_ANALYSIS {
+        if (mUseContentDetectionV2) {
+            return static_cast<scheduler::impl::LayerHistoryV2*>(mLayerHistory.get())
+                    ->mLayerInfos.size();
+        } else {
+            return static_cast<scheduler::impl::LayerHistory*>(mLayerHistory.get())
+                    ->mLayerInfos.size();
+        }
     }
 
     /* ------------------------------------------------------------------------
@@ -53,6 +72,12 @@
     auto& mutableEventControlThread() { return mEventControlThread; }
     auto& mutablePrimaryDispSync() { return mPrimaryDispSync; }
     auto& mutableHWVsyncAvailable() { return mHWVsyncAvailable; }
+    auto mutableLayerHistory() {
+        return static_cast<scheduler::impl::LayerHistory*>(mLayerHistory.get());
+    }
+    auto mutableLayerHistoryV2() {
+        return static_cast<scheduler::impl::LayerHistoryV2*>(mLayerHistory.get());
+    }
 
     ~TestableScheduler() {
         // All these pointer and container clears help ensure that GMock does
@@ -62,7 +87,12 @@
         mutableEventControlThread().reset();
         mutablePrimaryDispSync().reset();
         mConnections.clear();
-    };
+    }
+
+private:
+    void changeRefreshRate(const RefreshRate&, ConfigEvent) override {}
+    void repaintEverythingForHWC() override {}
+    void kernelTimerChanged(bool /*expired*/) override {}
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 1c1b020..38bc8a1 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -17,17 +17,18 @@
 #pragma once
 
 #include <compositionengine/Display.h>
-#include <compositionengine/Layer.h>
+#include <compositionengine/LayerFECompositionState.h>
 #include <compositionengine/OutputLayer.h>
 #include <compositionengine/impl/CompositionEngine.h>
-#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/impl/Display.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <compositionengine/mock/DisplaySurface.h>
 
 #include "BufferQueueLayer.h"
 #include "BufferStateLayer.h"
-#include "ColorLayer.h"
 #include "ContainerLayer.h"
 #include "DisplayDevice.h"
+#include "EffectLayer.h"
 #include "FakePhaseOffsets.h"
 #include "Layer.h"
 #include "NativeWindowSurface.h"
@@ -35,9 +36,10 @@
 #include "Scheduler/RefreshRateConfigs.h"
 #include "StartPropertySetThread.h"
 #include "SurfaceFlinger.h"
-#include "SurfaceFlingerFactory.h"
+#include "SurfaceFlingerDefaultFactory.h"
 #include "SurfaceInterceptor.h"
-#include "TimeStats/TimeStats.h"
+#include "TestableScheduler.h"
+#include "mock/DisplayHardware/MockDisplay.h"
 
 namespace android {
 
@@ -55,72 +57,82 @@
 
 } // namespace Hwc2
 
+namespace hal = android::hardware::graphics::composer::hal;
+
 namespace surfaceflinger::test {
 
 class Factory final : public surfaceflinger::Factory {
 public:
     ~Factory() = default;
 
-    std::unique_ptr<DispSync> createDispSync(const char*, bool, int64_t) override {
-        // TODO: Use test-fixture controlled factory
+    std::unique_ptr<DispSync> createDispSync(const char*, bool) override {
         return nullptr;
     }
 
     std::unique_ptr<EventControlThread> createEventControlThread(
             std::function<void(bool)>) override {
-        // TODO: Use test-fixture controlled factory
         return nullptr;
     }
 
     std::unique_ptr<HWComposer> createHWComposer(const std::string&) override {
-        // TODO: Use test-fixture controlled factory
         return nullptr;
     }
 
     std::unique_ptr<MessageQueue> createMessageQueue() override {
-        // TODO: Use test-fixture controlled factory
         return std::make_unique<android::impl::MessageQueue>();
     }
 
-    std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() override {
+    std::unique_ptr<scheduler::PhaseConfiguration> createPhaseConfiguration(
+            const scheduler::RefreshRateConfigs& /*refreshRateConfigs*/) override {
         return std::make_unique<scheduler::FakePhaseOffsets>();
     }
 
     std::unique_ptr<Scheduler> createScheduler(std::function<void(bool)>,
-                                               const scheduler::RefreshRateConfigs&) override {
-        // TODO: Use test-fixture controlled factory
+                                               const scheduler::RefreshRateConfigs&,
+                                               ISchedulerCallback&) override {
         return nullptr;
     }
 
     std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger* flinger) override {
-        // TODO: Use test-fixture controlled factory
         return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
     }
 
     sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
-        // TODO: Use test-fixture controlled factory
         return new StartPropertySetThread(timestampPropertyValue);
     }
 
-    sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&& creationArgs) override {
-        // TODO: Use test-fixture controlled factory
-        return new DisplayDevice(std::move(creationArgs));
+    sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& creationArgs) override {
+        return new DisplayDevice(creationArgs);
     }
 
     sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
                                           uint32_t layerCount, uint64_t usage,
                                           std::string requestorName) override {
-        // TODO: Use test-fixture controlled factory
         return new GraphicBuffer(width, height, format, layerCount, usage, requestorName);
     }
 
     void createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
                            sp<IGraphicBufferConsumer>* outConsumer,
                            bool consumerIsSurfaceFlinger) override {
-        if (!mCreateBufferQueue) return;
+        if (!mCreateBufferQueue) {
+            BufferQueue::createBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
+            return;
+        }
         mCreateBufferQueue(outProducer, outConsumer, consumerIsSurfaceFlinger);
     }
 
+    sp<IGraphicBufferProducer> createMonitoredProducer(const sp<IGraphicBufferProducer>& producer,
+                                                       const sp<SurfaceFlinger>& flinger,
+                                                       const wp<Layer>& layer) override {
+        return new MonitoredProducer(producer, flinger, layer);
+    }
+
+    sp<BufferLayerConsumer> createBufferLayerConsumer(const sp<IGraphicBufferConsumer>& consumer,
+                                                      renderengine::RenderEngine& renderEngine,
+                                                      uint32_t textureName, Layer* layer) override {
+        return new BufferLayerConsumer(consumer, renderEngine, textureName, layer);
+    }
+
     std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
             const sp<IGraphicBufferProducer>& producer) override {
         if (!mCreateNativeWindowSurface) return nullptr;
@@ -132,30 +144,19 @@
     }
 
     sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override {
-        // TODO: Use test-fixture controlled factory
         return nullptr;
     }
 
     sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs&) override {
-        // TODO: Use test-fixture controlled factory
         return nullptr;
     }
 
-    sp<ColorLayer> createColorLayer(const LayerCreationArgs&) override {
-        // TODO: Use test-fixture controlled factory
-        return nullptr;
-    }
+    sp<EffectLayer> createEffectLayer(const LayerCreationArgs&) override { return nullptr; }
 
     sp<ContainerLayer> createContainerLayer(const LayerCreationArgs&) override {
-        // TODO: Use test-fixture controlled factory
         return nullptr;
     }
 
-    std::shared_ptr<TimeStats> createTimeStats() override {
-        // TODO: Use test-fixture controlled factory
-        return std::make_shared<android::impl::TimeStats>();
-    }
-
     using CreateBufferQueueFunction =
             std::function<void(sp<IGraphicBufferProducer>* /* outProducer */,
                                sp<IGraphicBufferConsumer>* /* outConsumer */,
@@ -176,6 +177,11 @@
 
 class TestableSurfaceFlinger {
 public:
+    using HotplugEvent = SurfaceFlinger::HotplugEvent;
+
+    SurfaceFlinger* flinger() { return mFlinger.get(); }
+    TestableScheduler* scheduler() { return mScheduler; }
+
     // Extend this as needed for accessing SurfaceFlinger private (and public)
     // functions.
 
@@ -188,6 +194,45 @@
                 std::make_unique<impl::HWComposer>(std::move(composer)));
     }
 
+    void setupTimeStats(const std::shared_ptr<TimeStats>& timeStats) {
+        mFlinger->mCompositionEngine->setTimeStats(timeStats);
+    }
+
+    void setupScheduler(std::unique_ptr<DispSync> primaryDispSync,
+                        std::unique_ptr<EventControlThread> eventControlThread,
+                        std::unique_ptr<EventThread> appEventThread,
+                        std::unique_ptr<EventThread> sfEventThread,
+                        bool useContentDetectionV2 = false) {
+        std::vector<std::shared_ptr<const HWC2::Display::Config>> configs{
+                HWC2::Display::Config::Builder(mDisplay, 0)
+                        .setVsyncPeriod(int32_t(16666667))
+                        .setConfigGroup(0)
+                        .build()};
+
+        mFlinger->mRefreshRateConfigs = std::make_unique<
+                scheduler::RefreshRateConfigs>(configs, /*currentConfig=*/HwcConfigIndexType(0));
+        mFlinger->mRefreshRateStats = std::make_unique<
+                scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs, *mFlinger->mTimeStats,
+                                             /*currentConfig=*/HwcConfigIndexType(0),
+                                             /*powerMode=*/hal::PowerMode::OFF);
+        mFlinger->mPhaseConfiguration =
+                mFactory.createPhaseConfiguration(*mFlinger->mRefreshRateConfigs);
+
+        mScheduler =
+                new TestableScheduler(std::move(primaryDispSync), std::move(eventControlThread),
+                                      *mFlinger->mRefreshRateConfigs, useContentDetectionV2);
+
+        mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
+        mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
+        resetScheduler(mScheduler);
+
+        mFlinger->mVSyncModulator.emplace(*mScheduler, mFlinger->mAppConnectionHandle,
+                                          mFlinger->mSfConnectionHandle,
+                                          mFlinger->mPhaseConfiguration->getCurrentOffsets());
+    }
+
+    void resetScheduler(Scheduler* scheduler) { mFlinger->mScheduler.reset(scheduler); }
+
     using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
     void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
         mFactory.mCreateBufferQueue = f;
@@ -203,26 +248,32 @@
         memcpy(&mFlinger->mInternalDisplayPrimaries, &primaries, sizeof(ui::DisplayPrimaries));
     }
 
-    using HotplugEvent = SurfaceFlinger::HotplugEvent;
+    static auto& mutableLayerCurrentState(const sp<Layer>& layer) { return layer->mCurrentState; }
+    static auto& mutableLayerDrawingState(const sp<Layer>& layer) { return layer->mDrawingState; }
 
-    auto& mutableLayerCurrentState(sp<Layer> layer) { return layer->mCurrentState; }
-    auto& mutableLayerDrawingState(sp<Layer> layer) { return layer->mDrawingState; }
+    auto& mutableStateLock() { return mFlinger->mStateLock; }
 
-    void setLayerSidebandStream(sp<Layer> layer, sp<NativeHandle> sidebandStream) {
-        layer->mDrawingState.sidebandStream = sidebandStream;
-        layer->mSidebandStream = sidebandStream;
-        layer->getCompositionLayer()->editState().frontEnd.sidebandStream = sidebandStream;
+    static auto findOutputLayerForDisplay(const sp<Layer>& layer,
+                                          const sp<const DisplayDevice>& display) {
+        return layer->findOutputLayerForDisplay(display.get());
     }
 
-    void setLayerCompositionType(sp<Layer> layer, HWC2::Composition type) {
-        auto outputLayer = layer->findOutputLayerForDisplay(mFlinger->getDefaultDisplayDevice());
+    static void setLayerSidebandStream(const sp<Layer>& layer,
+                                       const sp<NativeHandle>& sidebandStream) {
+        layer->mDrawingState.sidebandStream = sidebandStream;
+        layer->mSidebandStream = sidebandStream;
+        layer->editCompositionState()->sidebandStream = sidebandStream;
+    }
+
+    void setLayerCompositionType(const sp<Layer>& layer, hal::Composition type) {
+        auto outputLayer = findOutputLayerForDisplay(layer, mFlinger->getDefaultDisplayDevice());
         LOG_ALWAYS_FATAL_IF(!outputLayer);
         auto& state = outputLayer->editState();
         LOG_ALWAYS_FATAL_IF(!outputLayer->getState().hwc);
-        (*state.hwc).hwcCompositionType = static_cast<Hwc2::IComposerClient::Composition>(type);
-    };
+        (*state.hwc).hwcCompositionType = type;
+    }
 
-    void setLayerPotentialCursor(sp<Layer> layer, bool potentialCursor) {
+    static void setLayerPotentialCursor(const sp<Layer>& layer, bool potentialCursor) {
         layer->mPotentialCursor = potentialCursor;
     }
 
@@ -238,15 +289,16 @@
         return mFlinger->destroyDisplay(displayToken);
     }
 
-    auto resetDisplayState() { return mFlinger->resetDisplayState(); }
+    auto resetDisplayState() NO_THREAD_SAFETY_ANALYSIS { return mFlinger->resetDisplayState(); }
 
-    auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
-                                       const std::optional<DisplayId>& displayId,
-                                       const DisplayDeviceState& state,
-                                       const sp<compositionengine::DisplaySurface>& dispSurface,
-                                       const sp<IGraphicBufferProducer>& producer) {
-        return mFlinger->setupNewDisplayDeviceInternal(displayToken, displayId, state, dispSurface,
-                                                       producer);
+    auto setupNewDisplayDeviceInternal(
+            const wp<IBinder>& displayToken,
+            std::shared_ptr<compositionengine::Display> compositionDisplay,
+            const DisplayDeviceState& state,
+            const sp<compositionengine::DisplaySurface>& dispSurface,
+            const sp<IGraphicBufferProducer>& producer) NO_THREAD_SAFETY_ANALYSIS {
+        return mFlinger->setupNewDisplayDeviceInternal(displayToken, compositionDisplay, state,
+                                                       dispSurface, producer);
     }
 
     auto handleTransactionLocked(uint32_t transactionFlags) {
@@ -254,8 +306,8 @@
         return mFlinger->handleTransactionLocked(transactionFlags);
     }
 
-    auto onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
-                           HWC2::Connection connection) {
+    auto onHotplugReceived(int32_t sequenceId, hal::HWDisplayId display,
+                           hal::Connection connection) {
         return mFlinger->onHotplugReceived(sequenceId, display, connection);
     }
 
@@ -271,19 +323,20 @@
 
     // Allow reading display state without locking, as if called on the SF main thread.
     auto setPowerModeInternal(const sp<DisplayDevice>& display,
-                              int mode) NO_THREAD_SAFETY_ANALYSIS {
+                              hal::PowerMode mode) NO_THREAD_SAFETY_ANALYSIS {
         return mFlinger->setPowerModeInternal(display, mode);
     }
 
-    auto onMessageReceived(int32_t what) { return mFlinger->onMessageReceived(what); }
+    auto onMessageReceived(int32_t what) { return mFlinger->onMessageReceived(what, systemTime()); }
 
-    auto captureScreenImplLocked(
-            const RenderArea& renderArea, SurfaceFlinger::TraverseLayersFunction traverseLayers,
-            ANativeWindowBuffer* buffer, bool useIdentityTransform, bool forSystem, int* outSyncFd) {
+    auto captureScreenImplLocked(const RenderArea& renderArea,
+                                 SurfaceFlinger::TraverseLayersFunction traverseLayers,
+                                 ANativeWindowBuffer* buffer, bool useIdentityTransform,
+                                 bool forSystem, int* outSyncFd, bool regionSampling) {
         bool ignored;
         return mFlinger->captureScreenImplLocked(renderArea, traverseLayers, buffer,
                                                  useIdentityTransform, forSystem, outSyncFd,
-                                                 ignored);
+                                                 regionSampling, ignored);
     }
 
     auto traverseLayersInDisplay(const sp<const DisplayDevice>& display,
@@ -296,6 +349,22 @@
         return mFlinger->SurfaceFlinger::getDisplayNativePrimaries(displayToken, primaries);
     }
 
+    auto& getTransactionQueue() { return mFlinger->mTransactionQueues; }
+
+    auto setTransactionState(const Vector<ComposerState>& states,
+                             const Vector<DisplayState>& displays, uint32_t flags,
+                             const sp<IBinder>& applyToken,
+                             const InputWindowCommands& inputWindowCommands,
+                             int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
+                             bool hasListenerCallbacks,
+                             std::vector<ListenerCallbacks>& listenerCallbacks) {
+        return mFlinger->setTransactionState(states, displays, flags, applyToken,
+                                             inputWindowCommands, desiredPresentTime, uncacheBuffer,
+                                             hasListenerCallbacks, listenerCallbacks);
+    }
+
+    auto flushTransactionQueues() { return mFlinger->flushTransactionQueues(); };
+
     /* ------------------------------------------------------------------------
      * Read-only access to private data to assert post-conditions.
      */
@@ -306,6 +375,7 @@
     auto& getHwComposer() const {
         return static_cast<impl::HWComposer&>(mFlinger->getHwComposer());
     }
+    auto& getCompositionEngine() const { return mFlinger->getCompositionEngine(); }
 
     const auto& getCompositorTiming() const { return mFlinger->getBE().mCompositorTiming; }
 
@@ -315,7 +385,6 @@
      */
 
     auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; }
-    auto& mutablePrimaryDisplayOrientation() { return SurfaceFlinger::primaryDisplayOrientation; }
     auto& mutableUseColorManagement() { return SurfaceFlinger::useColorManagement; }
 
     auto& mutableCurrentState() { return mFlinger->mCurrentState; }
@@ -332,18 +401,18 @@
     auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
     auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
     auto& mutablePowerAdvisor() { return mFlinger->mPowerAdvisor; }
+    auto& mutableDebugDisableHWC() { return mFlinger->mDebugDisableHWC; }
 
     auto& mutableComposerSequenceId() { return mFlinger->getBE().mComposerSequenceId; }
     auto& mutableHwcDisplayData() { return getHwComposer().mDisplayData; }
     auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
     auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; }
     auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; }
-    auto& mutableScheduler() { return mFlinger->mScheduler; }
-    auto& mutableAppConnectionHandle() { return mFlinger->mAppConnectionHandle; }
-    auto& mutableSfConnectionHandle() { return mFlinger->mSfConnectionHandle; }
-    auto& mutableRefreshRateConfigs() { return mFlinger->mRefreshRateConfigs; }
-    auto& mutableRefreshRateStats() { return mFlinger->mRefreshRateStats; }
-    auto& mutableTimeStats() { return mFlinger->mTimeStats; }
+    auto& mutableUseFrameRateApi() { return mFlinger->useFrameRateApi; }
+
+    auto fromHandle(const sp<IBinder>& handle) {
+        return mFlinger->fromHandle(handle);
+    }
 
     ~TestableSurfaceFlinger() {
         // All these pointer and container clears help ensure that GMock does
@@ -355,7 +424,7 @@
         mutableDrawingState().displays.clear();
         mutableEventQueue().reset();
         mutableInterceptor().reset();
-        mutableScheduler().reset();
+        mFlinger->mScheduler.reset();
         mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
         mFlinger->mCompositionEngine->setRenderEngine(
                 std::unique_ptr<renderengine::RenderEngine>());
@@ -367,12 +436,12 @@
      */
     struct HWC2Display : public HWC2::impl::Display {
         HWC2Display(Hwc2::Composer& composer,
-                    const std::unordered_set<HWC2::Capability>& capabilities, hwc2_display_t id,
-                    HWC2::DisplayType type)
+                    const std::unordered_set<hal::Capability>& capabilities, hal::HWDisplayId id,
+                    hal::DisplayType type)
               : HWC2::impl::Display(composer, capabilities, id, type) {}
         ~HWC2Display() {
             // Prevents a call to disable vsyncs.
-            mType = HWC2::DisplayType::Invalid;
+            mType = hal::DisplayType::INVALID;
         }
 
         auto& mutableIsConnected() { return this->mIsConnected; }
@@ -382,19 +451,19 @@
 
     class FakeHwcDisplayInjector {
     public:
-        static constexpr hwc2_display_t DEFAULT_HWC_DISPLAY_ID = 1000;
+        static constexpr hal::HWDisplayId DEFAULT_HWC_DISPLAY_ID = 1000;
         static constexpr int32_t DEFAULT_WIDTH = 1920;
         static constexpr int32_t DEFAULT_HEIGHT = 1280;
         static constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'666;
+        static constexpr int32_t DEFAULT_CONFIG_GROUP = 7;
         static constexpr int32_t DEFAULT_DPI = 320;
-        static constexpr int32_t DEFAULT_ACTIVE_CONFIG = 0;
-        static constexpr int32_t DEFAULT_POWER_MODE = 2;
+        static constexpr hal::HWConfigId DEFAULT_ACTIVE_CONFIG = 0;
+        static constexpr hal::PowerMode DEFAULT_POWER_MODE = hal::PowerMode::ON;
 
-        FakeHwcDisplayInjector(DisplayId displayId, HWC2::DisplayType hwcDisplayType,
-                               bool isPrimary)
+        FakeHwcDisplayInjector(DisplayId displayId, hal::DisplayType hwcDisplayType, bool isPrimary)
               : mDisplayId(displayId), mHwcDisplayType(hwcDisplayType), mIsPrimary(isPrimary) {}
 
-        auto& setHwcDisplayId(hwc2_display_t displayId) {
+        auto& setHwcDisplayId(hal::HWDisplayId displayId) {
             mHwcDisplayId = displayId;
             return *this;
         }
@@ -424,23 +493,23 @@
             return *this;
         }
 
-        auto& setActiveConfig(int32_t config) {
+        auto& setActiveConfig(hal::HWConfigId config) {
             mActiveConfig = config;
             return *this;
         }
 
-        auto& setCapabilities(const std::unordered_set<HWC2::Capability>* capabilities) {
+        auto& setCapabilities(const std::unordered_set<hal::Capability>* capabilities) {
             mCapabilities = capabilities;
             return *this;
         }
 
-        auto& setPowerMode(int mode) {
+        auto& setPowerMode(hal::PowerMode mode) {
             mPowerMode = mode;
             return *this;
         }
 
         void inject(TestableSurfaceFlinger* flinger, Hwc2::Composer* composer) {
-            static const std::unordered_set<HWC2::Capability> defaultCapabilities;
+            static const std::unordered_set<hal::Capability> defaultCapabilities;
             if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities;
 
             // Caution - Make sure that any values passed by reference here do
@@ -456,44 +525,47 @@
             config.setVsyncPeriod(mRefreshRate);
             config.setDpiX(mDpiX);
             config.setDpiY(mDpiY);
-            display->mutableConfigs().emplace(mActiveConfig, config.build());
+            config.setConfigGroup(mConfigGroup);
+            display->mutableConfigs().emplace(static_cast<int32_t>(mActiveConfig), config.build());
             display->mutableIsConnected() = true;
-            display->setPowerMode(static_cast<HWC2::PowerMode>(mPowerMode));
+            display->setPowerMode(mPowerMode);
 
-            flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = display.get();
+            flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = std::move(display);
 
-            if (mHwcDisplayType == HWC2::DisplayType::Physical) {
+            if (mHwcDisplayType == hal::DisplayType::PHYSICAL) {
                 flinger->mutableHwcPhysicalDisplayIdMap().emplace(mHwcDisplayId, mDisplayId);
                 (mIsPrimary ? flinger->mutableInternalHwcDisplayId()
                             : flinger->mutableExternalHwcDisplayId()) = mHwcDisplayId;
             }
-
-            flinger->mFakeHwcDisplays.push_back(std::move(display));
         }
 
     private:
         const DisplayId mDisplayId;
-        const HWC2::DisplayType mHwcDisplayType;
+        const hal::DisplayType mHwcDisplayType;
         const bool mIsPrimary;
 
-        hwc2_display_t mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID;
+        hal::HWDisplayId mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID;
         int32_t mWidth = DEFAULT_WIDTH;
         int32_t mHeight = DEFAULT_HEIGHT;
         int32_t mRefreshRate = DEFAULT_REFRESH_RATE;
         int32_t mDpiX = DEFAULT_DPI;
+        int32_t mConfigGroup = DEFAULT_CONFIG_GROUP;
         int32_t mDpiY = DEFAULT_DPI;
-        int32_t mActiveConfig = DEFAULT_ACTIVE_CONFIG;
-        int32_t mPowerMode = DEFAULT_POWER_MODE;
-        const std::unordered_set<HWC2::Capability>* mCapabilities = nullptr;
+        hal::HWConfigId mActiveConfig = DEFAULT_ACTIVE_CONFIG;
+        hal::PowerMode mPowerMode = DEFAULT_POWER_MODE;
+        const std::unordered_set<hal::Capability>* mCapabilities = nullptr;
     };
 
     class FakeDisplayDeviceInjector {
     public:
         FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger,
-                                  const std::optional<DisplayId>& displayId, bool isVirtual,
-                                  bool isPrimary)
-              : mFlinger(flinger), mCreationArgs(flinger.mFlinger.get(), mDisplayToken, displayId) {
-            mCreationArgs.isVirtual = isVirtual;
+                                  std::shared_ptr<compositionengine::Display> compositionDisplay,
+                                  std::optional<DisplayConnectionType> connectionType,
+                                  std::optional<hal::HWDisplayId> hwcDisplayId, bool isPrimary)
+              : mFlinger(flinger),
+                mCreationArgs(flinger.mFlinger.get(), mDisplayToken, compositionDisplay),
+                mHwcDisplayId(hwcDisplayId) {
+            mCreationArgs.connectionType = connectionType;
             mCreationArgs.isPrimary = isPrimary;
         }
 
@@ -532,7 +604,7 @@
             return *this;
         }
 
-        auto& setPowerMode(int mode) {
+        auto& setPowerMode(hal::PowerMode mode) {
             mCreationArgs.initialPowerMode = mode;
             return *this;
         }
@@ -549,19 +621,30 @@
             return *this;
         }
 
+        auto& setPhysicalOrientation(ui::Rotation orientation) {
+            mCreationArgs.physicalOrientation = orientation;
+            return *this;
+        }
+
         sp<DisplayDevice> inject() {
+            const auto displayId = mCreationArgs.compositionDisplay->getDisplayId();
+
             DisplayDeviceState state;
-            state.displayId = mCreationArgs.isVirtual ? std::nullopt : mCreationArgs.displayId;
+            if (const auto type = mCreationArgs.connectionType) {
+                LOG_ALWAYS_FATAL_IF(!displayId);
+                LOG_ALWAYS_FATAL_IF(!mHwcDisplayId);
+                state.physical = {*displayId, *type, *mHwcDisplayId};
+            }
+
             state.isSecure = mCreationArgs.isSecure;
 
-            sp<DisplayDevice> device = new DisplayDevice(std::move(mCreationArgs));
+            sp<DisplayDevice> device = new DisplayDevice(mCreationArgs);
             mFlinger.mutableDisplays().emplace(mDisplayToken, device);
             mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
             mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
 
-            if (!mCreationArgs.isVirtual) {
-                LOG_ALWAYS_FATAL_IF(!state.displayId);
-                mFlinger.mutablePhysicalDisplayTokens()[*state.displayId] = mDisplayToken;
+            if (const auto& physical = state.physical) {
+                mFlinger.mutablePhysicalDisplayTokens()[physical->id] = mDisplayToken;
             }
 
             return device;
@@ -571,13 +654,13 @@
         TestableSurfaceFlinger& mFlinger;
         sp<BBinder> mDisplayToken = new BBinder();
         DisplayDeviceCreationArgs mCreationArgs;
+        const std::optional<hal::HWDisplayId> mHwcDisplayId;
     };
 
     surfaceflinger::test::Factory mFactory;
     sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
-
-    // We need to keep a reference to these so they are properly destroyed.
-    std::vector<std::unique_ptr<HWC2Display>> mFakeHwcDisplays;
+    TestableScheduler* mScheduler = nullptr;
+    Hwc2::mock::Display mDisplay;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index f35758d..0a24650 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -14,33 +14,45 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #undef LOG_TAG
 #define LOG_TAG "LibSurfaceFlingerUnittests"
 
+#include <TimeStats/TimeStats.h>
+#include <android/util/ProtoOutputStream.h>
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
-
 #include <log/log.h>
 #include <utils/String16.h>
 #include <utils/Vector.h>
 
+#include <chrono>
 #include <random>
 #include <unordered_set>
 
-#include "TimeStats/TimeStats.h"
-
 #include "libsurfaceflinger_unittest_main.h"
 
 using namespace android::surfaceflinger;
 using namespace google::protobuf;
+using namespace std::chrono_literals;
 
 namespace android {
 namespace {
 
+using testing::_;
+using testing::AnyNumber;
 using testing::Contains;
+using testing::HasSubstr;
+using testing::InSequence;
 using testing::SizeIs;
+using testing::StrEq;
 using testing::UnorderedElementsAre;
 
+using PowerMode = hardware::graphics::composer::V2_4::IComposerClient::PowerMode;
+
 // clang-format off
 #define FMT_PROTO          true
 #define FMT_STRING         false
@@ -133,7 +145,44 @@
     }
 
     std::mt19937 mRandomEngine = std::mt19937(std::random_device()());
-    std::unique_ptr<TimeStats> mTimeStats = std::make_unique<impl::TimeStats>();
+
+    class FakeStatsEventDelegate : public impl::TimeStats::StatsEventDelegate {
+    public:
+        FakeStatsEventDelegate() = default;
+        ~FakeStatsEventDelegate() override = default;
+
+        struct AStatsEvent* addStatsEventToPullData(AStatsEventList*) override {
+            return mEvent;
+        }
+        void setStatsPullAtomCallback(int32_t atom_tag, AStatsManager_PullAtomMetadata*,
+                                      AStatsManager_PullAtomCallback callback,
+                                      void* cookie) override {
+            mAtomTags.push_back(atom_tag);
+            mCallback = callback;
+            mCookie = cookie;
+        }
+
+        AStatsManager_PullAtomCallbackReturn makePullAtomCallback(int32_t atom_tag, void* cookie) {
+            return (*mCallback)(atom_tag, nullptr, cookie);
+        }
+
+        MOCK_METHOD1(clearStatsPullAtomCallback, void(int32_t));
+        MOCK_METHOD2(statsEventSetAtomId, void(AStatsEvent*, uint32_t));
+        MOCK_METHOD2(statsEventWriteInt32, void(AStatsEvent*, int32_t));
+        MOCK_METHOD2(statsEventWriteInt64, void(AStatsEvent*, int64_t));
+        MOCK_METHOD2(statsEventWriteString8, void(AStatsEvent*, const char*));
+        MOCK_METHOD3(statsEventWriteByteArray, void(AStatsEvent*, const uint8_t*, size_t));
+        MOCK_METHOD1(statsEventBuild, void(AStatsEvent*));
+
+        AStatsEvent* mEvent = AStatsEvent_obtain();
+        std::vector<int32_t> mAtomTags;
+        AStatsManager_PullAtomCallback mCallback = nullptr;
+        void* mCookie = nullptr;
+    };
+    FakeStatsEventDelegate* mDelegate = new FakeStatsEventDelegate;
+    std::unique_ptr<TimeStats> mTimeStats =
+            std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate),
+                                              std::nullopt, std::nullopt);
 };
 
 std::string TimeStatsTest::inputCommand(InputCommand cmd, bool useProto) {
@@ -171,8 +220,8 @@
     return result;
 }
 
-static std::string genLayerName(int32_t layerID) {
-    return (layerID < 0 ? "invalid.dummy" : "com.dummy#") + std::to_string(layerID);
+static std::string genLayerName(int32_t layerId) {
+    return (layerId < 0 ? "PopupWindow:b54fcd1#0" : "com.example.fake#") + std::to_string(layerId);
 }
 
 void TimeStatsTest::setTimeStamp(TimeStamp type, int32_t id, uint64_t frameNumber, nsecs_t ts) {
@@ -210,6 +259,25 @@
     return distr(mRandomEngine);
 }
 
+TEST_F(TimeStatsTest, disabledByDefault) {
+    ASSERT_FALSE(mTimeStats->isEnabled());
+}
+
+TEST_F(TimeStatsTest, setsCallbacksAfterBoot) {
+    mTimeStats->onBootFinished();
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+}
+
+TEST_F(TimeStatsTest, clearsCallbacksOnDestruction) {
+    EXPECT_CALL(*mDelegate,
+                clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
+    EXPECT_CALL(*mDelegate,
+                clearStatsPullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    mTimeStats.reset();
+}
+
 TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
     ASSERT_TRUE(mTimeStats->isEnabled());
@@ -246,6 +314,125 @@
     EXPECT_EQ(CLIENT_COMPOSITION_FRAMES, globalProto.client_composition_frames());
 }
 
+TEST_F(TimeStatsTest, canIncreaseLateAcquireFrames) {
+    // this stat is not in the proto so verify by checking the string dump
+    constexpr size_t LATE_ACQUIRE_FRAMES = 2;
+
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+    for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) {
+        mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire);
+    }
+    insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 2, 2000000);
+
+    const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+    const std::string expectedResult = "lateAcquireFrames = " + std::to_string(LATE_ACQUIRE_FRAMES);
+    EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
+TEST_F(TimeStatsTest, canIncreaseBadDesiredPresent) {
+    // this stat is not in the proto so verify by checking the string dump
+    constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 2;
+
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+    for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) {
+        mTimeStats->incrementBadDesiredPresent(LAYER_ID_0);
+    }
+    insertTimeRecord(NORMAL_SEQUENCE_2, LAYER_ID_0, 2, 2000000);
+
+    const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+    const std::string expectedResult =
+            "badDesiredPresentFrames = " + std::to_string(BAD_DESIRED_PRESENT_FRAMES);
+    EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
+TEST_F(TimeStatsTest, canIncreaseClientCompositionReusedFrames) {
+    // this stat is not in the proto so verify by checking the string dump
+    constexpr size_t CLIENT_COMPOSITION_REUSED_FRAMES = 2;
+
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+    for (size_t i = 0; i < CLIENT_COMPOSITION_REUSED_FRAMES; i++) {
+        ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+    }
+
+    const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+    const std::string expectedResult =
+            "clientCompositionReusedFrames = " + std::to_string(CLIENT_COMPOSITION_REUSED_FRAMES);
+    EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
+TEST_F(TimeStatsTest, canIncreaseRefreshRateSwitches) {
+    // this stat is not in the proto so verify by checking the string dump
+    constexpr size_t REFRESH_RATE_SWITCHES = 2;
+
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+    for (size_t i = 0; i < REFRESH_RATE_SWITCHES; i++) {
+        ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
+    }
+
+    const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+    const std::string expectedResult =
+            "refreshRateSwitches = " + std::to_string(REFRESH_RATE_SWITCHES);
+    EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
+TEST_F(TimeStatsTest, canIncreaseCompositionStrategyChanges) {
+    // this stat is not in the proto so verify by checking the string dump
+    constexpr size_t COMPOSITION_STRATEGY_CHANGES = 2;
+
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+    for (size_t i = 0; i < COMPOSITION_STRATEGY_CHANGES; i++) {
+        ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
+    }
+
+    const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+    const std::string expectedResult =
+            "compositionStrategyChanges = " + std::to_string(COMPOSITION_STRATEGY_CHANGES);
+    EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
+TEST_F(TimeStatsTest, canAverageFrameDuration) {
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+    mTimeStats->setPowerMode(PowerMode::ON);
+    mTimeStats
+            ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+                                  std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+                                          .count());
+    mTimeStats
+            ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+                                  std::chrono::duration_cast<std::chrono::nanoseconds>(16ms)
+                                          .count());
+
+    const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+    EXPECT_THAT(result, HasSubstr("averageFrameDuration = 10.000 ms"));
+}
+
+TEST_F(TimeStatsTest, canAverageRenderEngineTimings) {
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+    mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
+                                                   .count(),
+                                           std::make_shared<FenceTime>(
+                                                   std::chrono::duration_cast<
+                                                           std::chrono::nanoseconds>(3ms)
+                                                           .count()));
+
+    mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
+                                                   .count(),
+                                           std::chrono::duration_cast<std::chrono::nanoseconds>(8ms)
+                                                   .count());
+
+    // Push a fake present fence to trigger flushing the RenderEngine timings.
+    mTimeStats->setPowerMode(PowerMode::ON);
+    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
+            std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
+
+    const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+    EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 3.000 ms"));
+}
+
 TEST_F(TimeStatsTest, canInsertGlobalPresentToPresent) {
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
 
@@ -254,13 +441,13 @@
     ASSERT_NO_FATAL_FAILURE(
             mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(2000000)));
 
-    ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
+    ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON));
     ASSERT_NO_FATAL_FAILURE(
             mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000)));
     ASSERT_NO_FATAL_FAILURE(
             mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000)));
 
-    ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_OFF));
+    ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::OFF));
     ASSERT_NO_FATAL_FAILURE(
             mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(6000000)));
     ASSERT_NO_FATAL_FAILURE(
@@ -275,6 +462,65 @@
     EXPECT_EQ(2, histogramProto.time_millis());
 }
 
+TEST_F(TimeStatsTest, canInsertGlobalFrameDuration) {
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    mTimeStats->setPowerMode(PowerMode::OFF);
+    mTimeStats
+            ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+                                  std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
+                                          .count());
+    mTimeStats->setPowerMode(PowerMode::ON);
+    mTimeStats
+            ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
+                                  std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+                                          .count());
+
+    SFTimeStatsGlobalProto globalProto;
+    ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+    ASSERT_EQ(1, globalProto.frame_duration_size());
+    const SFTimeStatsHistogramBucketProto& histogramProto = globalProto.frame_duration().Get(0);
+    EXPECT_EQ(1, histogramProto.frame_count());
+    EXPECT_EQ(3, histogramProto.time_millis());
+}
+
+TEST_F(TimeStatsTest, canInsertGlobalRenderEngineTiming) {
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms)
+                                                   .count(),
+                                           std::make_shared<FenceTime>(
+                                                   std::chrono::duration_cast<
+                                                           std::chrono::nanoseconds>(3ms)
+                                                           .count()));
+
+    mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
+                                                   .count(),
+                                           std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+                                                   .count());
+
+    // First verify that flushing RenderEngine durations did not occur yet.
+    SFTimeStatsGlobalProto preFlushProto;
+    ASSERT_TRUE(preFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+    ASSERT_EQ(0, preFlushProto.render_engine_timing_size());
+
+    // Push a fake present fence to trigger flushing the RenderEngine timings.
+    mTimeStats->setPowerMode(PowerMode::ON);
+    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
+            std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
+
+    // Now we can verify that RenderEngine durations were flushed now.
+    SFTimeStatsGlobalProto postFlushProto;
+    ASSERT_TRUE(postFlushProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+    ASSERT_EQ(1, postFlushProto.render_engine_timing_size());
+    const SFTimeStatsHistogramBucketProto& histogramProto =
+            postFlushProto.render_engine_timing().Get(0);
+    EXPECT_EQ(2, histogramProto.frame_count());
+    EXPECT_EQ(2, histogramProto.time_millis());
+}
+
 TEST_F(TimeStatsTest, canInsertOneLayerTimeStats) {
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
 
@@ -495,7 +741,16 @@
     ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames());
     ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
     ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
-    ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
+    ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON));
+
+    mTimeStats
+            ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
+                                  std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+                                          .count());
+    mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
+                                                   .count(),
+                                           std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+                                                   .count());
     ASSERT_NO_FATAL_FAILURE(
             mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
     ASSERT_NO_FATAL_FAILURE(
@@ -512,9 +767,38 @@
     EXPECT_EQ(0, globalProto.missed_frames());
     EXPECT_EQ(0, globalProto.client_composition_frames());
     EXPECT_EQ(0, globalProto.present_to_present_size());
+    EXPECT_EQ(0, globalProto.frame_duration_size());
+    EXPECT_EQ(0, globalProto.render_engine_timing_size());
     EXPECT_EQ(0, globalProto.stats_size());
 }
 
+TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) {
+    // These stats are not in the proto so verify by checking the string dump.
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+    ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+    ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
+    ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges());
+    mTimeStats->setPowerMode(PowerMode::ON);
+    mTimeStats
+            ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
+                                  std::chrono::duration_cast<std::chrono::nanoseconds>(5ms)
+                                          .count());
+    mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
+                                                   .count(),
+                                           std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+                                                   .count());
+    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(
+            std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count()));
+    EXPECT_TRUE(inputCommand(InputCommand::CLEAR, FMT_STRING).empty());
+
+    const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+    EXPECT_THAT(result, HasSubstr("clientCompositionReusedFrames = 0"));
+    EXPECT_THAT(result, HasSubstr("refreshRateSwitches = 0"));
+    EXPECT_THAT(result, HasSubstr("compositionStrategyChanges = 0"));
+    EXPECT_THAT(result, HasSubstr("averageFrameDuration = 0.000 ms"));
+    EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 0.000 ms"));
+}
+
 TEST_F(TimeStatsTest, canDumpWithMaxLayers) {
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
 
@@ -549,6 +833,359 @@
     ASSERT_EQ(0, globalProto.stats_size());
 }
 
+TEST_F(TimeStatsTest, noInfInAverageFPS) {
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 1000000);
+
+    const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+    EXPECT_THAT(result, HasSubstr("averageFPS = 0.000"));
+}
+
+namespace {
+std::string buildExpectedHistogramBytestring(const std::vector<int32_t>& times,
+                                             const std::vector<int32_t>& frameCounts) {
+    util::ProtoOutputStream proto;
+    for (int i = 0; i < times.size(); i++) {
+        ALOGE("Writing time: %d", times[i]);
+        proto.write(util::FIELD_TYPE_INT32 | util::FIELD_COUNT_REPEATED | 1 /* field id */,
+                    (int32_t)times[i]);
+        ALOGE("Writing count: %d", frameCounts[i]);
+        proto.write(util::FIELD_TYPE_INT64 | util::FIELD_COUNT_REPEATED | 2 /* field id */,
+                    (int64_t)frameCounts[i]);
+    }
+    std::string byteString;
+    proto.serializeToString(&byteString);
+    return byteString;
+}
+
+std::string dumpByteStringHex(const std::string& str) {
+    std::stringstream ss;
+    ss << std::hex;
+    for (const char& c : str) {
+        ss << (int)c << " ";
+    }
+
+    return ss.str();
+}
+
+} // namespace
+
+MATCHER_P2(BytesEq, bytes, size, "") {
+    std::string expected;
+    expected.append((const char*)bytes, size);
+    std::string actual;
+    actual.append((const char*)arg, size);
+
+    *result_listener << "Bytes are not equal! \n";
+    *result_listener << "size: " << size << "\n";
+    *result_listener << "expected: " << dumpByteStringHex(expected).c_str() << "\n";
+    *result_listener << "actual: " << dumpByteStringHex(actual).c_str() << "\n";
+
+    return expected == actual;
+}
+
+TEST_F(TimeStatsTest, globalStatsCallback) {
+    constexpr size_t TOTAL_FRAMES = 5;
+    constexpr size_t MISSED_FRAMES = 4;
+    constexpr size_t CLIENT_COMPOSITION_FRAMES = 3;
+    constexpr size_t DISPLAY_EVENT_CONNECTIONS = 14;
+
+    mTimeStats->onBootFinished();
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    for (size_t i = 0; i < TOTAL_FRAMES; i++) {
+        mTimeStats->incrementTotalFrames();
+    }
+    for (size_t i = 0; i < MISSED_FRAMES; i++) {
+        mTimeStats->incrementMissedFrames();
+    }
+    for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) {
+        mTimeStats->incrementClientCompositionFrames();
+    }
+
+    mTimeStats->recordDisplayEventConnectionCount(DISPLAY_EVENT_CONNECTIONS);
+    mTimeStats->setPowerMode(PowerMode::ON);
+    mTimeStats->recordFrameDuration(1000000, 3000000);
+    mTimeStats->recordRenderEngineDuration(2000000, 4000000);
+    mTimeStats->recordRenderEngineDuration(2000000, std::make_shared<FenceTime>(3000000));
+
+    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
+    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    EXPECT_NE(nullptr, mDelegate->mCallback);
+    EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+    std::string expectedFrameDuration = buildExpectedHistogramBytestring({2}, {1});
+    std::string expectedRenderEngineTiming = buildExpectedHistogramBytestring({1, 2}, {1, 1});
+
+    {
+        InSequence seq;
+        EXPECT_CALL(*mDelegate,
+                    statsEventSetAtomId(mDelegate->mEvent,
+                                        android::util::SURFACEFLINGER_STATS_GLOBAL_INFO));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, TOTAL_FRAMES));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, MISSED_FRAMES));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, CLIENT_COMPOSITION_FRAMES));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, _));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 2));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt32(mDelegate->mEvent, DISPLAY_EVENT_CONNECTIONS));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)expectedFrameDuration.c_str(),
+                                                     expectedFrameDuration.size()),
+                                             expectedFrameDuration.size()));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)
+                                                             expectedRenderEngineTiming.c_str(),
+                                                     expectedRenderEngineTiming.size()),
+                                             expectedRenderEngineTiming.size()));
+        EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
+    }
+    EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+              mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                              mDelegate->mCookie));
+
+    SFTimeStatsGlobalProto globalProto;
+    ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+    EXPECT_EQ(0, globalProto.total_frames());
+    EXPECT_EQ(0, globalProto.missed_frames());
+    EXPECT_EQ(0, globalProto.client_composition_frames());
+    EXPECT_EQ(0, globalProto.present_to_present_size());
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_pullsAllAndClears) {
+    constexpr size_t LATE_ACQUIRE_FRAMES = 2;
+    constexpr size_t BAD_DESIRED_PRESENT_FRAMES = 3;
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    mTimeStats->onBootFinished();
+
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+    for (size_t i = 0; i < LATE_ACQUIRE_FRAMES; i++) {
+        mTimeStats->incrementLatchSkipped(LAYER_ID_0, TimeStats::LatchSkipReason::LateAcquire);
+    }
+    for (size_t i = 0; i < BAD_DESIRED_PRESENT_FRAMES; i++) {
+        mTimeStats->incrementBadDesiredPresent(LAYER_ID_0);
+    }
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    EXPECT_NE(nullptr, mDelegate->mCallback);
+    EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+    std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {1});
+    std::string expectedPostToPresent = buildExpectedHistogramBytestring({4}, {1});
+    std::string expectedAcquireToPresent = buildExpectedHistogramBytestring({3}, {1});
+    std::string expectedLatchToPresent = buildExpectedHistogramBytestring({2}, {1});
+    std::string expectedDesiredToPresent = buildExpectedHistogramBytestring({1}, {1});
+    std::string expectedPostToAcquire = buildExpectedHistogramBytestring({1}, {1});
+    {
+        InSequence seq;
+        EXPECT_CALL(*mDelegate,
+                    statsEventSetAtomId(mDelegate->mEvent,
+                                        android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteString8(mDelegate->mEvent,
+                                           StrEq(genLayerName(LAYER_ID_0).c_str())));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 1));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, 0));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)
+                                                             expectedPresentToPresent.c_str(),
+                                                     expectedPresentToPresent.size()),
+                                             expectedPresentToPresent.size()));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)expectedPostToPresent.c_str(),
+                                                     expectedPostToPresent.size()),
+                                             expectedPostToPresent.size()));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)
+                                                             expectedAcquireToPresent.c_str(),
+                                                     expectedAcquireToPresent.size()),
+                                             expectedAcquireToPresent.size()));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)expectedLatchToPresent.c_str(),
+                                                     expectedLatchToPresent.size()),
+                                             expectedLatchToPresent.size()));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)
+                                                             expectedDesiredToPresent.c_str(),
+                                                     expectedDesiredToPresent.size()),
+                                             expectedDesiredToPresent.size()));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)expectedPostToAcquire.c_str(),
+                                                     expectedPostToAcquire.size()),
+                                             expectedPostToAcquire.size()));
+        EXPECT_CALL(*mDelegate, statsEventWriteInt64(mDelegate->mEvent, LATE_ACQUIRE_FRAMES));
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteInt64(mDelegate->mEvent, BAD_DESIRED_PRESENT_FRAMES));
+        EXPECT_CALL(*mDelegate, statsEventBuild(mDelegate->mEvent));
+    }
+    EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+              mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+                                              mDelegate->mCookie));
+
+    SFTimeStatsGlobalProto globalProto;
+    ASSERT_TRUE(globalProto.ParseFromString(inputCommand(InputCommand::DUMP_ALL, FMT_PROTO)));
+
+    EXPECT_EQ(0, globalProto.stats_size());
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleLayers) {
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    mTimeStats->onBootFinished();
+
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    EXPECT_NE(nullptr, mDelegate->mCallback);
+    EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+    EXPECT_CALL(*mDelegate,
+                statsEventSetAtomId(mDelegate->mEvent,
+                                    android::util::SURFACEFLINGER_STATS_LAYER_INFO))
+            .Times(2);
+    EXPECT_CALL(*mDelegate,
+                statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_0).c_str())));
+    EXPECT_CALL(*mDelegate,
+                statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
+    EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+              mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+                                              mDelegate->mCookie));
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_pullsMultipleBuckets) {
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    mTimeStats->onBootFinished();
+
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
+
+    // Now make sure that TimeStats flushes global stats to set the callback.
+    mTimeStats->setPowerMode(PowerMode::ON);
+    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(3000000));
+    mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(5000000));
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    EXPECT_NE(nullptr, mDelegate->mCallback);
+    EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1, 2}, {2, 1});
+    {
+        InSequence seq;
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)
+                                                             expectedPresentToPresent.c_str(),
+                                                     expectedPresentToPresent.size()),
+                                             expectedPresentToPresent.size()));
+        EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
+                .Times(AnyNumber());
+    }
+    EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+              mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+                                              mDelegate->mCookie));
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_limitsHistogramBuckets) {
+    mDelegate = new FakeStatsEventDelegate;
+    mTimeStats =
+            std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate),
+                                              std::nullopt, 1);
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    mTimeStats->onBootFinished();
+
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 3, 4000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 4, 5000000);
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    EXPECT_NE(nullptr, mDelegate->mCallback);
+    EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    std::string expectedPresentToPresent = buildExpectedHistogramBytestring({1}, {2});
+    {
+        InSequence seq;
+        EXPECT_CALL(*mDelegate,
+                    statsEventWriteByteArray(mDelegate->mEvent,
+                                             BytesEq((const uint8_t*)
+                                                             expectedPresentToPresent.c_str(),
+                                                     expectedPresentToPresent.size()),
+                                             expectedPresentToPresent.size()));
+        EXPECT_CALL(*mDelegate, statsEventWriteByteArray(mDelegate->mEvent, _, _))
+                .Times(AnyNumber());
+    }
+    EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+              mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+                                              mDelegate->mCookie));
+}
+
+TEST_F(TimeStatsTest, layerStatsCallback_limitsLayers) {
+    mDelegate = new FakeStatsEventDelegate;
+    mTimeStats =
+            std::make_unique<impl::TimeStats>(std::unique_ptr<FakeStatsEventDelegate>(mDelegate), 1,
+                                              std::nullopt);
+    EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+
+    mTimeStats->onBootFinished();
+
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 2, 2000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 1, 2000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 2, 3000000);
+    insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_1, 4, 5000000);
+
+    EXPECT_THAT(mDelegate->mAtomTags,
+                UnorderedElementsAre(android::util::SURFACEFLINGER_STATS_GLOBAL_INFO,
+                                     android::util::SURFACEFLINGER_STATS_LAYER_INFO));
+    EXPECT_NE(nullptr, mDelegate->mCallback);
+    EXPECT_EQ(mTimeStats.get(), mDelegate->mCookie);
+
+    EXPECT_CALL(*mDelegate,
+                statsEventSetAtomId(mDelegate->mEvent,
+                                    android::util::SURFACEFLINGER_STATS_LAYER_INFO))
+            .Times(1);
+    EXPECT_CALL(*mDelegate,
+                statsEventWriteString8(mDelegate->mEvent, StrEq(genLayerName(LAYER_ID_1).c_str())));
+    EXPECT_EQ(AStatsManager_PULL_SUCCESS,
+              mDelegate->makePullAtomCallback(android::util::SURFACEFLINGER_STATS_LAYER_INFO,
+                                              mDelegate->mCookie));
+}
+
 TEST_F(TimeStatsTest, canSurviveMonkey) {
     if (g_noSlowTests) {
         GTEST_SKIP();
@@ -557,24 +1194,27 @@
     EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
 
     for (size_t i = 0; i < 10000000; ++i) {
-        const int32_t layerID = genRandomInt32(-1, 10);
+        const int32_t layerId = genRandomInt32(-1, 10);
         const int32_t frameNumber = genRandomInt32(1, 10);
         switch (genRandomInt32(0, 100)) {
             case 0:
                 ALOGV("removeTimeRecord");
-                ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(layerID, frameNumber));
+                ASSERT_NO_FATAL_FAILURE(mTimeStats->removeTimeRecord(layerId, frameNumber));
                 continue;
             case 1:
                 ALOGV("onDestroy");
-                ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(layerID));
+                ASSERT_NO_FATAL_FAILURE(mTimeStats->onDestroy(layerId));
                 continue;
         }
         TimeStamp type = static_cast<TimeStamp>(genRandomInt32(TIME_STAMP_BEGIN, TIME_STAMP_END));
         const int32_t ts = genRandomInt32(1, 1000000000);
-        ALOGV("type[%d], layerID[%d], frameNumber[%d], ts[%d]", type, layerID, frameNumber, ts);
-        setTimeStamp(type, layerID, frameNumber, ts);
+        ALOGV("type[%d], layerId[%d], frameNumber[%d], ts[%d]", type, layerId, frameNumber, ts);
+        setTimeStamp(type, layerId, frameNumber, ts);
     }
 }
 
 } // namespace
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
new file mode 100644
index 0000000..2a48a22
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -0,0 +1,330 @@
+/*
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "CompositionTest"
+
+#include <compositionengine/Display.h>
+#include <compositionengine/mock/DisplaySurface.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/SurfaceComposerClient.h>
+#include <log/log.h>
+#include <utils/String8.h>
+
+#include "TestableScheduler.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockMessageQueue.h"
+
+namespace android {
+
+using testing::_;
+using testing::Return;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+
+class TransactionApplicationTest : public testing::Test {
+public:
+    TransactionApplicationTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+        mFlinger.mutableEventQueue().reset(mMessageQueue);
+        setupScheduler();
+    }
+
+    ~TransactionApplicationTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+
+    void setupScheduler() {
+        auto eventThread = std::make_unique<mock::EventThread>();
+        auto sfEventThread = std::make_unique<mock::EventThread>();
+
+        EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*eventThread, createEventConnection(_, _))
+                .WillOnce(Return(
+                        new EventThreadConnection(eventThread.get(), ResyncCallback(),
+                                                  ISurfaceComposer::eConfigChangedSuppress)));
+
+        EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+                .WillOnce(Return(
+                        new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
+                                                  ISurfaceComposer::eConfigChangedSuppress)));
+
+        EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0, _)).WillRepeatedly(Return(0));
+        EXPECT_CALL(*mPrimaryDispSync, getPeriod())
+                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+
+        mFlinger.setupScheduler(std::unique_ptr<mock::DispSync>(mPrimaryDispSync),
+                                std::make_unique<mock::EventControlThread>(),
+                                std::move(eventThread), std::move(sfEventThread));
+    }
+
+    TestableScheduler* mScheduler;
+    TestableSurfaceFlinger mFlinger;
+
+    std::unique_ptr<mock::EventThread> mEventThread = std::make_unique<mock::EventThread>();
+    mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
+
+    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+    mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+
+    struct TransactionInfo {
+        Vector<ComposerState> states;
+        Vector<DisplayState> displays;
+        uint32_t flags = 0;
+        sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
+        InputWindowCommands inputWindowCommands;
+        int64_t desiredPresentTime = -1;
+        client_cache_t uncacheBuffer;
+    };
+
+    void checkEqual(TransactionInfo info, SurfaceFlinger::TransactionState state) {
+        EXPECT_EQ(0, info.states.size());
+        EXPECT_EQ(0, state.states.size());
+
+        EXPECT_EQ(0, info.displays.size());
+        EXPECT_EQ(0, state.displays.size());
+        EXPECT_EQ(info.flags, state.flags);
+        EXPECT_EQ(info.desiredPresentTime, state.desiredPresentTime);
+    }
+
+    void setupSingle(TransactionInfo& transaction, uint32_t flags, bool syncInputWindows,
+                     int64_t desiredPresentTime) {
+        mTransactionNumber++;
+        transaction.flags |= flags; // ISurfaceComposer::eSynchronous;
+        transaction.inputWindowCommands.syncInputWindows = syncInputWindows;
+        transaction.desiredPresentTime = desiredPresentTime;
+    }
+
+    void NotPlacedOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
+        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+        // called in SurfaceFlinger::signalTransaction
+        EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+        EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_)).WillOnce(Return(systemTime()));
+        TransactionInfo transaction;
+        setupSingle(transaction, flags, syncInputWindows,
+                    /*desiredPresentTime*/ -1);
+        nsecs_t applicationTime = systemTime();
+        mFlinger.setTransactionState(transaction.states, transaction.displays, transaction.flags,
+                                     transaction.applyToken, transaction.inputWindowCommands,
+                                     transaction.desiredPresentTime, transaction.uncacheBuffer,
+                                     mHasListenerCallbacks, mCallbacks);
+
+        // This transaction should not have been placed on the transaction queue.
+        // If transaction is synchronous or syncs input windows, SF
+        // applyTransactionState should time out (5s) wating for SF to commit
+        // the transaction or to receive a signal that syncInputWindows has
+        // completed.  If this is animation, it should not time out waiting.
+        nsecs_t returnedTime = systemTime();
+        if (flags & ISurfaceComposer::eSynchronous || syncInputWindows) {
+            EXPECT_GE(returnedTime, applicationTime + s2ns(5));
+        } else {
+            EXPECT_LE(returnedTime, applicationTime + s2ns(5));
+        }
+        auto transactionQueue = mFlinger.getTransactionQueue();
+        EXPECT_EQ(0, transactionQueue.size());
+    }
+
+    void PlaceOnTransactionQueue(uint32_t flags, bool syncInputWindows) {
+        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+        // called in SurfaceFlinger::signalTransaction
+        EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+        // first check will see desired present time has not passed,
+        // but afterwards it will look like the desired present time has passed
+        nsecs_t time = systemTime();
+        EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_))
+                .WillOnce(Return(time + nsecs_t(5 * 1e8)));
+        TransactionInfo transaction;
+        setupSingle(transaction, flags, syncInputWindows,
+                    /*desiredPresentTime*/ time + s2ns(1));
+        nsecs_t applicationSentTime = systemTime();
+        mFlinger.setTransactionState(transaction.states, transaction.displays, transaction.flags,
+                                     transaction.applyToken, transaction.inputWindowCommands,
+                                     transaction.desiredPresentTime, transaction.uncacheBuffer,
+                                     mHasListenerCallbacks, mCallbacks);
+
+        nsecs_t returnedTime = systemTime();
+        EXPECT_LE(returnedTime, applicationSentTime + s2ns(5));
+        // This transaction should have been placed on the transaction queue
+        auto transactionQueue = mFlinger.getTransactionQueue();
+        EXPECT_EQ(1, transactionQueue.size());
+    }
+
+    void BlockedByPriorTransaction(uint32_t flags, bool syncInputWindows) {
+        ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+        // called in SurfaceFlinger::signalTransaction
+        nsecs_t time = systemTime();
+        EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+        EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_))
+                .WillOnce(Return(time + nsecs_t(5 * 1e8)));
+        // transaction that should go on the pending thread
+        TransactionInfo transactionA;
+        setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
+                    /*desiredPresentTime*/ time + s2ns(1));
+
+        // transaction that would not have gone on the pending thread if not
+        // blocked
+        TransactionInfo transactionB;
+        setupSingle(transactionB, flags, syncInputWindows,
+                    /*desiredPresentTime*/ -1);
+
+        nsecs_t applicationSentTime = systemTime();
+        mFlinger.setTransactionState(transactionA.states, transactionA.displays, transactionA.flags,
+                                     transactionA.applyToken, transactionA.inputWindowCommands,
+                                     transactionA.desiredPresentTime, transactionA.uncacheBuffer,
+                                     mHasListenerCallbacks, mCallbacks);
+
+        // This thread should not have been blocked by the above transaction
+        // (5s is the timeout period that applyTransactionState waits for SF to
+        // commit the transaction)
+        EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
+
+        applicationSentTime = systemTime();
+        mFlinger.setTransactionState(transactionB.states, transactionB.displays, transactionB.flags,
+                                     transactionB.applyToken, transactionB.inputWindowCommands,
+                                     transactionB.desiredPresentTime, transactionB.uncacheBuffer,
+                                     mHasListenerCallbacks, mCallbacks);
+
+        // this thread should have been blocked by the above transaction
+        // if this is an animation, this thread should be blocked for 5s
+        // in setTransactionState waiting for transactionA to flush.  Otherwise,
+        // the transaction should be placed on the pending queue
+        if (flags & ISurfaceComposer::eAnimation) {
+            EXPECT_GE(systemTime(), applicationSentTime + s2ns(5));
+        } else {
+            EXPECT_LE(systemTime(), applicationSentTime + s2ns(5));
+        }
+
+        // check that there is one binder on the pending queue.
+        auto transactionQueue = mFlinger.getTransactionQueue();
+        EXPECT_EQ(1, transactionQueue.size());
+
+        auto& [applyToken, transactionStates] = *(transactionQueue.begin());
+        EXPECT_EQ(2, transactionStates.size());
+
+        auto& transactionStateA = transactionStates.front();
+        transactionStates.pop();
+        checkEqual(transactionA, transactionStateA);
+        auto& transactionStateB = transactionStates.front();
+        checkEqual(transactionB, transactionStateB);
+    }
+
+    bool mHasListenerCallbacks = false;
+    std::vector<ListenerCallbacks> mCallbacks;
+    int mTransactionNumber = 0;
+};
+
+TEST_F(TransactionApplicationTest, Flush_RemovesFromQueue) {
+    ASSERT_EQ(0, mFlinger.getTransactionQueue().size());
+    // called in SurfaceFlinger::signalTransaction
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    // nsecs_t time = systemTime();
+    EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime(_))
+            .WillOnce(Return(nsecs_t(5 * 1e8)))
+            .WillOnce(Return(s2ns(2)));
+    TransactionInfo transactionA; // transaction to go on pending queue
+    setupSingle(transactionA, /*flags*/ 0, /*syncInputWindows*/ false,
+                /*desiredPresentTime*/ s2ns(1));
+    mFlinger.setTransactionState(transactionA.states, transactionA.displays, transactionA.flags,
+                                 transactionA.applyToken, transactionA.inputWindowCommands,
+                                 transactionA.desiredPresentTime, transactionA.uncacheBuffer,
+                                 mHasListenerCallbacks, mCallbacks);
+
+    auto& transactionQueue = mFlinger.getTransactionQueue();
+    ASSERT_EQ(1, transactionQueue.size());
+
+    auto& [applyToken, transactionStates] = *(transactionQueue.begin());
+    ASSERT_EQ(1, transactionStates.size());
+
+    auto& transactionState = transactionStates.front();
+    checkEqual(transactionA, transactionState);
+
+    // because flushing uses the cached expected present time, we send an empty
+    // transaction here (sending a null applyToken to fake it as from a
+    // different process) to re-query and reset the cached expected present time
+    TransactionInfo empty;
+    empty.applyToken = sp<IBinder>();
+    mFlinger.setTransactionState(empty.states, empty.displays, empty.flags, empty.applyToken,
+                                 empty.inputWindowCommands, empty.desiredPresentTime,
+                                 empty.uncacheBuffer, mHasListenerCallbacks, mCallbacks);
+
+    // flush transaction queue should flush as desiredPresentTime has
+    // passed
+    mFlinger.flushTransactionQueues();
+
+    EXPECT_EQ(0, transactionQueue.size());
+}
+
+TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Synchronous) {
+    NotPlacedOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_Animation) {
+    NotPlacedOnTransactionQueue(ISurfaceComposer::eAnimation, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, NotPlacedOnTransactionQueue_SyncInputWindows) {
+    NotPlacedOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true);
+}
+
+TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Synchronous) {
+    PlaceOnTransactionQueue(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_Animation) {
+    PlaceOnTransactionQueue(ISurfaceComposer::eAnimation, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, PlaceOnTransactionQueue_SyncInputWindows) {
+    PlaceOnTransactionQueue(/*flags*/ 0, /*syncInputWindows*/ true);
+}
+
+TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Synchronous) {
+    BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_Animation) {
+    BlockedByPriorTransaction(ISurfaceComposer::eSynchronous, /*syncInputWindows*/ false);
+}
+
+TEST_F(TransactionApplicationTest, BlockWithPriorTransaction_SyncInputWindows) {
+    BlockedByPriorTransaction(/*flags*/ 0, /*syncInputWindows*/ true);
+}
+
+TEST_F(TransactionApplicationTest, FromHandle) {
+    sp<IBinder> badHandle;
+    auto ret = mFlinger.fromHandle(badHandle);
+    EXPECT_EQ(nullptr, ret.promote().get());
+}
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
new file mode 100644
index 0000000..be49ef3
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -0,0 +1,220 @@
+/*
+ * 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 "Scheduler/TimeKeeper.h"
+#include "Scheduler/Timer.h"
+#include "Scheduler/VSyncDispatchTimerQueue.h"
+#include "Scheduler/VSyncTracker.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <thread>
+
+using namespace testing;
+using namespace std::literals;
+
+namespace android::scheduler {
+
+template <typename Rep, typename Per>
+constexpr nsecs_t toNs(std::chrono::duration<Rep, Per> const& tp) {
+    return std::chrono::duration_cast<std::chrono::nanoseconds>(tp).count();
+}
+
+class FixedRateIdealStubTracker : public VSyncTracker {
+public:
+    FixedRateIdealStubTracker() : mPeriod{toNs(3ms)} {}
+
+    bool addVsyncTimestamp(nsecs_t) final { return true; }
+
+    nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final {
+        auto const floor = timePoint % mPeriod;
+        if (floor == 0) {
+            return timePoint;
+        }
+        return timePoint - floor + mPeriod;
+    }
+
+    nsecs_t currentPeriod() const final { return mPeriod; }
+
+    void setPeriod(nsecs_t) final {}
+    void resetModel() final {}
+    void dump(std::string&) const final {}
+
+private:
+    nsecs_t const mPeriod;
+};
+
+class VRRStubTracker : public VSyncTracker {
+public:
+    VRRStubTracker(nsecs_t period) : mPeriod{period} {}
+
+    bool addVsyncTimestamp(nsecs_t) final { return true; }
+
+    nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t time_point) const final {
+        std::lock_guard<decltype(mMutex)> lk(mMutex);
+        auto const normalized_to_base = time_point - mBase;
+        auto const floor = (normalized_to_base) % mPeriod;
+        if (floor == 0) {
+            return time_point;
+        }
+        return normalized_to_base - floor + mPeriod + mBase;
+    }
+
+    void set_interval(nsecs_t interval, nsecs_t last_known) {
+        std::lock_guard<decltype(mMutex)> lk(mMutex);
+        mPeriod = interval;
+        mBase = last_known;
+    }
+
+    nsecs_t currentPeriod() const final {
+        std::lock_guard<decltype(mMutex)> lk(mMutex);
+        return mPeriod;
+    }
+
+    void setPeriod(nsecs_t) final {}
+    void resetModel() final {}
+    void dump(std::string&) const final {}
+
+private:
+    std::mutex mutable mMutex;
+    nsecs_t mPeriod;
+    nsecs_t mBase = 0;
+};
+
+struct VSyncDispatchRealtimeTest : testing::Test {
+    static nsecs_t constexpr mDispatchGroupThreshold = toNs(100us);
+    static nsecs_t constexpr mVsyncMoveThreshold = toNs(500us);
+    static size_t constexpr mIterations = 20;
+};
+
+class RepeatingCallbackReceiver {
+public:
+    RepeatingCallbackReceiver(VSyncDispatch& dispatch, nsecs_t wl)
+          : mWorkload(wl),
+            mCallback(
+                    dispatch, [&](auto time, auto) { callback_called(time); }, "repeat0") {}
+
+    void repeatedly_schedule(size_t iterations, std::function<void(nsecs_t)> const& onEachFrame) {
+        mCallbackTimes.reserve(iterations);
+        mCallback.schedule(mWorkload, systemTime(SYSTEM_TIME_MONOTONIC) + mWorkload);
+
+        for (auto i = 0u; i < iterations - 1; i++) {
+            std::unique_lock<decltype(mMutex)> lk(mMutex);
+            mCv.wait(lk, [&] { return mCalled; });
+            mCalled = false;
+            auto last = mLastTarget;
+            lk.unlock();
+
+            onEachFrame(last);
+
+            mCallback.schedule(mWorkload, last + mWorkload);
+        }
+
+        // wait for the last callback.
+        std::unique_lock<decltype(mMutex)> lk(mMutex);
+        mCv.wait(lk, [&] { return mCalled; });
+    }
+
+    void with_callback_times(std::function<void(std::vector<nsecs_t> const&)> const& fn) const {
+        fn(mCallbackTimes);
+    }
+
+private:
+    void callback_called(nsecs_t time) {
+        std::lock_guard<decltype(mMutex)> lk(mMutex);
+        mCallbackTimes.push_back(time);
+        mCalled = true;
+        mLastTarget = time;
+        mCv.notify_all();
+    }
+
+    nsecs_t const mWorkload;
+    VSyncCallbackRegistration mCallback;
+
+    std::mutex mMutex;
+    std::condition_variable mCv;
+    bool mCalled = false;
+    nsecs_t mLastTarget = 0;
+    std::vector<nsecs_t> mCallbackTimes;
+};
+
+TEST_F(VSyncDispatchRealtimeTest, triple_alarm) {
+    FixedRateIdealStubTracker tracker;
+    VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold,
+                                     mVsyncMoveThreshold);
+
+    static size_t constexpr num_clients = 3;
+    std::array<RepeatingCallbackReceiver, num_clients>
+            cb_receiver{RepeatingCallbackReceiver(dispatch, toNs(1500us)),
+                        RepeatingCallbackReceiver(dispatch, toNs(0h)),
+                        RepeatingCallbackReceiver(dispatch, toNs(1ms))};
+
+    auto const on_each_frame = [](nsecs_t) {};
+    std::array<std::thread, num_clients> threads{
+            std::thread([&] { cb_receiver[0].repeatedly_schedule(mIterations, on_each_frame); }),
+            std::thread([&] { cb_receiver[1].repeatedly_schedule(mIterations, on_each_frame); }),
+            std::thread([&] { cb_receiver[2].repeatedly_schedule(mIterations, on_each_frame); }),
+    };
+
+    for (auto it = threads.rbegin(); it != threads.rend(); it++) {
+        it->join();
+    }
+
+    for (auto const& cbs : cb_receiver) {
+        cbs.with_callback_times([](auto times) { EXPECT_THAT(times.size(), Eq(mIterations)); });
+    }
+}
+
+// starts at 333hz, slides down to 43hz
+TEST_F(VSyncDispatchRealtimeTest, vascillating_vrr) {
+    auto next_vsync_interval = toNs(3ms);
+    VRRStubTracker tracker(next_vsync_interval);
+    VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold,
+                                     mVsyncMoveThreshold);
+
+    RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms));
+
+    auto const on_each_frame = [&](nsecs_t last_known) {
+        tracker.set_interval(next_vsync_interval += toNs(1ms), last_known);
+    };
+
+    std::thread eventThread([&] { cb_receiver.repeatedly_schedule(mIterations, on_each_frame); });
+    eventThread.join();
+
+    cb_receiver.with_callback_times([](auto times) { EXPECT_THAT(times.size(), Eq(mIterations)); });
+}
+
+// starts at 333hz, jumps to 200hz at frame 10
+TEST_F(VSyncDispatchRealtimeTest, fixed_jump) {
+    VRRStubTracker tracker(toNs(3ms));
+    VSyncDispatchTimerQueue dispatch(std::make_unique<Timer>(), tracker, mDispatchGroupThreshold,
+                                     mVsyncMoveThreshold);
+
+    RepeatingCallbackReceiver cb_receiver(dispatch, toNs(1ms));
+
+    auto jump_frame_counter = 0u;
+    auto constexpr jump_frame_at = 10u;
+    auto const on_each_frame = [&](nsecs_t last_known) {
+        if (jump_frame_counter++ == jump_frame_at) {
+            tracker.set_interval(toNs(5ms), last_known);
+        }
+    };
+    std::thread eventThread([&] { cb_receiver.repeatedly_schedule(mIterations, on_each_frame); });
+    eventThread.join();
+
+    cb_receiver.with_callback_times([](auto times) { EXPECT_THAT(times.size(), Eq(mIterations)); });
+}
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
new file mode 100644
index 0000000..d940dc5
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -0,0 +1,925 @@
+/*
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+#define LOG_NDEBUG 0
+
+#include "Scheduler/TimeKeeper.h"
+#include "Scheduler/VSyncDispatchTimerQueue.h"
+#include "Scheduler/VSyncTracker.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <thread>
+
+using namespace testing;
+using namespace std::literals;
+namespace android::scheduler {
+
+class MockVSyncTracker : public VSyncTracker {
+public:
+    MockVSyncTracker(nsecs_t period) : mPeriod{period} {
+        ON_CALL(*this, nextAnticipatedVSyncTimeFrom(_))
+                .WillByDefault(Invoke(this, &MockVSyncTracker::nextVSyncTime));
+        ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true));
+    }
+
+    MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t));
+    MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
+    MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
+    MOCK_METHOD1(setPeriod, void(nsecs_t));
+    MOCK_METHOD0(resetModel, void());
+    MOCK_CONST_METHOD1(dump, void(std::string&));
+
+    nsecs_t nextVSyncTime(nsecs_t timePoint) const {
+        if (timePoint % mPeriod == 0) {
+            return timePoint;
+        }
+        return (timePoint - (timePoint % mPeriod) + mPeriod);
+    }
+
+protected:
+    nsecs_t const mPeriod;
+};
+
+class ControllableClock : public TimeKeeper {
+public:
+    ControllableClock() {
+        ON_CALL(*this, alarmIn(_, _))
+                .WillByDefault(Invoke(this, &ControllableClock::alarmInDefaultBehavior));
+        ON_CALL(*this, now()).WillByDefault(Invoke(this, &ControllableClock::fakeTime));
+    }
+
+    MOCK_CONST_METHOD0(now, nsecs_t());
+    MOCK_METHOD2(alarmIn, void(std::function<void()> const&, nsecs_t time));
+    MOCK_METHOD0(alarmCancel, void());
+    MOCK_CONST_METHOD1(dump, void(std::string&));
+
+    void alarmInDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
+        mCallback = callback;
+        mNextCallbackTime = time + mCurrentTime;
+    }
+
+    nsecs_t fakeTime() const { return mCurrentTime; }
+
+    void advanceToNextCallback() {
+        mCurrentTime = mNextCallbackTime;
+        if (mCallback) {
+            mCallback();
+        }
+    }
+
+    void advanceBy(nsecs_t advancement) {
+        mCurrentTime += advancement;
+        if (mCurrentTime >= (mNextCallbackTime + mLag) && mCallback) {
+            mCallback();
+        }
+    };
+
+    void setLag(nsecs_t lag) { mLag = lag; }
+
+private:
+    std::function<void()> mCallback;
+    nsecs_t mNextCallbackTime = 0;
+    nsecs_t mCurrentTime = 0;
+    nsecs_t mLag = 0;
+};
+
+class CountingCallback {
+public:
+    CountingCallback(VSyncDispatch& dispatch)
+          : mDispatch(dispatch),
+            mToken(dispatch.registerCallback(std::bind(&CountingCallback::counter, this,
+                                                       std::placeholders::_1,
+                                                       std::placeholders::_2),
+                                             "test")) {}
+    ~CountingCallback() { mDispatch.unregisterCallback(mToken); }
+
+    operator VSyncDispatch::CallbackToken() const { return mToken; }
+
+    void counter(nsecs_t time, nsecs_t) { mCalls.push_back(time); }
+
+    VSyncDispatch& mDispatch;
+    VSyncDispatch::CallbackToken mToken;
+    std::vector<nsecs_t> mCalls;
+};
+
+class PausingCallback {
+public:
+    PausingCallback(VSyncDispatch& dispatch, std::chrono::milliseconds pauseAmount)
+          : mDispatch(dispatch),
+            mToken(dispatch.registerCallback(std::bind(&PausingCallback::pause, this,
+                                                       std::placeholders::_1,
+                                                       std::placeholders::_2),
+                                             "test")),
+            mRegistered(true),
+            mPauseAmount(pauseAmount) {}
+    ~PausingCallback() { unregister(); }
+
+    operator VSyncDispatch::CallbackToken() const { return mToken; }
+
+    void pause(nsecs_t, nsecs_t) {
+        std::unique_lock<std::mutex> lk(mMutex);
+        mPause = true;
+        mCv.notify_all();
+
+        mCv.wait_for(lk, mPauseAmount, [this] { return !mPause; });
+
+        mResourcePresent = (mResource.lock() != nullptr);
+    }
+
+    bool waitForPause() {
+        std::unique_lock<std::mutex> lk(mMutex);
+        auto waiting = mCv.wait_for(lk, 10s, [this] { return mPause; });
+        return waiting;
+    }
+
+    void stashResource(std::weak_ptr<void> const& resource) { mResource = resource; }
+
+    bool resourcePresent() { return mResourcePresent; }
+
+    void unpause() {
+        std::unique_lock<std::mutex> lk(mMutex);
+        mPause = false;
+        mCv.notify_all();
+    }
+
+    void unregister() {
+        if (mRegistered) {
+            mDispatch.unregisterCallback(mToken);
+            mRegistered = false;
+        }
+    }
+
+    VSyncDispatch& mDispatch;
+    VSyncDispatch::CallbackToken mToken;
+    bool mRegistered = true;
+
+    std::mutex mMutex;
+    std::condition_variable mCv;
+    bool mPause = false;
+    std::weak_ptr<void> mResource;
+    bool mResourcePresent = false;
+    std::chrono::milliseconds const mPauseAmount;
+};
+
+class VSyncDispatchTimerQueueTest : public testing::Test {
+protected:
+    std::unique_ptr<TimeKeeper> createTimeKeeper() {
+        class TimeKeeperWrapper : public TimeKeeper {
+        public:
+            TimeKeeperWrapper(TimeKeeper& control) : mControllableClock(control) {}
+            void alarmIn(std::function<void()> const& callback, nsecs_t time) final {
+                mControllableClock.alarmIn(callback, time);
+            }
+            void alarmCancel() final { mControllableClock.alarmCancel(); }
+            nsecs_t now() const final { return mControllableClock.now(); }
+            void dump(std::string&) const final {}
+
+        private:
+            TimeKeeper& mControllableClock;
+        };
+        return std::make_unique<TimeKeeperWrapper>(mMockClock);
+    }
+
+    ~VSyncDispatchTimerQueueTest() {
+        // destructor of  dispatch will cancelAlarm(). Ignore final cancel in common test.
+        Mock::VerifyAndClearExpectations(&mMockClock);
+    }
+
+    void advanceToNextCallback() { mMockClock.advanceToNextCallback(); }
+
+    NiceMock<ControllableClock> mMockClock;
+    static nsecs_t constexpr mDispatchGroupThreshold = 5;
+    nsecs_t const mPeriod = 1000;
+    nsecs_t const mVsyncMoveThreshold = 300;
+    NiceMock<MockVSyncTracker> mStubTracker{mPeriod};
+    VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
+                                      mVsyncMoveThreshold};
+};
+
+TEST_F(VSyncDispatchTimerQueueTest, unregistersSetAlarmOnDestruction) {
+    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmCancel());
+    {
+        VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
+                                          mVsyncMoveThreshold};
+        CountingCallback cb(mDispatch);
+        EXPECT_EQ(mDispatch.schedule(cb, 100, 1000), ScheduleResult::Scheduled);
+    }
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFuture) {
+    auto intended = mPeriod - 230;
+    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+
+    CountingCallback cb(mDispatch);
+    EXPECT_EQ(mDispatch.schedule(cb, 100, intended), ScheduleResult::Scheduled);
+    advanceToNextCallback();
+
+    ASSERT_THAT(cb.mCalls.size(), Eq(1));
+    EXPECT_THAT(cb.mCalls[0], Eq(mPeriod));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithAdjustmentToTrueVsync) {
+    EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000)).WillOnce(Return(1150));
+    EXPECT_CALL(mMockClock, alarmIn(_, 1050));
+
+    CountingCallback cb(mDispatch);
+    mDispatch.schedule(cb, 100, mPeriod);
+    advanceToNextCallback();
+
+    ASSERT_THAT(cb.mCalls.size(), Eq(1));
+    EXPECT_THAT(cb.mCalls[0], Eq(1150));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingAdjustmentPast) {
+    auto const now = 234;
+    mMockClock.advanceBy(234);
+    auto const workDuration = 10 * mPeriod;
+    EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + workDuration))
+            .WillOnce(Return(mPeriod * 11));
+    EXPECT_CALL(mMockClock, alarmIn(_, mPeriod - now));
+
+    CountingCallback cb(mDispatch);
+    EXPECT_EQ(mDispatch.schedule(cb, workDuration, mPeriod), ScheduleResult::Scheduled);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancel) {
+    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmCancel());
+
+    CountingCallback cb(mDispatch);
+    EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.cancel(cb), CancelResult::Cancelled);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLate) {
+    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmCancel());
+
+    CountingCallback cb(mDispatch);
+    EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+    mMockClock.advanceBy(950);
+    EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLateWhenRunning) {
+    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmCancel());
+
+    PausingCallback cb(mDispatch, std::chrono::duration_cast<std::chrono::milliseconds>(1s));
+    EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+
+    std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
+    EXPECT_TRUE(cb.waitForPause());
+    EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate);
+    cb.unpause();
+    pausingThread.join();
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, unregisterSynchronizes) {
+    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmCancel());
+
+    auto resource = std::make_shared<int>(110);
+
+    PausingCallback cb(mDispatch, 50ms);
+    cb.stashResource(resource);
+    EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
+
+    std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
+    EXPECT_TRUE(cb.waitForPause());
+
+    cb.unregister();
+    resource.reset();
+
+    cb.unpause();
+    pausingThread.join();
+
+    EXPECT_TRUE(cb.resourcePresent());
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, basicTwoAlarmSetting) {
+    EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
+            .Times(4)
+            .WillOnce(Return(1055))
+            .WillOnce(Return(1063))
+            .WillOnce(Return(1063))
+            .WillOnce(Return(1075));
+
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 955)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 813)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 162)).InSequence(seq);
+
+    CountingCallback cb0(mDispatch);
+    CountingCallback cb1(mDispatch);
+
+    mDispatch.schedule(cb0, 100, mPeriod);
+    mDispatch.schedule(cb1, 250, mPeriod);
+
+    advanceToNextCallback();
+    advanceToNextCallback();
+
+    ASSERT_THAT(cb0.mCalls.size(), Eq(1));
+    EXPECT_THAT(cb0.mCalls[0], Eq(1075));
+    ASSERT_THAT(cb1.mCalls.size(), Eq(1));
+    EXPECT_THAT(cb1.mCalls[0], Eq(1063));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, rearmsFaroutTimeoutWhenCancellingCloseOne) {
+    EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
+            .Times(4)
+            .WillOnce(Return(10000))
+            .WillOnce(Return(1000))
+            .WillOnce(Return(10000))
+            .WillOnce(Return(10000));
+
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 750)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
+
+    CountingCallback cb0(mDispatch);
+    CountingCallback cb1(mDispatch);
+
+    mDispatch.schedule(cb0, 100, mPeriod * 10);
+    mDispatch.schedule(cb1, 250, mPeriod);
+    mDispatch.cancel(cb1);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, noUnnecessaryRearmsWhenRescheduling) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
+
+    CountingCallback cb0(mDispatch);
+    CountingCallback cb1(mDispatch);
+
+    mDispatch.schedule(cb0, 400, 1000);
+    mDispatch.schedule(cb1, 200, 1000);
+    mDispatch.schedule(cb1, 300, 1000);
+    advanceToNextCallback();
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, necessaryRearmsWhenModifying) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
+
+    CountingCallback cb0(mDispatch);
+    CountingCallback cb1(mDispatch);
+
+    mDispatch.schedule(cb0, 400, 1000);
+    mDispatch.schedule(cb1, 200, 1000);
+    mDispatch.schedule(cb1, 500, 1000);
+    advanceToNextCallback();
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, modifyIntoGroup) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 990)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 10)).InSequence(seq);
+
+    auto offset = 400;
+    auto closeOffset = offset + mDispatchGroupThreshold - 1;
+    auto notCloseOffset = offset + 2 * mDispatchGroupThreshold;
+
+    CountingCallback cb0(mDispatch);
+    CountingCallback cb1(mDispatch);
+
+    mDispatch.schedule(cb0, 400, 1000);
+    mDispatch.schedule(cb1, 200, 1000);
+    mDispatch.schedule(cb1, closeOffset, 1000);
+
+    advanceToNextCallback();
+    ASSERT_THAT(cb0.mCalls.size(), Eq(1));
+    EXPECT_THAT(cb0.mCalls[0], Eq(mPeriod));
+    ASSERT_THAT(cb1.mCalls.size(), Eq(1));
+    EXPECT_THAT(cb1.mCalls[0], Eq(mPeriod));
+
+    mDispatch.schedule(cb0, 400, 2000);
+    mDispatch.schedule(cb1, notCloseOffset, 2000);
+    advanceToNextCallback();
+    ASSERT_THAT(cb1.mCalls.size(), Eq(2));
+    EXPECT_THAT(cb1.mCalls[1], Eq(2000));
+
+    advanceToNextCallback();
+    ASSERT_THAT(cb0.mCalls.size(), Eq(2));
+    EXPECT_THAT(cb0.mCalls[1], Eq(2000));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenEndingAndDoesntCancel) {
+    EXPECT_CALL(mMockClock, alarmIn(_, 900));
+    EXPECT_CALL(mMockClock, alarmIn(_, 800));
+    EXPECT_CALL(mMockClock, alarmIn(_, 100));
+    EXPECT_CALL(mMockClock, alarmCancel());
+
+    CountingCallback cb0(mDispatch);
+    CountingCallback cb1(mDispatch);
+
+    mDispatch.schedule(cb0, 100, 1000);
+    mDispatch.schedule(cb1, 200, 1000);
+    advanceToNextCallback();
+    EXPECT_EQ(mDispatch.cancel(cb0), CancelResult::Cancelled);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, setAlarmCallsAtCorrectTimeWithChangingVsync) {
+    EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
+            .Times(3)
+            .WillOnce(Return(950))
+            .WillOnce(Return(1975))
+            .WillOnce(Return(2950));
+
+    CountingCallback cb(mDispatch);
+    mDispatch.schedule(cb, 100, 920);
+
+    mMockClock.advanceBy(850);
+    EXPECT_THAT(cb.mCalls.size(), Eq(1));
+
+    mDispatch.schedule(cb, 100, 1900);
+    mMockClock.advanceBy(900);
+    EXPECT_THAT(cb.mCalls.size(), Eq(1));
+    mMockClock.advanceBy(125);
+    EXPECT_THAT(cb.mCalls.size(), Eq(2));
+
+    mDispatch.schedule(cb, 100, 2900);
+    mMockClock.advanceBy(975);
+    EXPECT_THAT(cb.mCalls.size(), Eq(3));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, callbackReentrancy) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
+
+    VSyncDispatch::CallbackToken tmp;
+    tmp = mDispatch.registerCallback([&](auto, auto) { mDispatch.schedule(tmp, 100, 2000); },
+                                     "o.o");
+
+    mDispatch.schedule(tmp, 100, 1000);
+    advanceToNextCallback();
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, callbackReentrantWithPastWakeup) {
+    VSyncDispatch::CallbackToken tmp;
+    std::optional<nsecs_t> lastTarget;
+    tmp = mDispatch.registerCallback(
+            [&](auto timestamp, auto) {
+                EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp - mVsyncMoveThreshold),
+                          ScheduleResult::Scheduled);
+                EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp), ScheduleResult::Scheduled);
+                EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp + mVsyncMoveThreshold),
+                          ScheduleResult::Scheduled);
+                lastTarget = timestamp;
+            },
+            "oo");
+
+    mDispatch.schedule(tmp, 999, 1000);
+    advanceToNextCallback();
+    EXPECT_THAT(lastTarget, Eq(1000));
+
+    advanceToNextCallback();
+    EXPECT_THAT(lastTarget, Eq(2000));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, modificationsAroundVsyncTime) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 200)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 150)).InSequence(seq);
+
+    CountingCallback cb(mDispatch);
+    mDispatch.schedule(cb, 0, 1000);
+
+    mMockClock.advanceBy(750);
+    mDispatch.schedule(cb, 50, 1000);
+
+    advanceToNextCallback();
+    mDispatch.schedule(cb, 50, 2000);
+
+    mMockClock.advanceBy(800);
+    mDispatch.schedule(cb, 100, 2000);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, lateModifications) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 400)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 350)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 950)).InSequence(seq);
+
+    CountingCallback cb0(mDispatch);
+    CountingCallback cb1(mDispatch);
+
+    mDispatch.schedule(cb0, 500, 1000);
+    mDispatch.schedule(cb1, 100, 1000);
+
+    advanceToNextCallback();
+    mDispatch.schedule(cb0, 200, 2000);
+    mDispatch.schedule(cb1, 150, 1000);
+
+    advanceToNextCallback();
+    advanceToNextCallback();
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, doesntCancelPriorValidTimerForFutureMod) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+
+    CountingCallback cb0(mDispatch);
+    CountingCallback cb1(mDispatch);
+    mDispatch.schedule(cb0, 500, 1000);
+    mDispatch.schedule(cb1, 500, 20000);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, setsTimerAfterCancellation) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
+
+    CountingCallback cb0(mDispatch);
+    mDispatch.schedule(cb0, 500, 1000);
+    mDispatch.cancel(cb0);
+    mDispatch.schedule(cb0, 100, 1000);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, makingUpIdsError) {
+    VSyncDispatch::CallbackToken token(100);
+    EXPECT_THAT(mDispatch.schedule(token, 100, 1000), Eq(ScheduleResult::Error));
+    EXPECT_THAT(mDispatch.cancel(token), Eq(CancelResult::Error));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, canMoveCallbackBackwardsInTime) {
+    CountingCallback cb0(mDispatch);
+    EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb0, 100, 1000), ScheduleResult::Scheduled);
+}
+
+// b/1450138150
+TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync) {
+    EXPECT_CALL(mMockClock, alarmIn(_, 500));
+    CountingCallback cb(mDispatch);
+    EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
+    mMockClock.advanceBy(400);
+
+    EXPECT_EQ(mDispatch.schedule(cb, 800, 1000), ScheduleResult::Scheduled);
+    advanceToNextCallback();
+    ASSERT_THAT(cb.mCalls.size(), Eq(1));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, targetOffsetMovingBackALittleCanStillSchedule) {
+    EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
+            .Times(2)
+            .WillOnce(Return(1000))
+            .WillOnce(Return(1002));
+    CountingCallback cb(mDispatch);
+    EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
+    mMockClock.advanceBy(400);
+    EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) {
+    CountingCallback cb0(mDispatch);
+    EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
+    advanceToNextCallback();
+    EXPECT_EQ(mDispatch.schedule(cb0, 1100, 2000), ScheduleResult::Scheduled);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    CountingCallback cb0(mDispatch);
+    EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
+    advanceToNextCallback();
+    EXPECT_EQ(mDispatch.schedule(cb0, 1900, 2000), ScheduleResult::Scheduled);
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) {
+    EXPECT_CALL(mMockClock, alarmIn(_, 600));
+
+    CountingCallback cb(mDispatch);
+    EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
+
+    EXPECT_EQ(mDispatch.schedule(cb, 1400, 1000), ScheduleResult::Scheduled);
+
+    advanceToNextCallback();
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, helperMove) {
+    EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
+    EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
+
+    VSyncCallbackRegistration cb(
+            mDispatch, [](auto, auto) {}, "");
+    VSyncCallbackRegistration cb1(std::move(cb));
+    cb.schedule(100, 1000);
+    cb.cancel();
+
+    cb1.schedule(500, 1000);
+    cb1.cancel();
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, helperMoveAssign) {
+    EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
+    EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
+
+    VSyncCallbackRegistration cb(
+            mDispatch, [](auto, auto) {}, "");
+    VSyncCallbackRegistration cb1(
+            mDispatch, [](auto, auto) {}, "");
+    cb1 = std::move(cb);
+    cb.schedule(100, 1000);
+    cb.cancel();
+
+    cb1.schedule(500, 1000);
+    cb1.cancel();
+}
+
+// b/154303580
+TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminent) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 1200)).InSequence(seq);
+    CountingCallback cb1(mDispatch);
+    CountingCallback cb2(mDispatch);
+
+    EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
+
+    mMockClock.setLag(100);
+    mMockClock.advanceBy(620);
+
+    EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
+    mMockClock.advanceBy(80);
+
+    EXPECT_THAT(cb1.mCalls.size(), Eq(1));
+    EXPECT_THAT(cb2.mCalls.size(), Eq(0));
+}
+
+// b/154303580.
+// If the same callback tries to reschedule itself after it's too late, timer opts to apply the
+// update later, as opposed to blocking the calling thread.
+TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminentSameCallback) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 930)).InSequence(seq);
+    CountingCallback cb(mDispatch);
+
+    EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
+
+    mMockClock.setLag(100);
+    mMockClock.advanceBy(620);
+
+    EXPECT_EQ(mDispatch.schedule(cb, 370, 2000), ScheduleResult::Scheduled);
+    mMockClock.advanceBy(80);
+
+    EXPECT_THAT(cb.mCalls.size(), Eq(1));
+}
+
+// b/154303580.
+TEST_F(VSyncDispatchTimerQueueTest, skipsRearmingWhenNotNextScheduled) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
+    CountingCallback cb1(mDispatch);
+    CountingCallback cb2(mDispatch);
+
+    EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
+
+    mMockClock.setLag(100);
+    mMockClock.advanceBy(620);
+
+    EXPECT_EQ(mDispatch.cancel(cb2), CancelResult::Cancelled);
+
+    mMockClock.advanceBy(80);
+
+    EXPECT_THAT(cb1.mCalls.size(), Eq(1));
+    EXPECT_THAT(cb2.mCalls.size(), Eq(0));
+}
+
+TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenCancelledAndIsNextScheduled) {
+    Sequence seq;
+    EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmIn(_, 1280)).InSequence(seq);
+    EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
+    CountingCallback cb1(mDispatch);
+    CountingCallback cb2(mDispatch);
+
+    EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
+    EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
+
+    mMockClock.setLag(100);
+    mMockClock.advanceBy(620);
+
+    EXPECT_EQ(mDispatch.cancel(cb1), CancelResult::Cancelled);
+
+    EXPECT_THAT(cb1.mCalls.size(), Eq(0));
+    EXPECT_THAT(cb2.mCalls.size(), Eq(0));
+    mMockClock.advanceToNextCallback();
+
+    EXPECT_THAT(cb1.mCalls.size(), Eq(0));
+    EXPECT_THAT(cb2.mCalls.size(), Eq(1));
+}
+
+class VSyncDispatchTimerQueueEntryTest : public testing::Test {
+protected:
+    nsecs_t const mPeriod = 1000;
+    nsecs_t const mVsyncMoveThreshold = 200;
+    NiceMock<MockVSyncTracker> mStubTracker{mPeriod};
+};
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, stateAfterInitialization) {
+    std::string name("basicname");
+    VSyncDispatchTimerQueueEntry entry(
+            name, [](auto, auto) {}, mVsyncMoveThreshold);
+    EXPECT_THAT(entry.name(), Eq(name));
+    EXPECT_FALSE(entry.lastExecutedVsyncTarget());
+    EXPECT_FALSE(entry.wakeupTime());
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) {
+    VSyncDispatchTimerQueueEntry entry(
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
+
+    EXPECT_FALSE(entry.wakeupTime());
+    EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    auto const wakeup = entry.wakeupTime();
+    ASSERT_TRUE(wakeup);
+    EXPECT_THAT(*wakeup, Eq(900));
+
+    entry.disarm();
+    EXPECT_FALSE(entry.wakeupTime());
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, stateSchedulingReallyLongWakeupLatency) {
+    auto const duration = 500;
+    auto const now = 8750;
+
+    EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + duration))
+            .Times(1)
+            .WillOnce(Return(10000));
+    VSyncDispatchTimerQueueEntry entry(
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
+
+    EXPECT_FALSE(entry.wakeupTime());
+    EXPECT_THAT(entry.schedule(500, 994, mStubTracker, now), Eq(ScheduleResult::Scheduled));
+    auto const wakeup = entry.wakeupTime();
+    ASSERT_TRUE(wakeup);
+    EXPECT_THAT(*wakeup, Eq(9500));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) {
+    auto callCount = 0;
+    auto vsyncCalledTime = 0;
+    auto wakeupCalledTime = 0;
+    VSyncDispatchTimerQueueEntry entry(
+            "test",
+            [&](auto vsyncTime, auto wakeupTime) {
+                callCount++;
+                vsyncCalledTime = vsyncTime;
+                wakeupCalledTime = wakeupTime;
+            },
+            mVsyncMoveThreshold);
+
+    EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    auto const wakeup = entry.wakeupTime();
+    ASSERT_TRUE(wakeup);
+    EXPECT_THAT(*wakeup, Eq(900));
+
+    entry.callback(entry.executing(), *wakeup);
+
+    EXPECT_THAT(callCount, Eq(1));
+    EXPECT_THAT(vsyncCalledTime, Eq(mPeriod));
+    EXPECT_THAT(wakeupCalledTime, Eq(*wakeup));
+    EXPECT_FALSE(entry.wakeupTime());
+    auto lastCalledTarget = entry.lastExecutedVsyncTarget();
+    ASSERT_TRUE(lastCalledTarget);
+    EXPECT_THAT(*lastCalledTarget, Eq(mPeriod));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, updateCallback) {
+    EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
+            .Times(2)
+            .WillOnce(Return(1000))
+            .WillOnce(Return(1020));
+
+    VSyncDispatchTimerQueueEntry entry(
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
+
+    EXPECT_FALSE(entry.wakeupTime());
+    entry.update(mStubTracker, 0);
+    EXPECT_FALSE(entry.wakeupTime());
+
+    EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    auto wakeup = entry.wakeupTime();
+    ASSERT_TRUE(wakeup);
+    EXPECT_THAT(wakeup, Eq(900));
+
+    entry.update(mStubTracker, 0);
+    wakeup = entry.wakeupTime();
+    ASSERT_TRUE(wakeup);
+    EXPECT_THAT(*wakeup, Eq(920));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) {
+    VSyncDispatchTimerQueueEntry entry(
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
+    EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    entry.update(mStubTracker, 0);
+
+    auto const wakeup = entry.wakeupTime();
+    ASSERT_TRUE(wakeup);
+    EXPECT_THAT(*wakeup, Eq(wakeup));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) {
+    VSyncDispatchTimerQueueEntry entry(
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
+    EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    entry.executing(); // 1000 is executing
+    // had 1000 not been executing, this could have been scheduled for time 800.
+    EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
+
+    EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(*entry.wakeupTime(), Eq(1950));
+
+    EXPECT_THAT(entry.schedule(200, 1001, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest,
+       willRequestNextEstimateWhenSnappingToNextTargettableVSync) {
+    VSyncDispatchTimerQueueEntry entry(
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
+
+    Sequence seq;
+    EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
+            .InSequence(seq)
+            .WillOnce(Return(1000));
+    EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
+            .InSequence(seq)
+            .WillOnce(Return(1000));
+    EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000 + mVsyncMoveThreshold))
+            .InSequence(seq)
+            .WillOnce(Return(2000));
+
+    EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+
+    entry.executing(); // 1000 is executing
+
+    EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) {
+    VSyncDispatchTimerQueueEntry entry(
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
+    EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+    EXPECT_THAT(entry.schedule(1200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
+}
+
+TEST_F(VSyncDispatchTimerQueueEntryTest, storesPendingUpdatesUntilUpdate) {
+    static constexpr auto effectualOffset = 200;
+    VSyncDispatchTimerQueueEntry entry(
+            "test", [](auto, auto) {}, mVsyncMoveThreshold);
+    EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
+    entry.addPendingWorkloadUpdate(100, 400);
+    entry.addPendingWorkloadUpdate(effectualOffset, 700);
+    EXPECT_TRUE(entry.hasPendingWorkloadUpdate());
+    entry.update(mStubTracker, 0);
+    EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
+    EXPECT_THAT(*entry.wakeupTime(), Eq(mPeriod - effectualOffset));
+}
+
+} // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp
new file mode 100644
index 0000000..9c1ec07
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncModulatorTest.cpp
@@ -0,0 +1,301 @@
+/*
+ * 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 "LibSurfaceFlingerUnittests"
+#define LOG_NDEBUG 0
+
+#include "Scheduler/VSyncModulator.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace testing;
+
+namespace android::scheduler {
+
+class MockScheduler : public IPhaseOffsetControl {
+public:
+    void setPhaseOffset(ConnectionHandle handle, nsecs_t phaseOffset) {
+        mPhaseOffset[handle] = phaseOffset;
+    }
+
+    nsecs_t getOffset(ConnectionHandle handle) { return mPhaseOffset[handle]; }
+
+private:
+    std::unordered_map<ConnectionHandle, nsecs_t> mPhaseOffset;
+};
+
+class VSyncModulatorTest : public testing::Test {
+protected:
+    static constexpr auto MIN_EARLY_FRAME_COUNT_TRANSACTION =
+            VSyncModulator::MIN_EARLY_FRAME_COUNT_TRANSACTION;
+    // Add a 1ms slack to avoid strange timer race conditions.
+    static constexpr auto MARGIN_FOR_TX_APPLY = VSyncModulator::MARGIN_FOR_TX_APPLY + 1ms;
+
+    // Used to enumerate the different offsets we have
+    enum {
+        SF_LATE,
+        APP_LATE,
+        SF_EARLY,
+        APP_EARLY,
+        SF_EARLY_GL,
+        APP_EARLY_GL,
+    };
+
+    std::unique_ptr<VSyncModulator> mVSyncModulator;
+    MockScheduler mMockScheduler;
+    ConnectionHandle mAppConnection{1};
+    ConnectionHandle mSfConnection{2};
+    VSyncModulator::OffsetsConfig mOffsets = {{SF_EARLY, APP_EARLY},
+                                              {SF_EARLY_GL, APP_EARLY_GL},
+                                              {SF_LATE, APP_LATE}};
+
+    void SetUp() override {
+        mVSyncModulator = std::make_unique<VSyncModulator>(mMockScheduler, mAppConnection,
+                                                           mSfConnection, mOffsets);
+        mVSyncModulator->setPhaseOffsets(mOffsets);
+
+        EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+    };
+
+    void TearDown() override { mVSyncModulator.reset(); }
+};
+
+TEST_F(VSyncModulatorTest, Normal) {
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+    }
+}
+
+TEST_F(VSyncModulatorTest, EarlyEnd) {
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->onRefreshed(false);
+    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStart) {
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->onRefreshed(false);
+    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartWithEarly) {
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Early);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->onRefreshed(false);
+    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartWithMoreTransactions) {
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+        mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
+        std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->onRefreshed(false);
+    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartAfterEarlyEnd) {
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->onRefreshed(false);
+    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+TEST_F(VSyncModulatorTest, EarlyStartAfterEarlyEndWithMoreTransactions) {
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyStart);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < 5 * MIN_EARLY_FRAME_COUNT_TRANSACTION; i++) {
+        mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::Normal);
+        std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->setTransactionStart(Scheduler::TransactionStart::EarlyEnd);
+    std::this_thread::sleep_for(MARGIN_FOR_TX_APPLY);
+    mVSyncModulator->onTransactionHandled();
+    EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+
+    for (int i = 0; i < MIN_EARLY_FRAME_COUNT_TRANSACTION - 1; i++) {
+        mVSyncModulator->onRefreshed(false);
+        EXPECT_EQ(APP_EARLY, mMockScheduler.getOffset(mAppConnection));
+        EXPECT_EQ(SF_EARLY, mMockScheduler.getOffset(mSfConnection));
+    }
+
+    mVSyncModulator->onRefreshed(false);
+    EXPECT_EQ(APP_LATE, mMockScheduler.getOffset(mAppConnection));
+    EXPECT_EQ(SF_LATE, mMockScheduler.getOffset(mSfConnection));
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
new file mode 100644
index 0000000..fc39235
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -0,0 +1,470 @@
+/*
+ * 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.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+#define LOG_NDEBUG 0
+
+#include "Scheduler/VSyncPredictor.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <algorithm>
+#include <chrono>
+#include <utility>
+
+using namespace testing;
+using namespace std::literals;
+
+namespace android::scheduler {
+
+MATCHER_P2(IsCloseTo, value, tolerance, "is within tolerance") {
+    return arg <= value + tolerance && arg >= value - tolerance;
+}
+
+std::vector<nsecs_t> generateVsyncTimestamps(size_t count, nsecs_t period, nsecs_t bias) {
+    std::vector<nsecs_t> vsyncs(count);
+    std::generate(vsyncs.begin(), vsyncs.end(),
+                  [&, n = 0]() mutable { return n++ * period + bias; });
+    return vsyncs;
+}
+
+struct VSyncPredictorTest : testing::Test {
+    nsecs_t mNow = 0;
+    nsecs_t mPeriod = 1000;
+    static constexpr size_t kHistorySize = 10;
+    static constexpr size_t kMinimumSamplesForPrediction = 6;
+    static constexpr size_t kOutlierTolerancePercent = 25;
+    static constexpr nsecs_t mMaxRoundingError = 100;
+
+    VSyncPredictor tracker{mPeriod, kHistorySize, kMinimumSamplesForPrediction,
+                           kOutlierTolerancePercent};
+};
+
+TEST_F(VSyncPredictorTest, reportsAnticipatedPeriod) {
+    auto [slope, intercept] = tracker.getVSyncPredictionModel();
+
+    EXPECT_THAT(slope, Eq(mPeriod));
+    EXPECT_THAT(intercept, Eq(0));
+
+    auto const changedPeriod = 2000;
+    tracker.setPeriod(changedPeriod);
+    std::tie(slope, intercept) = tracker.getVSyncPredictionModel();
+    EXPECT_THAT(slope, Eq(changedPeriod));
+    EXPECT_THAT(intercept, Eq(0));
+}
+
+TEST_F(VSyncPredictorTest, reportsSamplesNeededWhenHasNoDataPoints) {
+    for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+        EXPECT_TRUE(tracker.needsMoreSamples(mNow += mPeriod));
+        tracker.addVsyncTimestamp(mNow);
+    }
+    EXPECT_FALSE(tracker.needsMoreSamples(mNow));
+}
+
+TEST_F(VSyncPredictorTest, reportsSamplesNeededAfterExplicitRateChange) {
+    for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+        tracker.addVsyncTimestamp(mNow += mPeriod);
+    }
+    EXPECT_FALSE(tracker.needsMoreSamples(mNow));
+
+    auto const changedPeriod = mPeriod * 2;
+    tracker.setPeriod(changedPeriod);
+    EXPECT_TRUE(tracker.needsMoreSamples(mNow));
+
+    for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+        EXPECT_TRUE(tracker.needsMoreSamples(mNow += changedPeriod));
+        tracker.addVsyncTimestamp(mNow);
+    }
+    EXPECT_FALSE(tracker.needsMoreSamples(mNow));
+}
+
+TEST_F(VSyncPredictorTest, transitionsToModelledPointsAfterSynthetic) {
+    auto last = mNow;
+    auto const bias = 10;
+    for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+        EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(last + mPeriod));
+        mNow += mPeriod - bias;
+        last = mNow;
+        tracker.addVsyncTimestamp(mNow);
+        mNow += bias;
+    }
+
+    EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod - bias));
+    EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod - bias));
+    EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 990), Eq(mNow + 2 * mPeriod - bias));
+}
+
+TEST_F(VSyncPredictorTest, uponNotifiedOfInaccuracyUsesSynthetic) {
+    auto const slightlyLessPeriod = mPeriod - 10;
+    auto const changedPeriod = mPeriod - 1;
+    for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+        tracker.addVsyncTimestamp(mNow += slightlyLessPeriod);
+    }
+
+    EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + slightlyLessPeriod));
+    tracker.setPeriod(changedPeriod);
+    EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + changedPeriod));
+}
+
+// b/159882858
+TEST_F(VSyncPredictorTest, updatesTimebaseForSyntheticAfterIdleTime) {
+    for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+        EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
+    }
+
+    EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
+
+    auto const halfPeriod = mPeriod >> 2;
+    nsecs_t relativelyLongGapWithDrift = mPeriod * 100 + halfPeriod;
+
+    EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += relativelyLongGapWithDrift));
+
+    tracker.resetModel();
+    EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
+}
+
+TEST_F(VSyncPredictorTest, uponBadVsyncWillSwitchToSyntheticWhileRecalibrating) {
+    auto const slightlyMorePeriod = mPeriod + 10;
+    for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+        EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += slightlyMorePeriod));
+    }
+
+    EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + slightlyMorePeriod));
+
+    auto const halfPeriod = mPeriod >> 2;
+    EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += halfPeriod));
+
+    tracker.resetModel();
+    EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
+}
+
+TEST_F(VSyncPredictorTest, adaptsToFenceTimelines_60hzHighVariance) {
+    // these are precomputed simulated 16.6s vsyncs with uniform distribution +/- 1.6ms error
+    std::vector<nsecs_t> const simulatedVsyncs{
+            15492949,  32325658,  49534984,  67496129,  84652891,
+            100332564, 117737004, 132125931, 149291099, 165199602,
+    };
+    auto constexpr idealPeriod = 16600000;
+    auto constexpr expectedPeriod = 16639242;
+    auto constexpr expectedIntercept = 1049341;
+
+    tracker.setPeriod(idealPeriod);
+    for (auto const& timestamp : simulatedVsyncs) {
+        tracker.addVsyncTimestamp(timestamp);
+    }
+    auto [slope, intercept] = tracker.getVSyncPredictionModel();
+    EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
+    EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
+}
+
+TEST_F(VSyncPredictorTest, adaptsToFenceTimelines_90hzLowVariance) {
+    // these are precomputed simulated 11.1 vsyncs with uniform distribution +/- 1ms error
+    std::vector<nsecs_t> const simulatedVsyncs{
+            11167047, 22603464, 32538479, 44938134, 56321268,
+            66730346, 78062637, 88171429, 99707843, 111397621,
+    };
+    auto idealPeriod = 11110000;
+    auto expectedPeriod = 11089413;
+    auto expectedIntercept = 94421;
+
+    tracker.setPeriod(idealPeriod);
+    for (auto const& timestamp : simulatedVsyncs) {
+        tracker.addVsyncTimestamp(timestamp);
+    }
+    auto [slope, intercept] = tracker.getVSyncPredictionModel();
+    EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
+    EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
+}
+
+TEST_F(VSyncPredictorTest, adaptsToFenceTimelinesDiscontinuous_22hzLowVariance) {
+    // these are 11.1s vsyncs with low variance, randomly computed, between -1 and 1ms
+    std::vector<nsecs_t> const simulatedVsyncs{
+            45259463,   // 0
+            91511026,   // 1
+            136307650,  // 2
+            1864501714, // 40
+            1908641034, // 41
+            1955278544, // 42
+            4590180096, // 100
+            4681594994, // 102
+            5499224734, // 120
+            5591378272, // 122
+    };
+    auto idealPeriod = 45454545;
+    auto expectedPeriod = 45450152;
+    auto expectedIntercept = 469647;
+
+    tracker.setPeriod(idealPeriod);
+    for (auto const& timestamp : simulatedVsyncs) {
+        tracker.addVsyncTimestamp(timestamp);
+    }
+    auto [slope, intercept] = tracker.getVSyncPredictionModel();
+    EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
+    EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
+}
+
+TEST_F(VSyncPredictorTest, againstOutliersDiscontinuous_500hzLowVariance) {
+    std::vector<nsecs_t> const simulatedVsyncs{
+            1992548,    // 0
+            4078038,    // 1
+            6165794,    // 2
+            7958171,    // 3
+            10193537,   // 4
+            2401840200, // 1200
+            2403000000, // an outlier that should be excluded (1201 and a half)
+            2405803629, // 1202
+            2408028599, // 1203
+            2410121051, // 1204
+    };
+    auto idealPeriod = 2000000;
+    auto expectedPeriod = 1999892;
+    auto expectedIntercept = 86342;
+
+    tracker.setPeriod(idealPeriod);
+    for (auto const& timestamp : simulatedVsyncs) {
+        tracker.addVsyncTimestamp(timestamp);
+    }
+
+    auto [slope, intercept] = tracker.getVSyncPredictionModel();
+    EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
+    EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
+}
+
+TEST_F(VSyncPredictorTest, handlesVsyncChange) {
+    auto const fastPeriod = 100;
+    auto const fastTimeBase = 100;
+    auto const slowPeriod = 400;
+    auto const slowTimeBase = 800;
+    auto const simulatedVsyncsFast =
+            generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod, fastTimeBase);
+    auto const simulatedVsyncsSlow =
+            generateVsyncTimestamps(kMinimumSamplesForPrediction, slowPeriod, slowTimeBase);
+
+    tracker.setPeriod(fastPeriod);
+    for (auto const& timestamp : simulatedVsyncsFast) {
+        tracker.addVsyncTimestamp(timestamp);
+    }
+
+    auto const mMaxRoundingError = 100;
+    auto [slope, intercept] = tracker.getVSyncPredictionModel();
+    EXPECT_THAT(slope, IsCloseTo(fastPeriod, mMaxRoundingError));
+    EXPECT_THAT(intercept, IsCloseTo(0, mMaxRoundingError));
+
+    tracker.setPeriod(slowPeriod);
+    for (auto const& timestamp : simulatedVsyncsSlow) {
+        tracker.addVsyncTimestamp(timestamp);
+    }
+    std::tie(slope, intercept) = tracker.getVSyncPredictionModel();
+    EXPECT_THAT(slope, IsCloseTo(slowPeriod, mMaxRoundingError));
+    EXPECT_THAT(intercept, IsCloseTo(0, mMaxRoundingError));
+}
+
+TEST_F(VSyncPredictorTest, willBeAccurateUsingPriorResultsForRate) {
+    auto const fastPeriod = 101000;
+    auto const fastTimeBase = fastPeriod - 500;
+    auto const fastPeriod2 = 99000;
+
+    auto const slowPeriod = 400000;
+    auto const slowTimeBase = 800000 - 201;
+    auto const simulatedVsyncsFast =
+            generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod, fastTimeBase);
+    auto const simulatedVsyncsSlow =
+            generateVsyncTimestamps(kMinimumSamplesForPrediction, slowPeriod, slowTimeBase);
+    auto const simulatedVsyncsFast2 =
+            generateVsyncTimestamps(kMinimumSamplesForPrediction, fastPeriod2, fastTimeBase);
+
+    auto idealPeriod = 100000;
+    tracker.setPeriod(idealPeriod);
+    for (auto const& timestamp : simulatedVsyncsFast) {
+        tracker.addVsyncTimestamp(timestamp);
+    }
+    auto [slope, intercept] = tracker.getVSyncPredictionModel();
+    EXPECT_THAT(slope, Eq(fastPeriod));
+    EXPECT_THAT(intercept, Eq(0));
+
+    tracker.setPeriod(slowPeriod);
+    for (auto const& timestamp : simulatedVsyncsSlow) {
+        tracker.addVsyncTimestamp(timestamp);
+    }
+
+    // we had a model for 100ns mPeriod before, use that until the new samples are
+    // sufficiently built up
+    tracker.setPeriod(idealPeriod);
+    std::tie(slope, intercept) = tracker.getVSyncPredictionModel();
+    EXPECT_THAT(slope, Eq(fastPeriod));
+    EXPECT_THAT(intercept, Eq(0));
+
+    for (auto const& timestamp : simulatedVsyncsFast2) {
+        tracker.addVsyncTimestamp(timestamp);
+    }
+    std::tie(slope, intercept) = tracker.getVSyncPredictionModel();
+    EXPECT_THAT(slope, Eq(fastPeriod2));
+    EXPECT_THAT(intercept, Eq(0));
+}
+
+TEST_F(VSyncPredictorTest, willBecomeInaccurateAfterA_longTimeWithNoSamples) {
+    auto const simulatedVsyncs = generateVsyncTimestamps(kMinimumSamplesForPrediction, mPeriod, 0);
+
+    for (auto const& timestamp : simulatedVsyncs) {
+        tracker.addVsyncTimestamp(timestamp);
+    }
+    auto const mNow = *simulatedVsyncs.rbegin();
+    EXPECT_FALSE(tracker.needsMoreSamples(mNow));
+
+    // TODO: would be better to decay this as a result of the variance of the samples
+    static auto constexpr aLongTimeOut = 1000000000;
+    EXPECT_TRUE(tracker.needsMoreSamples(mNow + aLongTimeOut));
+}
+
+TEST_F(VSyncPredictorTest, idealModelPredictionsBeforeRegressionModelIsBuilt) {
+    auto const simulatedVsyncs =
+            generateVsyncTimestamps(kMinimumSamplesForPrediction + 1, mPeriod, 0);
+    nsecs_t const mNow = 0;
+    EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mPeriod));
+
+    nsecs_t const aBitOfTime = 422;
+
+    for (auto i = 0; i < kMinimumSamplesForPrediction; i++) {
+        tracker.addVsyncTimestamp(simulatedVsyncs[i]);
+        EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(simulatedVsyncs[i] + aBitOfTime),
+                    Eq(mPeriod + simulatedVsyncs[i]));
+    }
+
+    for (auto i = kMinimumSamplesForPrediction; i < simulatedVsyncs.size(); i++) {
+        tracker.addVsyncTimestamp(simulatedVsyncs[i]);
+        EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(simulatedVsyncs[i] + aBitOfTime),
+                    Eq(mPeriod + simulatedVsyncs[i]));
+    }
+}
+
+// See b/145667109, and comment in prod code under test.
+TEST_F(VSyncPredictorTest, doesNotPredictBeforeTimePointWithHigherIntercept) {
+    std::vector<nsecs_t> const simulatedVsyncs{
+            158929578733000,
+            158929306806205, // oldest TS in ringbuffer
+            158929650879052,
+            158929661969209,
+            158929684198847,
+            158929695268171,
+            158929706370359,
+    };
+    auto const idealPeriod = 11111111;
+    auto const expectedPeriod = 11113919;
+    auto const expectedIntercept = -1195945;
+
+    tracker.setPeriod(idealPeriod);
+    for (auto const& timestamp : simulatedVsyncs) {
+        tracker.addVsyncTimestamp(timestamp);
+    }
+
+    auto [slope, intercept] = tracker.getVSyncPredictionModel();
+    EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
+    EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
+
+    // (timePoint - oldestTS) % expectedPeriod works out to be: 395334
+    // (timePoint - oldestTS) / expectedPeriod works out to be: 38.96
+    // so failure to account for the offset will floor the ordinal to 38, which was in the past.
+    auto const timePoint = 158929728723871;
+    auto const prediction = tracker.nextAnticipatedVSyncTimeFrom(timePoint);
+    EXPECT_THAT(prediction, Ge(timePoint));
+}
+
+// See b/151146131
+TEST_F(VSyncPredictorTest, hasEnoughPrecision) {
+    VSyncPredictor tracker{mPeriod, 20, kMinimumSamplesForPrediction, kOutlierTolerancePercent};
+    std::vector<nsecs_t> const simulatedVsyncs{840873348817, 840890049444, 840906762675,
+                                               840923581635, 840940161584, 840956868096,
+                                               840973702473, 840990256277, 841007116851,
+                                               841023722530, 841040452167, 841057073002,
+                                               841073800920, 841090474360, 841107278632,
+                                               841123898634, 841140750875, 841157287127,
+                                               841591357014, 840856664232
+
+    };
+    auto const idealPeriod = 16666666;
+    auto const expectedPeriod = 16698426;
+    auto const expectedIntercept = 58055;
+
+    tracker.setPeriod(idealPeriod);
+    for (auto const& timestamp : simulatedVsyncs) {
+        tracker.addVsyncTimestamp(timestamp);
+    }
+
+    auto [slope, intercept] = tracker.getVSyncPredictionModel();
+    EXPECT_THAT(slope, IsCloseTo(expectedPeriod, mMaxRoundingError));
+    EXPECT_THAT(intercept, IsCloseTo(expectedIntercept, mMaxRoundingError));
+}
+
+TEST_F(VSyncPredictorTest, resetsWhenInstructed) {
+    auto const idealPeriod = 10000;
+    auto const realPeriod = 10500;
+    tracker.setPeriod(idealPeriod);
+    for (auto i = 0; i < kMinimumSamplesForPrediction; i++) {
+        tracker.addVsyncTimestamp(i * realPeriod);
+    }
+
+    EXPECT_THAT(std::get<0>(tracker.getVSyncPredictionModel()),
+                IsCloseTo(realPeriod, mMaxRoundingError));
+    tracker.resetModel();
+    EXPECT_THAT(std::get<0>(tracker.getVSyncPredictionModel()),
+                IsCloseTo(idealPeriod, mMaxRoundingError));
+}
+
+TEST_F(VSyncPredictorTest, slopeAlwaysValid) {
+    constexpr auto kNumVsyncs = 100;
+    auto invalidPeriod = mPeriod;
+    auto now = 0;
+    for (int i = 0; i < kNumVsyncs; i++) {
+        tracker.addVsyncTimestamp(now);
+        now += invalidPeriod;
+        invalidPeriod *= 0.9f;
+
+        auto [slope, intercept] = tracker.getVSyncPredictionModel();
+        EXPECT_THAT(slope, IsCloseTo(mPeriod, mPeriod * kOutlierTolerancePercent / 100.f));
+
+        // When VsyncPredictor returns the period it means that it doesn't know how to predict and
+        // it needs to get more samples
+        if (slope == mPeriod && intercept == 0) {
+            EXPECT_TRUE(tracker.needsMoreSamples(now));
+        }
+    }
+}
+
+constexpr nsecs_t operator""_years(unsigned long long years) noexcept {
+    using namespace std::chrono_literals;
+    return years * 365 * 24 * 3600 *
+            std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
+}
+TEST_F(VSyncPredictorTest, aPhoneThatHasBeenAroundAWhileCanStillComputePeriod) {
+    constexpr nsecs_t timeBase = 100_years;
+
+    for (auto i = 0; i < kHistorySize; i++) {
+        tracker.addVsyncTimestamp(timeBase + i * mPeriod);
+    }
+    auto [slope, intercept] = tracker.getVSyncPredictionModel();
+    EXPECT_THAT(slope, IsCloseTo(mPeriod, mMaxRoundingError));
+    EXPECT_THAT(intercept, Eq(0));
+}
+
+} // namespace android::scheduler
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
new file mode 100644
index 0000000..a972562
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -0,0 +1,742 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+#define LOG_NDEBUG 0
+
+#include "Scheduler/TimeKeeper.h"
+#include "Scheduler/VSyncDispatch.h"
+#include "Scheduler/VSyncReactor.h"
+#include "Scheduler/VSyncTracker.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <ui/Fence.h>
+#include <ui/FenceTime.h>
+#include <array>
+
+using namespace testing;
+using namespace std::literals;
+namespace android::scheduler {
+
+class MockVSyncTracker : public VSyncTracker {
+public:
+    MockVSyncTracker() { ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true)); }
+    MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t));
+    MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
+    MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
+    MOCK_METHOD1(setPeriod, void(nsecs_t));
+    MOCK_METHOD0(resetModel, void());
+    MOCK_CONST_METHOD1(dump, void(std::string&));
+};
+
+class VSyncTrackerWrapper : public VSyncTracker {
+public:
+    VSyncTrackerWrapper(std::shared_ptr<VSyncTracker> const& tracker) : mTracker(tracker) {}
+
+    bool addVsyncTimestamp(nsecs_t timestamp) final {
+        return mTracker->addVsyncTimestamp(timestamp);
+    }
+    nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final {
+        return mTracker->nextAnticipatedVSyncTimeFrom(timePoint);
+    }
+    nsecs_t currentPeriod() const final { return mTracker->currentPeriod(); }
+    void setPeriod(nsecs_t period) final { mTracker->setPeriod(period); }
+    void resetModel() final { mTracker->resetModel(); }
+    void dump(std::string& result) const final { mTracker->dump(result); }
+
+private:
+    std::shared_ptr<VSyncTracker> const mTracker;
+};
+
+class MockClock : public Clock {
+public:
+    MOCK_CONST_METHOD0(now, nsecs_t());
+};
+
+class ClockWrapper : public Clock {
+public:
+    ClockWrapper(std::shared_ptr<Clock> const& clock) : mClock(clock) {}
+
+    nsecs_t now() const { return mClock->now(); }
+
+private:
+    std::shared_ptr<Clock> const mClock;
+};
+
+class MockVSyncDispatch : public VSyncDispatch {
+public:
+    MOCK_METHOD2(registerCallback,
+                 CallbackToken(std::function<void(nsecs_t, nsecs_t)> const&, std::string));
+    MOCK_METHOD1(unregisterCallback, void(CallbackToken));
+    MOCK_METHOD3(schedule, ScheduleResult(CallbackToken, nsecs_t, nsecs_t));
+    MOCK_METHOD1(cancel, CancelResult(CallbackToken token));
+    MOCK_CONST_METHOD1(dump, void(std::string&));
+};
+
+class VSyncDispatchWrapper : public VSyncDispatch {
+public:
+    VSyncDispatchWrapper(std::shared_ptr<VSyncDispatch> const& dispatch) : mDispatch(dispatch) {}
+    CallbackToken registerCallback(std::function<void(nsecs_t, nsecs_t)> const& callbackFn,
+                                   std::string callbackName) final {
+        return mDispatch->registerCallback(callbackFn, callbackName);
+    }
+
+    void unregisterCallback(CallbackToken token) final { mDispatch->unregisterCallback(token); }
+
+    ScheduleResult schedule(CallbackToken token, nsecs_t workDuration,
+                            nsecs_t earliestVsync) final {
+        return mDispatch->schedule(token, workDuration, earliestVsync);
+    }
+
+    CancelResult cancel(CallbackToken token) final { return mDispatch->cancel(token); }
+
+    void dump(std::string& result) const final { return mDispatch->dump(result); }
+
+private:
+    std::shared_ptr<VSyncDispatch> const mDispatch;
+};
+
+std::shared_ptr<FenceTime> generateInvalidFence() {
+    sp<Fence> fence = new Fence();
+    return std::make_shared<FenceTime>(fence);
+}
+
+std::shared_ptr<FenceTime> generatePendingFence() {
+    sp<Fence> fence = new Fence(dup(fileno(tmpfile())));
+    return std::make_shared<FenceTime>(fence);
+}
+
+void signalFenceWithTime(std::shared_ptr<FenceTime> const& fence, nsecs_t time) {
+    FenceTime::Snapshot snap(time);
+    fence->applyTrustedSnapshot(snap);
+}
+
+std::shared_ptr<FenceTime> generateSignalledFenceWithTime(nsecs_t time) {
+    sp<Fence> fence = new Fence(dup(fileno(tmpfile())));
+    std::shared_ptr<FenceTime> ft = std::make_shared<FenceTime>(fence);
+    signalFenceWithTime(ft, time);
+    return ft;
+}
+
+class StubCallback : public DispSync::Callback {
+public:
+    void onDispSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) final {
+        std::lock_guard<std::mutex> lk(mMutex);
+        mLastCallTime = when;
+    }
+    std::optional<nsecs_t> lastCallTime() const {
+        std::lock_guard<std::mutex> lk(mMutex);
+        return mLastCallTime;
+    }
+
+private:
+    std::mutex mutable mMutex;
+    std::optional<nsecs_t> mLastCallTime GUARDED_BY(mMutex);
+};
+
+class VSyncReactorTest : public testing::Test {
+protected:
+    VSyncReactorTest()
+          : mMockDispatch(std::make_shared<NiceMock<MockVSyncDispatch>>()),
+            mMockTracker(std::make_shared<NiceMock<MockVSyncTracker>>()),
+            mMockClock(std::make_shared<NiceMock<MockClock>>()),
+            mReactor(std::make_unique<ClockWrapper>(mMockClock),
+                     std::make_unique<VSyncDispatchWrapper>(mMockDispatch),
+                     std::make_unique<VSyncTrackerWrapper>(mMockTracker), kPendingLimit,
+                     false /* supportKernelIdleTimer */) {
+        ON_CALL(*mMockClock, now()).WillByDefault(Return(mFakeNow));
+        ON_CALL(*mMockTracker, currentPeriod()).WillByDefault(Return(period));
+    }
+
+    std::shared_ptr<MockVSyncDispatch> mMockDispatch;
+    std::shared_ptr<MockVSyncTracker> mMockTracker;
+    std::shared_ptr<MockClock> mMockClock;
+    static constexpr size_t kPendingLimit = 3;
+    static constexpr nsecs_t mDummyTime = 47;
+    static constexpr nsecs_t mPhase = 3000;
+    static constexpr nsecs_t mAnotherPhase = 5200;
+    static constexpr nsecs_t period = 10000;
+    static constexpr nsecs_t mFakeVSyncTime = 2093;
+    static constexpr nsecs_t mFakeWakeupTime = 1892;
+    static constexpr nsecs_t mFakeNow = 2214;
+    static constexpr const char mName[] = "callbacky";
+    VSyncDispatch::CallbackToken const mFakeToken{2398};
+
+    nsecs_t lastCallbackTime = 0;
+    StubCallback outerCb;
+    std::function<void(nsecs_t, nsecs_t)> innerCb;
+
+    VSyncReactor mReactor;
+};
+
+TEST_F(VSyncReactorTest, addingNullFenceCheck) {
+    EXPECT_FALSE(mReactor.addPresentFence(nullptr));
+}
+
+TEST_F(VSyncReactorTest, addingInvalidFenceSignalsNeedsMoreInfo) {
+    EXPECT_TRUE(mReactor.addPresentFence(generateInvalidFence()));
+}
+
+TEST_F(VSyncReactorTest, addingSignalledFenceAddsToTracker) {
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(mDummyTime));
+    EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(mDummyTime)));
+}
+
+TEST_F(VSyncReactorTest, addingPendingFenceAddsSignalled) {
+    nsecs_t anotherDummyTime = 2919019201;
+
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(0);
+    auto pendingFence = generatePendingFence();
+    EXPECT_FALSE(mReactor.addPresentFence(pendingFence));
+    Mock::VerifyAndClearExpectations(mMockTracker.get());
+
+    signalFenceWithTime(pendingFence, mDummyTime);
+
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(mDummyTime));
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(anotherDummyTime));
+    EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(anotherDummyTime)));
+}
+
+TEST_F(VSyncReactorTest, limitsPendingFences) {
+    std::array<std::shared_ptr<FenceTime>, kPendingLimit * 2> fences;
+    std::array<nsecs_t, fences.size()> fakeTimes;
+    std::generate(fences.begin(), fences.end(), [] { return generatePendingFence(); });
+    std::generate(fakeTimes.begin(), fakeTimes.end(), [i = 10]() mutable {
+        i++;
+        return i * i;
+    });
+
+    for (auto const& fence : fences) {
+        mReactor.addPresentFence(fence);
+    }
+
+    for (auto i = fences.size() - kPendingLimit; i < fences.size(); i++) {
+        EXPECT_CALL(*mMockTracker, addVsyncTimestamp(fakeTimes[i]));
+    }
+
+    for (auto i = 0u; i < fences.size(); i++) {
+        signalFenceWithTime(fences[i], fakeTimes[i]);
+    }
+    mReactor.addPresentFence(generatePendingFence());
+}
+
+TEST_F(VSyncReactorTest, ignoresPresentFencesWhenToldTo) {
+    static constexpr size_t aFewTimes = 8;
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(mDummyTime)).Times(1);
+
+    mReactor.setIgnorePresentFences(true);
+    for (auto i = 0; i < aFewTimes; i++) {
+        mReactor.addPresentFence(generateSignalledFenceWithTime(mDummyTime));
+    }
+
+    mReactor.setIgnorePresentFences(false);
+    EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(mDummyTime)));
+}
+
+TEST_F(VSyncReactorTest, ignoresProperlyAfterAPeriodConfirmation) {
+    bool periodFlushed = true;
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(2);
+    mReactor.setIgnorePresentFences(true);
+
+    nsecs_t const newPeriod = 5000;
+    mReactor.setPeriod(newPeriod);
+
+    EXPECT_TRUE(mReactor.addResyncSample(0, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+    EXPECT_FALSE(mReactor.addResyncSample(newPeriod, std::nullopt, &periodFlushed));
+    EXPECT_TRUE(periodFlushed);
+
+    EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
+TEST_F(VSyncReactorTest, queriesTrackerForNextRefreshNow) {
+    nsecs_t const fakeTimestamp = 4839;
+    EXPECT_CALL(*mMockTracker, currentPeriod()).Times(0);
+    EXPECT_CALL(*mMockTracker, nextAnticipatedVSyncTimeFrom(_))
+            .Times(1)
+            .WillOnce(Return(fakeTimestamp));
+
+    EXPECT_THAT(mReactor.computeNextRefresh(0, mMockClock->now()), Eq(fakeTimestamp));
+}
+
+TEST_F(VSyncReactorTest, queriesTrackerForExpectedPresentTime) {
+    nsecs_t const fakeTimestamp = 4839;
+    EXPECT_CALL(*mMockTracker, currentPeriod()).Times(0);
+    EXPECT_CALL(*mMockTracker, nextAnticipatedVSyncTimeFrom(_))
+            .Times(1)
+            .WillOnce(Return(fakeTimestamp));
+
+    EXPECT_THAT(mReactor.expectedPresentTime(mMockClock->now()), Eq(fakeTimestamp));
+}
+
+TEST_F(VSyncReactorTest, queriesTrackerForNextRefreshFuture) {
+    nsecs_t const fakeTimestamp = 4839;
+    nsecs_t const fakePeriod = 1010;
+    nsecs_t const mFakeNow = 2214;
+    int const numPeriodsOut = 3;
+    EXPECT_CALL(*mMockClock, now()).WillOnce(Return(mFakeNow));
+    EXPECT_CALL(*mMockTracker, currentPeriod()).WillOnce(Return(fakePeriod));
+    EXPECT_CALL(*mMockTracker, nextAnticipatedVSyncTimeFrom(mFakeNow + numPeriodsOut * fakePeriod))
+            .WillOnce(Return(fakeTimestamp));
+    EXPECT_THAT(mReactor.computeNextRefresh(numPeriodsOut, mMockClock->now()), Eq(fakeTimestamp));
+}
+
+TEST_F(VSyncReactorTest, getPeriod) {
+    nsecs_t const fakePeriod = 1010;
+    EXPECT_CALL(*mMockTracker, currentPeriod()).WillOnce(Return(fakePeriod));
+    EXPECT_THAT(mReactor.getPeriod(), Eq(fakePeriod));
+}
+
+TEST_F(VSyncReactorTest, setPeriodCalledOnceConfirmedChange) {
+    nsecs_t const newPeriod = 5000;
+    EXPECT_CALL(*mMockTracker, setPeriod(_)).Times(0);
+    mReactor.setPeriod(newPeriod);
+
+    bool periodFlushed = true;
+    EXPECT_TRUE(mReactor.addResyncSample(10000, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+
+    EXPECT_TRUE(mReactor.addResyncSample(20000, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+
+    Mock::VerifyAndClearExpectations(mMockTracker.get());
+    EXPECT_CALL(*mMockTracker, setPeriod(newPeriod)).Times(1);
+
+    EXPECT_FALSE(mReactor.addResyncSample(25000, std::nullopt, &periodFlushed));
+    EXPECT_TRUE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, changingPeriodBackAbortsConfirmationProcess) {
+    nsecs_t sampleTime = 0;
+    nsecs_t const newPeriod = 5000;
+    mReactor.setPeriod(newPeriod);
+    bool periodFlushed = true;
+    EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+
+    EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+
+    mReactor.setPeriod(period);
+    EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, changingToAThirdPeriodWillWaitForLastPeriod) {
+    nsecs_t sampleTime = 0;
+    nsecs_t const secondPeriod = 5000;
+    nsecs_t const thirdPeriod = 2000;
+
+    mReactor.setPeriod(secondPeriod);
+    bool periodFlushed = true;
+    EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+    EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+    mReactor.setPeriod(thirdPeriod);
+    EXPECT_TRUE(mReactor.addResyncSample(sampleTime += secondPeriod, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+    EXPECT_FALSE(mReactor.addResyncSample(sampleTime += thirdPeriod, std::nullopt, &periodFlushed));
+    EXPECT_TRUE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, reportedBadTimestampFromPredictorWillReactivateHwVSync) {
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_))
+            .WillOnce(Return(false))
+            .WillOnce(Return(true))
+            .WillOnce(Return(true));
+    EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+    EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+
+    nsecs_t skewyPeriod = period >> 1;
+    bool periodFlushed = false;
+    nsecs_t sampleTime = 0;
+    EXPECT_TRUE(mReactor.addResyncSample(sampleTime += skewyPeriod, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+    EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, reportedBadTimestampFromPredictorWillReactivateHwVSyncPendingFence) {
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_))
+            .Times(2)
+            .WillOnce(Return(false))
+            .WillOnce(Return(true));
+
+    auto fence = generatePendingFence();
+    EXPECT_FALSE(mReactor.addPresentFence(fence));
+    signalFenceWithTime(fence, period >> 1);
+    EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
+TEST_F(VSyncReactorTest, presentFenceAdditionDoesNotInterruptConfirmationProcess) {
+    nsecs_t const newPeriod = 5000;
+    mReactor.setPeriod(newPeriod);
+    EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
+TEST_F(VSyncReactorTest, setPeriodCalledFirstTwoEventsNewPeriod) {
+    nsecs_t const newPeriod = 5000;
+    EXPECT_CALL(*mMockTracker, setPeriod(_)).Times(0);
+    mReactor.setPeriod(newPeriod);
+
+    bool periodFlushed = true;
+    EXPECT_TRUE(mReactor.addResyncSample(5000, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+    Mock::VerifyAndClearExpectations(mMockTracker.get());
+
+    EXPECT_CALL(*mMockTracker, setPeriod(newPeriod)).Times(1);
+    EXPECT_FALSE(mReactor.addResyncSample(10000, std::nullopt, &periodFlushed));
+    EXPECT_TRUE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, addResyncSampleTypical) {
+    nsecs_t const fakeTimestamp = 3032;
+    bool periodFlushed = false;
+
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(fakeTimestamp));
+    EXPECT_FALSE(mReactor.addResyncSample(fakeTimestamp, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, addResyncSamplePeriodChanges) {
+    bool periodFlushed = false;
+    nsecs_t const newPeriod = 4000;
+
+    mReactor.setPeriod(newPeriod);
+
+    auto time = 0;
+    auto constexpr numTimestampSubmissions = 10;
+    for (auto i = 0; i < numTimestampSubmissions; i++) {
+        time += period;
+        EXPECT_TRUE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed));
+        EXPECT_FALSE(periodFlushed);
+    }
+
+    time += newPeriod;
+    EXPECT_FALSE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed));
+    EXPECT_TRUE(periodFlushed);
+
+    for (auto i = 0; i < numTimestampSubmissions; i++) {
+        time += newPeriod;
+        EXPECT_FALSE(mReactor.addResyncSample(time, std::nullopt, &periodFlushed));
+        EXPECT_FALSE(periodFlushed);
+    }
+}
+
+TEST_F(VSyncReactorTest, addPresentFenceWhileAwaitingPeriodConfirmationRequestsHwVsync) {
+    auto time = 0;
+    bool periodFlushed = false;
+    nsecs_t const newPeriod = 4000;
+    mReactor.setPeriod(newPeriod);
+
+    time += period;
+    mReactor.addResyncSample(time, std::nullopt, &periodFlushed);
+    EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+
+    time += newPeriod;
+    mReactor.addResyncSample(time, std::nullopt, &periodFlushed);
+
+    EXPECT_FALSE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
+static nsecs_t computeWorkload(nsecs_t period, nsecs_t phase) {
+    return period - phase;
+}
+
+TEST_F(VSyncReactorTest, addEventListener) {
+    Sequence seq;
+    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+            .InSequence(seq)
+            .WillOnce(Return(mFakeToken));
+    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+            .InSequence(seq);
+    EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).Times(2).InSequence(seq);
+    EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+    mReactor.removeEventListener(&outerCb, &lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, addEventListenerTwiceChangesPhase) {
+    Sequence seq;
+    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+            .InSequence(seq)
+            .WillOnce(Return(mFakeToken));
+    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+            .InSequence(seq);
+    EXPECT_CALL(*mMockDispatch,
+                schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _)) // mFakeNow))
+            .InSequence(seq);
+    EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
+    EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+    mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, eventListenerGetsACallbackAndReschedules) {
+    Sequence seq;
+    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+            .InSequence(seq)
+            .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+            .InSequence(seq);
+    EXPECT_CALL(*mMockDispatch,
+                schedule(mFakeToken, computeWorkload(period, mPhase), mFakeVSyncTime))
+            .Times(2)
+            .InSequence(seq);
+    EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
+    EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+    ASSERT_TRUE(innerCb);
+    innerCb(mFakeVSyncTime, mFakeWakeupTime);
+    innerCb(mFakeVSyncTime, mFakeWakeupTime);
+}
+
+TEST_F(VSyncReactorTest, callbackTimestampDistributedIsWakeupTime) {
+    Sequence seq;
+    EXPECT_CALL(*mMockDispatch, registerCallback(_, _))
+            .InSequence(seq)
+            .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+            .InSequence(seq);
+    EXPECT_CALL(*mMockDispatch,
+                schedule(mFakeToken, computeWorkload(period, mPhase), mFakeVSyncTime))
+            .InSequence(seq);
+
+    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+    ASSERT_TRUE(innerCb);
+    innerCb(mFakeVSyncTime, mFakeWakeupTime);
+    EXPECT_THAT(outerCb.lastCallTime(), Optional(mFakeWakeupTime));
+}
+
+TEST_F(VSyncReactorTest, eventListenersRemovedOnDestruction) {
+    Sequence seq;
+    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+            .InSequence(seq)
+            .WillOnce(Return(mFakeToken));
+    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+            .InSequence(seq);
+    EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
+    EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+}
+
+// b/149221293
+TEST_F(VSyncReactorTest, selfRemovingEventListenerStopsCallbacks) {
+    class SelfRemovingCallback : public DispSync::Callback {
+    public:
+        SelfRemovingCallback(VSyncReactor& vsr) : mVsr(vsr) {}
+        void onDispSyncEvent(nsecs_t when, nsecs_t /*expectedVSyncTimestamp*/) final {
+            mVsr.removeEventListener(this, &when);
+        }
+
+    private:
+        VSyncReactor& mVsr;
+    } selfRemover(mReactor);
+
+    Sequence seq;
+    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+            .InSequence(seq)
+            .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+            .InSequence(seq);
+    EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).Times(2).InSequence(seq);
+    EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+    mReactor.addEventListener(mName, mPhase, &selfRemover, lastCallbackTime);
+    innerCb(0, 0);
+}
+
+TEST_F(VSyncReactorTest, addEventListenerChangePeriod) {
+    Sequence seq;
+    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+            .InSequence(seq)
+            .WillOnce(Return(mFakeToken));
+    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+            .InSequence(seq);
+    EXPECT_CALL(*mMockDispatch,
+                schedule(mFakeToken, computeWorkload(period, mAnotherPhase), mFakeNow))
+            .InSequence(seq);
+    EXPECT_CALL(*mMockDispatch, cancel(mFakeToken)).InSequence(seq);
+    EXPECT_CALL(*mMockDispatch, unregisterCallback(mFakeToken)).InSequence(seq);
+
+    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+    mReactor.addEventListener(mName, mAnotherPhase, &outerCb, lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, changingPeriodChangesOffsetsOnNextCb) {
+    static constexpr nsecs_t anotherPeriod = 23333;
+    Sequence seq;
+    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+            .InSequence(seq)
+            .WillOnce(Return(mFakeToken));
+    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), mFakeNow))
+            .InSequence(seq);
+    EXPECT_CALL(*mMockTracker, setPeriod(anotherPeriod));
+    EXPECT_CALL(*mMockDispatch,
+                schedule(mFakeToken, computeWorkload(anotherPeriod, mPhase), mFakeNow))
+            .InSequence(seq);
+
+    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+
+    bool periodFlushed = false;
+    mReactor.setPeriod(anotherPeriod);
+    EXPECT_TRUE(mReactor.addResyncSample(anotherPeriod, std::nullopt, &periodFlushed));
+    EXPECT_FALSE(mReactor.addResyncSample(anotherPeriod * 2, std::nullopt, &periodFlushed));
+
+    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, offsetsAppliedOnNextOpportunity) {
+    Sequence seq;
+    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+            .InSequence(seq)
+            .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mPhase), _))
+            .InSequence(seq)
+            .WillOnce(Return(ScheduleResult::Scheduled));
+
+    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _))
+            .InSequence(seq)
+            .WillOnce(Return(ScheduleResult::Scheduled));
+
+    EXPECT_CALL(*mMockDispatch, schedule(mFakeToken, computeWorkload(period, mAnotherPhase), _))
+            .InSequence(seq)
+            .WillOnce(Return(ScheduleResult::Scheduled));
+
+    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+    mReactor.changePhaseOffset(&outerCb, mAnotherPhase);
+    ASSERT_TRUE(innerCb);
+    innerCb(mFakeVSyncTime, mFakeWakeupTime);
+}
+
+TEST_F(VSyncReactorTest, negativeOffsetsApplied) {
+    nsecs_t const negativePhase = -4000;
+    Sequence seq;
+    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+            .InSequence(seq)
+            .WillOnce(Return(mFakeToken));
+    EXPECT_CALL(*mMockDispatch,
+                schedule(mFakeToken, computeWorkload(period, negativePhase), mFakeNow))
+            .InSequence(seq);
+    mReactor.addEventListener(mName, negativePhase, &outerCb, lastCallbackTime);
+}
+
+TEST_F(VSyncReactorTest, beginResyncResetsModel) {
+    EXPECT_CALL(*mMockTracker, resetModel());
+    mReactor.beginResync();
+}
+
+TEST_F(VSyncReactorTest, periodChangeWithGivenVsyncPeriod) {
+    bool periodFlushed = true;
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(3);
+    mReactor.setIgnorePresentFences(true);
+
+    nsecs_t const newPeriod = 5000;
+    mReactor.setPeriod(newPeriod);
+
+    EXPECT_TRUE(mReactor.addResyncSample(0, 0, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+    EXPECT_TRUE(mReactor.addResyncSample(newPeriod, 0, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+    EXPECT_FALSE(mReactor.addResyncSample(newPeriod, newPeriod, &periodFlushed));
+    EXPECT_TRUE(periodFlushed);
+
+    EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
+TEST_F(VSyncReactorTest, periodIsMeasuredIfIgnoringComposer) {
+    // Create a reactor which supports the kernel idle timer
+    auto idleReactor = VSyncReactor(std::make_unique<ClockWrapper>(mMockClock),
+                                    std::make_unique<VSyncDispatchWrapper>(mMockDispatch),
+                                    std::make_unique<VSyncTrackerWrapper>(mMockTracker),
+                                    kPendingLimit, true /* supportKernelIdleTimer */);
+
+    bool periodFlushed = true;
+    EXPECT_CALL(*mMockTracker, addVsyncTimestamp(_)).Times(5);
+    idleReactor.setIgnorePresentFences(true);
+
+    // First, set the same period, which should only be confirmed when we receive two
+    // matching callbacks
+    idleReactor.setPeriod(10000);
+    EXPECT_TRUE(idleReactor.addResyncSample(0, 0, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+    // Correct period but incorrect timestamp delta
+    EXPECT_TRUE(idleReactor.addResyncSample(0, 10000, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+    // Correct period and correct timestamp delta
+    EXPECT_FALSE(idleReactor.addResyncSample(10000, 10000, &periodFlushed));
+    EXPECT_TRUE(periodFlushed);
+
+    // Then, set a new period, which should be confirmed as soon as we receive a callback
+    // reporting the new period
+    nsecs_t const newPeriod = 5000;
+    idleReactor.setPeriod(newPeriod);
+    // Incorrect timestamp delta and period
+    EXPECT_TRUE(idleReactor.addResyncSample(20000, 10000, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+    // Incorrect timestamp delta but correct period
+    EXPECT_FALSE(idleReactor.addResyncSample(20000, 5000, &periodFlushed));
+    EXPECT_TRUE(periodFlushed);
+
+    EXPECT_TRUE(idleReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
+using VSyncReactorDeathTest = VSyncReactorTest;
+TEST_F(VSyncReactorDeathTest, invalidRemoval) {
+    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+    mReactor.removeEventListener(&outerCb, &lastCallbackTime);
+    EXPECT_DEATH(mReactor.removeEventListener(&outerCb, &lastCallbackTime), ".*");
+}
+
+TEST_F(VSyncReactorDeathTest, invalidChange) {
+    EXPECT_DEATH(mReactor.changePhaseOffset(&outerCb, mPhase), ".*");
+
+    // the current DispSync-interface usage pattern has evolved around an implementation quirk,
+    // which is a callback is assumed to always exist, and it is valid api usage to change the
+    // offset of an object that is in the removed state.
+    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+    mReactor.removeEventListener(&outerCb, &lastCallbackTime);
+    mReactor.changePhaseOffset(&outerCb, mPhase);
+}
+
+TEST_F(VSyncReactorDeathTest, cannotScheduleOnRegistration) {
+    ON_CALL(*mMockDispatch, schedule(_, _, _))
+            .WillByDefault(Return(ScheduleResult::CannotSchedule));
+    EXPECT_DEATH(mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime), ".*");
+}
+
+TEST_F(VSyncReactorDeathTest, cannotScheduleOnCallback) {
+    EXPECT_CALL(*mMockDispatch, registerCallback(_, std::string(mName)))
+            .WillOnce(DoAll(SaveArg<0>(&innerCb), Return(mFakeToken)));
+    EXPECT_CALL(*mMockDispatch, schedule(_, _, _)).WillOnce(Return(ScheduleResult::Scheduled));
+
+    mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);
+    ASSERT_TRUE(innerCb);
+    Mock::VerifyAndClearExpectations(mMockDispatch.get());
+
+    ON_CALL(*mMockDispatch, schedule(_, _, _))
+            .WillByDefault(Return(ScheduleResult::CannotSchedule));
+    EXPECT_DEATH(innerCb(mFakeVSyncTime, mFakeWakeupTime), ".*");
+}
+
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
index 7ed57b9..0780af1 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "mock/DisplayHardware/MockComposer.h"
 
 namespace android {
@@ -27,3 +31,6 @@
 } // namespace mock
 } // namespace Hwc2
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 3c7e1da..c2c5072 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -39,12 +39,13 @@
 using android::hardware::graphics::composer::V2_1::Display;
 using android::hardware::graphics::composer::V2_1::Error;
 using android::hardware::graphics::composer::V2_1::IComposer;
-using android::hardware::graphics::composer::V2_1::IComposerCallback;
 using android::hardware::graphics::composer::V2_1::Layer;
-using android::hardware::graphics::composer::V2_3::IComposerClient;
+using android::hardware::graphics::composer::V2_4::IComposerCallback;
+using android::hardware::graphics::composer::V2_4::IComposerClient;
 
 class Composer : public Hwc2::Composer {
 public:
+    using Display = android::hardware::graphics::composer::V2_1::Display;
     Composer();
     ~Composer() override;
 
@@ -71,7 +72,6 @@
     MOCK_METHOD2(getDisplayName, Error(Display, std::string*));
     MOCK_METHOD4(getDisplayRequests,
                  Error(Display, uint32_t*, std::vector<Layer>*, std::vector<uint32_t>*));
-    MOCK_METHOD2(getDisplayType, Error(Display, IComposerClient::DisplayType*));
     MOCK_METHOD2(getDozeSupport, Error(Display, bool*));
     MOCK_METHOD5(getHdrCapabilities, Error(Display, std::vector<Hdr>*, float*, float*, float*));
     MOCK_METHOD1(getPerFrameMetadataKeys,
@@ -118,10 +118,29 @@
     MOCK_METHOD4(setDisplayContentSamplingEnabled, Error(Display, bool, uint8_t, uint64_t));
     MOCK_METHOD4(getDisplayedContentSample,
                  Error(Display, uint64_t, uint64_t, DisplayedFrameStats*));
-    MOCK_METHOD2(getDisplayCapabilities, Error(Display, std::vector<DisplayCapability>*));
     MOCK_METHOD3(setLayerPerFrameMetadataBlobs,
                  Error(Display, Layer, const std::vector<IComposerClient::PerFrameMetadataBlob>&));
     MOCK_METHOD2(setDisplayBrightness, Error(Display, float));
+    MOCK_METHOD0(isVsyncPeriodSwitchSupported, bool());
+    MOCK_METHOD2(getDisplayCapabilities, Error(Display, std::vector<DisplayCapability>*));
+    MOCK_METHOD2(getDisplayConnectionType,
+                 V2_4::Error(Display, IComposerClient::DisplayConnectionType*));
+    MOCK_METHOD3(getSupportedDisplayVsyncPeriods,
+                 V2_4::Error(Display, Config, std::vector<VsyncPeriodNanos>*));
+    MOCK_METHOD2(getDisplayVsyncPeriod, V2_4::Error(Display, VsyncPeriodNanos*));
+    MOCK_METHOD4(setActiveConfigWithConstraints,
+                 V2_4::Error(Display, Config, const IComposerClient::VsyncPeriodChangeConstraints&,
+                             VsyncPeriodChangeTimeline*));
+    MOCK_METHOD2(setAutoLowLatencyMode, V2_4::Error(Display, bool));
+    MOCK_METHOD2(getSupportedContentTypes,
+                 V2_4::Error(Display, std::vector<IComposerClient::ContentType>*));
+    MOCK_METHOD2(setContentType, V2_4::Error(Display, IComposerClient::ContentType));
+    MOCK_METHOD5(setLayerGenericMetadata,
+                 V2_4::Error(Display, Layer, const std::string&, bool,
+                             const std::vector<uint8_t>&));
+    MOCK_METHOD1(getLayerGenericMetadataKeys,
+                 V2_4::Error(std::vector<IComposerClient::LayerGenericMetadataKey>*));
+    MOCK_METHOD2(getClientTargetProperty, Error(Display, IComposerClient::ClientTargetProperty*));
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
index 6dc28bc..fe99e77 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockDisplay.h
@@ -20,66 +20,82 @@
 
 #include "DisplayHardware/HWC2.h"
 
-using HWC2::Error;
-using HWC2::Layer;
+using android::HWC2::Layer;
 
 namespace android {
 namespace Hwc2 {
 namespace mock {
 
+namespace hal = android::hardware::graphics::composer::hal;
+
 class Display : public HWC2::Display {
 public:
+    using Layer = ::Layer;
+
     Display();
     ~Display();
 
-    MOCK_CONST_METHOD0(getId, hwc2_layer_t());
+    MOCK_CONST_METHOD0(getId, hal::HWDisplayId());
     MOCK_CONST_METHOD0(isConnected, bool());
     MOCK_METHOD1(setConnected, void(bool));
-    MOCK_CONST_METHOD0(getCapabilities, const std::unordered_set<HWC2::DisplayCapability>&());
+    MOCK_CONST_METHOD0(getCapabilities, const std::unordered_set<hal::DisplayCapability>&());
 
-    MOCK_METHOD0(acceptChanges, Error());
-    MOCK_METHOD1(createLayer, Error(Layer**));
-    MOCK_METHOD1(destroyLayer, Error(Layer*));
-    MOCK_CONST_METHOD1(getActiveConfig, Error(std::shared_ptr<const Config>*));
-    MOCK_CONST_METHOD1(getActiveConfigIndex, Error(int* outIndex));
-    MOCK_METHOD1(getChangedCompositionTypes, Error(std::unordered_map<Layer*, HWC2::Composition>*));
-    MOCK_CONST_METHOD1(getColorModes, Error(std::vector<android::ui::ColorMode>*));
+    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,
-                       Error(android::ui::ColorMode, std::vector<android::ui::RenderIntent>*));
-    MOCK_METHOD2(getDataspaceSaturationMatrix, Error(android::ui::Dataspace, android::mat4*));
+                       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, Error(std::string*));
+    MOCK_CONST_METHOD1(getName, hal::Error(std::string*));
     MOCK_METHOD2(getRequests,
-                 Error(HWC2::DisplayRequest*, std::unordered_map<Layer*, HWC2::LayerRequest>*));
-    MOCK_CONST_METHOD1(getType, Error(HWC2::DisplayType*));
-    MOCK_CONST_METHOD1(supportsDoze, Error(bool*));
-    MOCK_CONST_METHOD1(getHdrCapabilities, Error(android::HdrCapabilities*));
+                 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,
-                       Error(android::ui::PixelFormat*, android::ui::Dataspace*, uint8_t*));
-    MOCK_CONST_METHOD3(setDisplayContentSamplingEnabled, Error(bool, uint8_t, uint64_t));
+                       hal::Error(hal::PixelFormat*, hal::Dataspace*, uint8_t*));
+    MOCK_CONST_METHOD3(setDisplayContentSamplingEnabled, hal::Error(bool, uint8_t, uint64_t));
     MOCK_CONST_METHOD3(getDisplayedContentSample,
-                       Error(uint64_t, uint64_t, android::DisplayedFrameStats*));
-    MOCK_CONST_METHOD1(getReleaseFences,
-                       Error(std::unordered_map<Layer*, android::sp<android::Fence>>* outFences));
-    MOCK_METHOD1(present, Error(android::sp<android::Fence>*));
-    MOCK_METHOD1(setActiveConfig, Error(const std::shared_ptr<const HWC2::Display::Config>&));
+                       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,
-                 Error(uint32_t, const android::sp<android::GraphicBuffer>&,
-                       const android::sp<android::Fence>&, android::ui::Dataspace));
-    MOCK_METHOD2(setColorMode, Error(android::ui::ColorMode, android::ui::RenderIntent));
-    MOCK_METHOD2(setColorTransform, Error(const android::mat4&, android_color_transform_t));
+                 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,
-                 Error(const android::sp<android::GraphicBuffer>&,
-                       const android::sp<android::Fence>&));
-    MOCK_METHOD1(setPowerMode, Error(HWC2::PowerMode));
-    MOCK_METHOD1(setVsyncEnabled, Error(HWC2::Vsync));
-    MOCK_METHOD2(validate, Error(uint32_t*, uint32_t*));
+                 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,
-                 Error(uint32_t*, uint32_t*, android::sp<android::Fence>*, uint32_t*));
-    MOCK_CONST_METHOD1(setDisplayBrightness, Error(float));
+                 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 mock
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index 7c65f95..e22d0cf 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -29,7 +29,9 @@
     PowerAdvisor();
     ~PowerAdvisor() override;
 
+    MOCK_METHOD0(onBootFinished, void());
     MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
+    MOCK_METHOD0(notifyDisplayUpdateImminent, void());
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
index f6c4f62..1c8c44d 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.cpp
@@ -17,6 +17,7 @@
 #include "mock/MockDispSync.h"
 #include <thread>
 
+using namespace std::chrono_literals;
 namespace android {
 namespace mock {
 
@@ -54,8 +55,9 @@
 void DispSync::triggerCallback() {
     if (mCallback.callback == nullptr) return;
 
-    mCallback.callback->onDispSyncEvent(
-            std::chrono::steady_clock::now().time_since_epoch().count());
+    const std::chrono::nanoseconds now = std::chrono::steady_clock::now().time_since_epoch();
+    const auto expectedVSyncTime = now + 16ms;
+    mCallback.callback->onDispSyncEvent(now.count(), expectedVSyncTime.count());
 }
 
 } // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
index 9ca116d..b39487c 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockDispSync.h
@@ -31,15 +31,15 @@
     MOCK_METHOD0(reset, void());
     MOCK_METHOD1(addPresentFence, bool(const std::shared_ptr<FenceTime>&));
     MOCK_METHOD0(beginResync, void());
-    MOCK_METHOD2(addResyncSample, bool(nsecs_t, bool*));
+    MOCK_METHOD3(addResyncSample, bool(nsecs_t, std::optional<nsecs_t>, bool*));
     MOCK_METHOD0(endResync, void());
     MOCK_METHOD1(setPeriod, void(nsecs_t));
     MOCK_METHOD0(getPeriod, nsecs_t());
     MOCK_METHOD0(getIntendedPeriod, nsecs_t());
     MOCK_METHOD1(setRefreshSkipCount, void(int));
-    MOCK_CONST_METHOD1(computeNextRefresh, nsecs_t(int));
+    MOCK_CONST_METHOD2(computeNextRefresh, nsecs_t(int, nsecs_t));
     MOCK_METHOD1(setIgnorePresentFences, void(bool));
-    MOCK_METHOD0(expectedPresentTime, nsecs_t());
+    MOCK_METHOD1(expectedPresentTime, nsecs_t(nsecs_t));
 
     MOCK_CONST_METHOD1(dump, void(std::string&));
 
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index ed35ebf..054aaf8 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -33,14 +33,16 @@
     MOCK_METHOD0(onScreenReleased, void());
     MOCK_METHOD0(onScreenAcquired, void());
     MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
-    MOCK_METHOD2(onConfigChanged, void(PhysicalDisplayId, int32_t));
+    MOCK_METHOD3(onConfigChanged, void(PhysicalDisplayId, HwcConfigIndexType, nsecs_t));
     MOCK_CONST_METHOD1(dump, void(std::string&));
     MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
     MOCK_METHOD1(registerDisplayEventConnection,
                  status_t(const sp<android::EventThreadConnection> &));
     MOCK_METHOD2(setVsyncRate, void(uint32_t, const sp<android::EventThreadConnection> &));
     MOCK_METHOD1(requestNextVsync, void(const sp<android::EventThreadConnection> &));
+    MOCK_METHOD1(requestLatestConfig, void(const sp<android::EventThreadConnection> &));
     MOCK_METHOD1(pauseVsyncCallback, void(bool));
+    MOCK_METHOD0(getEventThreadConnectionCount, size_t());
 };
 
 } // namespace mock
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
similarity index 75%
rename from services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp
rename to services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
index a7fd667..358dfdb 100644
--- a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-#include "mock/gui/MockGraphicBufferProducer.h"
+#include "mock/MockFrameTracer.h"
 
 namespace android {
 namespace mock {
 
 // Explicit default instantiation is recommended.
-GraphicBufferProducer::GraphicBufferProducer() = default;
-GraphicBufferProducer::~GraphicBufferProducer() = default;
+FrameTracer::FrameTracer() = default;
+FrameTracer::~FrameTracer() = default;
 
 } // namespace mock
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h
new file mode 100644
index 0000000..f768b81
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h
@@ -0,0 +1,43 @@
+/*
+ * 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 "FrameTracer/FrameTracer.h"
+
+namespace android {
+namespace mock {
+
+class FrameTracer : public android::FrameTracer {
+public:
+    FrameTracer();
+    ~FrameTracer();
+
+    MOCK_METHOD0(initialize, void());
+    MOCK_METHOD0(registerDataSource, void());
+    MOCK_METHOD2(traceNewLayer, void(int32_t, const std::string&));
+    MOCK_METHOD6(traceTimestamp,
+                 void(int32_t, uint64_t, uint64_t, nsecs_t, FrameEvent::BufferEventType, nsecs_t));
+    MOCK_METHOD6(traceFence,
+                 void(int32_t, uint64_t, uint64_t, const std::shared_ptr<FenceTime>&,
+                      FrameEvent::BufferEventType, nsecs_t));
+    MOCK_METHOD0(miniDump, std::string());
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockLayer.h b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
new file mode 100644
index 0000000..078d8e07
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockLayer.h
@@ -0,0 +1,38 @@
+/*
+ * 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 "Layer.h"
+
+namespace android::mock {
+
+class MockLayer : public Layer {
+public:
+    MockLayer(SurfaceFlinger* flinger, std::string name)
+          : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 800, 600, 0, {})) {}
+    explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {}
+
+    MOCK_CONST_METHOD0(getType, const char*());
+    MOCK_METHOD0(getFrameSelectionPriority, int32_t());
+    MOCK_CONST_METHOD0(isVisible, bool());
+    MOCK_METHOD0(createClone, sp<Layer>());
+    MOCK_CONST_METHOD0(getFrameRateForLayerTree, FrameRate());
+};
+
+} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
index 97a13e4..5fb06fd 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.cpp
@@ -16,12 +16,15 @@
 
 #include "mock/MockMessageQueue.h"
 
-namespace android {
-namespace mock {
+namespace android::mock {
 
-// Explicit default instantiation is recommended.
-MessageQueue::MessageQueue() = default;
+MessageQueue::MessageQueue() {
+    ON_CALL(*this, postMessage).WillByDefault([](sp<MessageHandler>&& handler) {
+        // Execute task to prevent broken promise exception on destruction.
+        handler->handleMessage(Message());
+    });
+}
+
 MessageQueue::~MessageQueue() = default;
 
-} // namespace mock
-} // namespace android
\ No newline at end of file
+} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index 1b1c1a7..a82b583 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -21,8 +21,7 @@
 #include "Scheduler/EventThread.h"
 #include "Scheduler/MessageQueue.h"
 
-namespace android {
-namespace mock {
+namespace android::mock {
 
 class MessageQueue : public android::MessageQueue {
 public:
@@ -30,13 +29,11 @@
     ~MessageQueue() override;
 
     MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&));
-    MOCK_METHOD2(setEventThread, void(android::EventThread*, ResyncCallback));
     MOCK_METHOD1(setEventConnection, void(const sp<EventThreadConnection>& connection));
     MOCK_METHOD0(waitMessage, void());
-    MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
+    MOCK_METHOD1(postMessage, void(sp<MessageHandler>&&));
     MOCK_METHOD0(invalidate, void());
     MOCK_METHOD0(refresh, void());
 };
 
-} // namespace mock
-} // namespace android
+} // namespace android::mock
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
index 4129328..7e925b9 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "mock/MockSurfaceInterceptor.h"
 
 namespace android {
@@ -25,3 +29,6 @@
 
 } // namespace mock
 } // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
index 458b2f3..5beee1c 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
@@ -39,7 +39,7 @@
                       const Vector<DisplayState>&, uint32_t));
     MOCK_METHOD1(saveSurfaceCreation, void(const sp<const Layer>&));
     MOCK_METHOD1(saveSurfaceDeletion, void(const sp<const Layer>&));
-    MOCK_METHOD4(saveBufferUpdate, void(const sp<const Layer>&, uint32_t, uint32_t, uint64_t));
+    MOCK_METHOD4(saveBufferUpdate, void(int32_t, uint32_t, uint32_t, uint64_t));
     MOCK_METHOD1(saveDisplayCreation, void(const DisplayDeviceState&));
     MOCK_METHOD1(saveDisplayDeletion, void(int32_t));
     MOCK_METHOD2(savePowerModeUpdate, void(int32_t, int32_t));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index b1634a8..4186e2b 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -28,13 +28,23 @@
     TimeStats();
     ~TimeStats() override;
 
+    MOCK_METHOD0(onBootFinished, void());
     MOCK_METHOD3(parseArgs, void(bool, const Vector<String16>&, std::string&));
     MOCK_METHOD0(isEnabled, bool());
     MOCK_METHOD0(miniDump, std::string());
     MOCK_METHOD0(incrementTotalFrames, void());
     MOCK_METHOD0(incrementMissedFrames, void());
     MOCK_METHOD0(incrementClientCompositionFrames, void());
+    MOCK_METHOD0(incrementClientCompositionReusedFrames, void());
+    MOCK_METHOD0(incrementRefreshRateSwitches, void());
+    MOCK_METHOD0(incrementCompositionStrategyChanges, void());
+    MOCK_METHOD1(recordDisplayEventConnectionCount, void(int32_t));
+    MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t));
+    MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t));
+    MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, const std::shared_ptr<FenceTime>&));
     MOCK_METHOD4(setPostTime, void(int32_t, uint64_t, const std::string&, nsecs_t));
+    MOCK_METHOD2(incrementLatchSkipped, void(int32_t layerId, LatchSkipReason reason));
+    MOCK_METHOD1(incrementBadDesiredPresent, void(int32_t layerId));
     MOCK_METHOD3(setLatchTime, void(int32_t, uint64_t, nsecs_t));
     MOCK_METHOD3(setDesiredTime, void(int32_t, uint64_t, nsecs_t));
     MOCK_METHOD3(setAcquireTime, void(int32_t, uint64_t, nsecs_t));
@@ -43,7 +53,8 @@
     MOCK_METHOD3(setPresentFence, void(int32_t, uint64_t, const std::shared_ptr<FenceTime>&));
     MOCK_METHOD1(onDestroy, void(int32_t));
     MOCK_METHOD2(removeTimeRecord, void(int32_t, uint64_t));
-    MOCK_METHOD1(setPowerMode, void(int32_t));
+    MOCK_METHOD1(setPowerMode,
+                 void(hardware::graphics::composer::V2_4::IComposerClient::PowerMode));
     MOCK_METHOD2(recordRefreshRate, void(uint32_t, nsecs_t));
     MOCK_METHOD1(setPresentFenceGlobal, void(const std::shared_ptr<FenceTime>&));
 };
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp b/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp
deleted file mode 100644
index a17b73f..0000000
--- a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2018 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/gui/MockGraphicBufferConsumer.h"
-
-namespace android {
-namespace mock {
-
-// Explicit default instantiation is recommended.
-GraphicBufferConsumer::GraphicBufferConsumer() = default;
-GraphicBufferConsumer::~GraphicBufferConsumer() = default;
-
-} // namespace mock
-} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.h b/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.h
deleted file mode 100644
index 98f24c2..0000000
--- a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferConsumer.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2018 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 <gui/IGraphicBufferConsumer.h>
-
-#include <utils/RefBase.h>
-
-namespace android {
-namespace mock {
-
-class GraphicBufferConsumer : public BnGraphicBufferConsumer, public virtual android::RefBase {
-public:
-    GraphicBufferConsumer();
-    ~GraphicBufferConsumer() override;
-
-    MOCK_METHOD3(acquireBuffer, status_t(BufferItem*, nsecs_t, uint64_t));
-    MOCK_METHOD1(detachBuffer, status_t(int));
-    MOCK_METHOD2(attachBuffer, status_t(int*, const sp<GraphicBuffer>&));
-    MOCK_METHOD5(releaseBuffer, status_t(int, uint64_t, EGLDisplay, EGLSyncKHR, const sp<Fence>&));
-    MOCK_METHOD2(consumerConnect, status_t(const sp<IConsumerListener>&, bool));
-    MOCK_METHOD0(consumerDisconnect, status_t());
-    MOCK_METHOD1(getReleasedBuffers, status_t(uint64_t*));
-    MOCK_METHOD2(setDefaultBufferSize, status_t(uint32_t, uint32_t));
-    MOCK_METHOD1(setMaxBufferCount, status_t(int));
-    MOCK_METHOD1(setMaxAcquiredBufferCount, status_t(int));
-    MOCK_METHOD1(setConsumerName, status_t(const String8&));
-    MOCK_METHOD1(setDefaultBufferFormat, status_t(PixelFormat));
-    MOCK_METHOD1(setDefaultBufferDataSpace, status_t(android_dataspace));
-    MOCK_METHOD1(setConsumerUsageBits, status_t(uint64_t));
-    MOCK_METHOD1(setConsumerIsProtected, status_t(bool));
-    MOCK_METHOD1(setTransformHint, status_t(uint32_t));
-    MOCK_CONST_METHOD1(getSidebandStream, status_t(sp<NativeHandle>*));
-    MOCK_METHOD2(getOccupancyHistory, status_t(bool, std::vector<OccupancyTracker::Segment>*));
-    MOCK_METHOD0(discardFreeBuffers, status_t());
-    MOCK_CONST_METHOD2(dumpState, status_t(const String8&, String8*));
-};
-
-} // namespace mock
-} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.h b/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.h
deleted file mode 100644
index c98f39f..0000000
--- a/services/surfaceflinger/tests/unittests/mock/gui/MockGraphicBufferProducer.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2018 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 <gui/IGraphicBufferProducer.h>
-
-#include <utils/RefBase.h>
-
-namespace android {
-namespace mock {
-
-class GraphicBufferProducer : public BnGraphicBufferProducer, public virtual android::RefBase {
-public:
-    GraphicBufferProducer();
-    ~GraphicBufferProducer() override;
-
-    MOCK_METHOD2(requestBuffer, status_t(int, sp<GraphicBuffer>*));
-    MOCK_METHOD1(setMaxDequeuedBufferCount, status_t(int));
-    MOCK_METHOD1(setAsyncMode, status_t(bool));
-    MOCK_METHOD8(dequeueBuffer,
-                 status_t(int*, sp<Fence>*, uint32_t, uint32_t, PixelFormat, uint64_t, uint64_t*,
-                          FrameEventHistoryDelta*));
-    MOCK_METHOD1(detachBuffer, status_t(int));
-    MOCK_METHOD2(detachNextBuffer, status_t(sp<GraphicBuffer>*, sp<Fence>*));
-    MOCK_METHOD2(attachBuffer, status_t(int*, const sp<GraphicBuffer>&));
-    MOCK_METHOD3(queueBuffer, status_t(int, const QueueBufferInput&, QueueBufferOutput*));
-    MOCK_METHOD2(cancelBuffer, status_t(int, const sp<Fence>&));
-    MOCK_METHOD2(query, int(int, int*));
-    MOCK_METHOD4(connect, status_t(const sp<IProducerListener>&, int, bool, QueueBufferOutput*));
-    MOCK_METHOD2(disconnect, status_t(int, DisconnectMode));
-    MOCK_METHOD1(setSidebandStream, status_t(const sp<NativeHandle>&));
-    MOCK_METHOD4(allocateBuffers, void(uint32_t, uint32_t, PixelFormat, uint64_t));
-    MOCK_METHOD1(allowAllocation, status_t(bool));
-    MOCK_METHOD1(setGenerationNumber, status_t(uint32_t));
-    MOCK_CONST_METHOD0(getConsumerName, String8());
-    MOCK_METHOD1(setSharedBufferMode, status_t(bool));
-    MOCK_METHOD1(setAutoRefresh, status_t(bool));
-    MOCK_METHOD1(setDequeueTimeout, status_t(nsecs_t));
-    MOCK_METHOD3(getLastQueuedBuffer, status_t(sp<GraphicBuffer>*, sp<Fence>*, float[16]));
-    MOCK_METHOD1(getFrameTimestamps, void(FrameEventHistoryDelta*));
-    MOCK_CONST_METHOD1(getUniqueId, status_t(uint64_t*));
-    MOCK_CONST_METHOD1(getConsumerUsage, status_t(uint64_t*));
-};
-
-} // namespace mock
-} // namespace android
diff --git a/services/surfaceflinger/tests/utils/CallbackUtils.h b/services/surfaceflinger/tests/utils/CallbackUtils.h
new file mode 100644
index 0000000..1318deb
--- /dev/null
+++ b/services/surfaceflinger/tests/utils/CallbackUtils.h
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 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 <gtest/gtest.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+#include <ui/Fence.h>
+#include <utils/Timers.h>
+#include <thread>
+
+namespace android {
+
+namespace {
+
+struct CallbackData {
+    CallbackData() = default;
+    CallbackData(nsecs_t time, const sp<Fence>& fence,
+                 const std::vector<SurfaceControlStats>& stats)
+          : latchTime(time), presentFence(fence), surfaceControlStats(stats) {}
+
+    nsecs_t latchTime;
+    sp<Fence> presentFence;
+    std::vector<SurfaceControlStats> surfaceControlStats;
+};
+
+class ExpectedResult {
+public:
+    enum Transaction {
+        NOT_PRESENTED = 0,
+        PRESENTED,
+    };
+
+    enum Buffer {
+        NOT_ACQUIRED = 0,
+        ACQUIRED,
+    };
+
+    enum PreviousBuffer {
+        NOT_RELEASED = 0,
+        RELEASED,
+        UNKNOWN,
+    };
+
+    void reset() {
+        mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+        mExpectedSurfaceResults.clear();
+    }
+
+    void addSurface(ExpectedResult::Transaction transactionResult, const sp<SurfaceControl>& layer,
+                    ExpectedResult::Buffer bufferResult = ACQUIRED,
+                    ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
+        mTransactionResult = transactionResult;
+        mExpectedSurfaceResults.emplace(std::piecewise_construct, std::forward_as_tuple(layer),
+                                        std::forward_as_tuple(bufferResult, previousBufferResult));
+    }
+
+    void addSurfaces(ExpectedResult::Transaction transactionResult,
+                     const std::vector<sp<SurfaceControl>>& layers,
+                     ExpectedResult::Buffer bufferResult = ACQUIRED,
+                     ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
+        for (const auto& layer : layers) {
+            addSurface(transactionResult, layer, bufferResult, previousBufferResult);
+        }
+    }
+
+    void addExpectedPresentTime(nsecs_t expectedPresentTime) {
+        mExpectedPresentTime = expectedPresentTime;
+    }
+
+    void verifyCallbackData(const CallbackData& callbackData) const {
+        const auto& [latchTime, presentFence, surfaceControlStats] = callbackData;
+        if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
+            ASSERT_GE(latchTime, 0) << "bad latch time";
+            ASSERT_NE(presentFence, nullptr);
+            if (mExpectedPresentTime >= 0) {
+                ASSERT_EQ(presentFence->wait(3000), NO_ERROR);
+                ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6));
+                // if the panel is running at 30 hz, at the worst case, our expected time just
+                // misses vsync and we have to wait another 33.3ms
+                ASSERT_LE(presentFence->getSignalTime(),
+                          mExpectedPresentTime + nsecs_t(66.666666 * 1e6));
+            }
+        } else {
+            ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented";
+            ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
+        }
+
+        ASSERT_EQ(surfaceControlStats.size(), mExpectedSurfaceResults.size())
+                << "wrong number of surfaces";
+
+        for (const auto& stats : surfaceControlStats) {
+            ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control";
+
+            const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl);
+            ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end())
+                    << "unexpected surface control";
+            expectedSurfaceResult->second.verifySurfaceControlStats(stats, latchTime);
+        }
+    }
+
+private:
+    class ExpectedSurfaceResult {
+    public:
+        ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult,
+                              ExpectedResult::PreviousBuffer previousBufferResult)
+              : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
+
+        void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
+                                       nsecs_t latchTime) const {
+            const auto&
+                    [surfaceControl, latch, acquireTime, presentFence, previousReleaseFence,
+                     transformHint,
+                     frameEvents] = surfaceControlStats;
+
+            ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
+                    << "bad acquire time";
+            ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
+
+            if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
+                ASSERT_NE(previousReleaseFence, nullptr)
+                        << "failed to set release prev buffer fence";
+            } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) {
+                ASSERT_EQ(previousReleaseFence, nullptr)
+                        << "should not have set released prev buffer fence";
+            }
+        }
+
+    private:
+        ExpectedResult::Buffer mBufferResult;
+        ExpectedResult::PreviousBuffer mPreviousBufferResult;
+    };
+
+    struct SCHash {
+        std::size_t operator()(const sp<SurfaceControl>& sc) const {
+            return std::hash<IBinder*>{}(sc->getHandle().get());
+        }
+    };
+    ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+    nsecs_t mExpectedPresentTime = -1;
+    std::unordered_map<sp<SurfaceControl>, ExpectedSurfaceResult, SCHash> mExpectedSurfaceResults;
+};
+
+class CallbackHelper {
+public:
+    static void function(void* callbackContext, nsecs_t latchTime, const sp<Fence>& presentFence,
+                         const std::vector<SurfaceControlStats>& stats) {
+        if (!callbackContext) {
+            ALOGE("failed to get callback context");
+        }
+        CallbackHelper* helper = static_cast<CallbackHelper*>(callbackContext);
+        std::lock_guard lock(helper->mMutex);
+        helper->mCallbackDataQueue.emplace(latchTime, presentFence, stats);
+        helper->mConditionVariable.notify_all();
+    }
+
+    void getCallbackData(CallbackData* outData) {
+        std::unique_lock lock(mMutex);
+
+        if (mCallbackDataQueue.empty()) {
+            ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)),
+                      std::cv_status::timeout)
+                    << "did not receive callback";
+        }
+
+        *outData = std::move(mCallbackDataQueue.front());
+        mCallbackDataQueue.pop();
+    }
+
+    void verifyFinalState() {
+        // Wait to see if there are extra callbacks
+        std::this_thread::sleep_for(500ms);
+
+        std::lock_guard lock(mMutex);
+        EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received";
+        mCallbackDataQueue = {};
+    }
+
+    void* getContext() { return static_cast<void*>(this); }
+
+    std::mutex mMutex;
+    std::condition_variable mConditionVariable;
+    std::queue<CallbackData> mCallbackDataQueue;
+};
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/utils/ColorUtils.h b/services/surfaceflinger/tests/utils/ColorUtils.h
new file mode 100644
index 0000000..07916b6
--- /dev/null
+++ b/services/surfaceflinger/tests/utils/ColorUtils.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 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 <ui/ColorSpace.h>
+
+namespace android {
+
+namespace {
+
+struct Color {
+    uint8_t r;
+    uint8_t g;
+    uint8_t b;
+    uint8_t a;
+
+    static const Color RED;
+    static const Color GREEN;
+    static const Color BLUE;
+    static const Color WHITE;
+    static const Color BLACK;
+    static const Color TRANSPARENT;
+};
+
+const Color Color::RED{255, 0, 0, 255};
+const Color Color::GREEN{0, 255, 0, 255};
+const Color Color::BLUE{0, 0, 255, 255};
+const Color Color::WHITE{255, 255, 255, 255};
+const Color Color::BLACK{0, 0, 0, 255};
+const Color Color::TRANSPARENT{0, 0, 0, 0};
+
+class ColorTransformHelper {
+public:
+    static void DegammaColorSingle(half& s) {
+        if (s <= 0.03928f)
+            s = s / 12.92f;
+        else
+            s = pow((s + 0.055f) / 1.055f, 2.4f);
+    }
+
+    static void DegammaColor(half3& color) {
+        DegammaColorSingle(color.r);
+        DegammaColorSingle(color.g);
+        DegammaColorSingle(color.b);
+    }
+
+    static void GammaColorSingle(half& s) {
+        if (s <= 0.0031308f) {
+            s = s * 12.92f;
+        } else {
+            s = 1.055f * pow(s, (1.0f / 2.4f)) - 0.055f;
+        }
+    }
+
+    static void GammaColor(half3& color) {
+        GammaColorSingle(color.r);
+        GammaColorSingle(color.g);
+        GammaColorSingle(color.b);
+    }
+
+    static void applyMatrix(half3& color, const mat3& mat) {
+        half3 ret = half3(0);
+
+        for (int i = 0; i < 3; i++) {
+            for (int j = 0; j < 3; j++) {
+                ret[i] = ret[i] + color[j] * mat[j][i];
+            }
+        }
+        color = ret;
+    }
+};
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
new file mode 100644
index 0000000..5480b00
--- /dev/null
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 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 <ui/Rect.h>
+#include <utils/String8.h>
+#include "TransactionUtils.h"
+
+namespace android {
+
+namespace {
+
+// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
+// individual pixel values for testing purposes.
+class ScreenCapture : public RefBase {
+public:
+    static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
+        captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
+    }
+
+    static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
+        const auto sf = ComposerService::getComposerService();
+        SurfaceComposerClient::Transaction().apply(true);
+
+        sp<GraphicBuffer> outBuffer;
+        ASSERT_EQ(NO_ERROR, sf->captureScreen(displayToken, &outBuffer, Rect(), 0, 0, false));
+        *sc = std::make_unique<ScreenCapture>(outBuffer);
+    }
+
+    static void captureLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
+                              Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        SurfaceComposerClient::Transaction().apply(true);
+
+        sp<GraphicBuffer> outBuffer;
+        ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale));
+        *sc = std::make_unique<ScreenCapture>(outBuffer);
+    }
+
+    static void captureChildLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
+                                   Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        SurfaceComposerClient::Transaction().apply(true);
+
+        sp<GraphicBuffer> outBuffer;
+        ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale, true));
+        *sc = std::make_unique<ScreenCapture>(outBuffer);
+    }
+
+    static void captureChildLayersExcluding(
+            std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
+            std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> excludeLayers) {
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        SurfaceComposerClient::Transaction().apply(true);
+
+        sp<GraphicBuffer> outBuffer;
+        ASSERT_EQ(NO_ERROR,
+                  sf->captureLayers(parentHandle, &outBuffer, ui::Dataspace::V0_SRGB,
+                                    ui::PixelFormat::RGBA_8888, Rect::EMPTY_RECT, excludeLayers,
+                                    1.0f, true));
+        *sc = std::make_unique<ScreenCapture>(outBuffer);
+    }
+
+    void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
+        ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
+        TransactionUtils::expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
+    }
+
+    void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
+        ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
+        const bool leftBorder = rect.left > 0;
+        const bool topBorder = rect.top > 0;
+        const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth());
+        const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight());
+
+        if (topBorder) {
+            Rect top(rect.left, rect.top - 1, rect.right, rect.top);
+            if (leftBorder) {
+                top.left -= 1;
+            }
+            if (rightBorder) {
+                top.right += 1;
+            }
+            expectColor(top, color, tolerance);
+        }
+        if (leftBorder) {
+            Rect left(rect.left - 1, rect.top, rect.left, rect.bottom);
+            expectColor(left, color, tolerance);
+        }
+        if (rightBorder) {
+            Rect right(rect.right, rect.top, rect.right + 1, rect.bottom);
+            expectColor(right, color, tolerance);
+        }
+        if (bottomBorder) {
+            Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1);
+            if (leftBorder) {
+                bottom.left -= 1;
+            }
+            if (rightBorder) {
+                bottom.right += 1;
+            }
+            expectColor(bottom, color, tolerance);
+        }
+    }
+
+    void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight,
+                        const Color& bottomLeft, const Color& bottomRight, bool filtered = false,
+                        uint8_t tolerance = 0) {
+        ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0);
+
+        const int32_t centerX = rect.left + (rect.right - rect.left) / 2;
+        const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2;
+        // avoid checking borders due to unspecified filtering behavior
+        const int32_t offsetX = filtered ? 2 : 0;
+        const int32_t offsetY = filtered ? 2 : 0;
+        expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft,
+                    tolerance);
+        expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight,
+                    tolerance);
+        expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft,
+                    tolerance);
+        expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom),
+                    bottomRight, tolerance);
+    }
+
+    void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
+        ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
+        const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
+        if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
+            String8 err(String8::format("pixel @ (%3d, %3d): "
+                                        "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
+                                        x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
+            EXPECT_EQ(String8(), err) << err.string();
+        }
+    }
+
+    void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); }
+
+    void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); }
+
+    void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
+
+    explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
+        mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
+    }
+
+    ~ScreenCapture() { mOutBuffer->unlock(); }
+
+private:
+    sp<GraphicBuffer> mOutBuffer;
+    uint8_t* mPixels = nullptr;
+};
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h
new file mode 100644
index 0000000..8e1f943
--- /dev/null
+++ b/services/surfaceflinger/tests/utils/TransactionUtils.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 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 <chrono>
+
+#include <android/native_window.h>
+#include <binder/IPCThreadState.h>
+#include <gtest/gtest.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+
+#include "ColorUtils.h"
+
+namespace android {
+
+namespace {
+
+using namespace std::chrono_literals;
+using Transaction = SurfaceComposerClient::Transaction;
+
+std::ostream& operator<<(std::ostream& os, const Color& color) {
+    os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
+    return os;
+}
+
+class TransactionUtils {
+public:
+    // Fill a region with the specified color.
+    static void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect,
+                                             const Color& color) {
+        Rect r(0, 0, buffer.width, buffer.height);
+        if (!r.intersect(rect, &r)) {
+            return;
+        }
+
+        int32_t width = r.right - r.left;
+        int32_t height = r.bottom - r.top;
+
+        for (int32_t row = 0; row < height; row++) {
+            uint8_t* dst = static_cast<uint8_t*>(buffer.bits) +
+                    (buffer.stride * (r.top + row) + r.left) * 4;
+            for (int32_t column = 0; column < width; column++) {
+                dst[0] = color.r;
+                dst[1] = color.g;
+                dst[2] = color.b;
+                dst[3] = color.a;
+                dst += 4;
+            }
+        }
+    }
+
+    // Fill a region with the specified color.
+    static void fillGraphicBufferColor(const sp<GraphicBuffer>& buffer, const Rect& rect,
+                                       const Color& color) {
+        Rect r(0, 0, buffer->width, buffer->height);
+        if (!r.intersect(rect, &r)) {
+            return;
+        }
+
+        int32_t width = r.right - r.left;
+        int32_t height = r.bottom - r.top;
+
+        uint8_t* pixels;
+        buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+                     reinterpret_cast<void**>(&pixels));
+
+        for (int32_t row = 0; row < height; row++) {
+            uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4;
+            for (int32_t column = 0; column < width; column++) {
+                dst[0] = color.r;
+                dst[1] = color.g;
+                dst[2] = color.b;
+                dst[3] = color.a;
+                dst += 4;
+            }
+        }
+        buffer->unlock();
+    }
+
+    // Check if a region has the specified color.
+    static void expectBufferColor(const sp<GraphicBuffer>& outBuffer, uint8_t* pixels,
+                                  const Rect& rect, const Color& color, uint8_t tolerance) {
+        int32_t x = rect.left;
+        int32_t y = rect.top;
+        int32_t width = rect.right - rect.left;
+        int32_t height = rect.bottom - rect.top;
+
+        int32_t bufferWidth = int32_t(outBuffer->getWidth());
+        int32_t bufferHeight = int32_t(outBuffer->getHeight());
+        if (x + width > bufferWidth) {
+            x = std::min(x, bufferWidth);
+            width = bufferWidth - x;
+        }
+        if (y + height > bufferHeight) {
+            y = std::min(y, bufferHeight);
+            height = bufferHeight - y;
+        }
+
+        auto colorCompare = [tolerance](uint8_t a, uint8_t b) {
+            uint8_t tmp = a >= b ? a - b : b - a;
+            return tmp <= tolerance;
+        };
+        for (int32_t j = 0; j < height; j++) {
+            const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4;
+            for (int32_t i = 0; i < width; i++) {
+                const uint8_t expected[4] = {color.r, color.g, color.b, color.a};
+                EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare))
+                        << "pixel @ (" << x + i << ", " << y + j << "): "
+                        << "expected (" << color << "), "
+                        << "got (" << Color{src[0], src[1], src[2], src[3]} << ")";
+                src += 4;
+            }
+        }
+    }
+
+    static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, const Color& color,
+                                 bool unlock = true) {
+        fillSurfaceRGBA8(sc, color.r, color.g, color.b, unlock);
+    }
+
+    // Fill an RGBA_8888 formatted surface with a single color.
+    static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b,
+                                 bool unlock = true) {
+        ANativeWindow_Buffer outBuffer;
+        sp<Surface> s = sc->getSurface();
+        ASSERT_TRUE(s != nullptr);
+        ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
+        uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
+        for (int y = 0; y < outBuffer.height; y++) {
+            for (int x = 0; x < outBuffer.width; x++) {
+                uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
+                pixel[0] = r;
+                pixel[1] = g;
+                pixel[2] = b;
+                pixel[3] = 255;
+            }
+        }
+        if (unlock) {
+            ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+        }
+    }
+};
+
+enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY };
+
+// Environment for starting up binder threads. This is required for testing
+// virtual displays, as BufferQueue parameters may be queried over binder.
+class BinderEnvironment : public ::testing::Environment {
+public:
+    void SetUp() override { ProcessState::self()->startThreadPool(); }
+};
+
+/** RAII Wrapper around get/seteuid */
+class UIDFaker {
+    uid_t oldId;
+
+public:
+    UIDFaker(uid_t uid) {
+        oldId = geteuid();
+        seteuid(uid);
+    }
+    ~UIDFaker() { seteuid(oldId); }
+};
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index a1b45e6..667dfb9 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -14,6 +14,10 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <android/looper.h>
 #include <gui/DisplayEventReceiver.h>
 #include <utils/Looper.h>
@@ -82,3 +86,6 @@
 
     return 0;
 }
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"