Merge "Expose shared timeline counters into telemetry:"
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index 994375b..d95d04a 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -131,6 +131,34 @@
     chmod 0666 /sys/kernel/tracing/events/task/task_newtask/enable
     chmod 0666 /sys/kernel/debug/tracing/events/gpu_mem/gpu_mem_total/enable
     chmod 0666 /sys/kernel/tracing/events/gpu_mem/gpu_mem_total/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/irq_handler_entry/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/irq_handler_entry/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/irq_handler_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/irq_handler_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/softirq_entry/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/softirq_entry/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/softirq_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/softirq_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/softirq_raise/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/softirq_raise/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/tasklet_entry/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/tasklet_entry/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/tasklet_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/tasklet_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/tasklet_hi_entry/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/tasklet_hi_entry/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/irq/tasklet_hi_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/irq/tasklet_hi_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ipi/enable
+    chmod 0666 /sys/kernel/tracing/events/ipi/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ipi/ipi_entry/enable
+    chmod 0666 /sys/kernel/tracing/events/ipi/ipi_entry/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ipi/ipi_exit/enable
+    chmod 0666 /sys/kernel/tracing/events/ipi/ipi_exit/enable
+    chmod 0666 /sys/kernel/debug/tracing/events/ipi/ipi_raise/enable
+    chmod 0666 /sys/kernel/tracing/events/ipi/ipi_raise/enable
 
     # disk
     chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable
diff --git a/cmds/dumpstate/DumpstateInternal.cpp b/cmds/dumpstate/DumpstateInternal.cpp
index bbc724c..3091f6b 100644
--- a/cmds/dumpstate/DumpstateInternal.cpp
+++ b/cmds/dumpstate/DumpstateInternal.cpp
@@ -69,7 +69,7 @@
 
     static const std::vector<std::string> group_names{
         "log", "sdcard_r", "sdcard_rw", "mount", "inet", "net_bw_stats",
-            "readproc", "bluetooth", "wakelock"};
+            "readproc", "bluetooth", "wakelock", "nfc"};
     std::vector<gid_t> groups(group_names.size(), 0);
     for (size_t i = 0; i < group_names.size(); ++i) {
         grp = getgrnam(group_names[i].c_str());
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 91d5524..a81cdaf 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1636,6 +1636,8 @@
 
     /* Dump Bluetooth HCI logs */
     ds.AddDir("/data/misc/bluetooth/logs", true);
+    /* Dump Nfc NCI logs */
+    ds.AddDir("/data/misc/nfc/logs", true);
 
     if (ds.options_->do_screenshot && !ds.do_early_screenshot_) {
         MYLOGI("taking late screenshot\n");
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index bb0e5ad..1c6583e 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -239,10 +239,10 @@
     EXPECT_EQ(access(getZipFilePath().c_str(), F_OK), 0);
 }
 
-TEST_F(ZippedBugreportGenerationTest, Is3MBMBinSize) {
+TEST_F(ZippedBugreportGenerationTest, Is1MBMBinSize) {
     struct stat st;
     EXPECT_EQ(stat(getZipFilePath().c_str(), &st), 0);
-    EXPECT_GE(st.st_size, 3000000 /* 3MB */);
+    EXPECT_GE(st.st_size, 1000000 /* 1MB */);
 }
 
 TEST_F(ZippedBugreportGenerationTest, TakesBetween30And300Seconds) {
@@ -401,7 +401,7 @@
     SectionExists("batterystats", /* bytes= */ 1000);
 }
 
-TEST_F(BugreportSectionTest, WifiSectionGenerated) {
+TEST_F(BugreportSectionTest, DISABLED_WifiSectionGenerated) {
     SectionExists("wifi", /* bytes= */ 100000);
 }
 
diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp
index bd45005..7c9e3b2 100644
--- a/cmds/installd/tests/Android.bp
+++ b/cmds/installd/tests/Android.bp
@@ -41,6 +41,21 @@
         "liblogwrap",
     ],
     test_config: "installd_cache_test.xml",
+
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
 }
 
 cc_test {
@@ -66,6 +81,21 @@
         "liblogwrap",
     ],
     test_config: "installd_service_test.xml",
+
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
 }
 
 cc_test {
@@ -93,6 +123,21 @@
         "libz",
     ],
     test_config: "installd_dexopt_test.xml",
+
+    product_variables: {
+        arc: {
+            exclude_srcs: [
+                "QuotaUtils.cpp",
+            ],
+            static_libs: [
+                "libarcdiskquota",
+                "arc_services_aidl",
+            ],
+            cflags: [
+                "-DUSE_ARC",
+            ],
+        },
+    },
 }
 
 cc_test {
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index 9964888..ba6cdf1 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -479,8 +479,7 @@
 }
 
 TEST_F(ListTest, DumpVintf) {
-    const std::string expected = "<manifest version=\"2.0\" type=\"device\">\n"
-                                 "    <hal format=\"hidl\">\n"
+    const std::string expected = "    <hal format=\"hidl\">\n"
                                  "        <name>a.h.foo1</name>\n"
                                  "        <transport>hwbinder</transport>\n"
                                  "        <fqname>@1.0::IFoo/1</fqname>\n"
@@ -499,8 +498,7 @@
                                  "        <name>a.h.foo4</name>\n"
                                  "        <transport arch=\"32\">passthrough</transport>\n"
                                  "        <fqname>@4.0::IFoo/4</fqname>\n"
-                                 "    </hal>\n"
-                                 "</manifest>";
+                                 "    </hal>\n";
 
     optind = 1; // mimic Lshal::parseArg()
     EXPECT_EQ(0u, mockList->main(createArg({"lshal", "--init-vintf"})));
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index 6c3b79b..c6f656b 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -41,7 +41,6 @@
         LayerChange                 layer                   = 5;
         CropChange                  crop                    = 6;
         MatrixChange                matrix                  = 8;
-        OverrideScalingModeChange   override_scaling_mode   = 9;
         TransparentRegionHintChange transparent_region_hint = 10;
         LayerStackChange            layer_stack             = 11;
         HiddenFlagChange            hidden_flag             = 12;
@@ -55,6 +54,7 @@
         ReparentChildrenChange      reparent_children       = 20;
         BackgroundBlurRadiusChange  background_blur_radius  = 21;
         ShadowRadiusChange          shadow_radius           = 22;
+        BlurRegionsChange           blur_regions            = 23;
     }
 }
 
@@ -95,10 +95,6 @@
     required float dtdy = 4;
 }
 
-message OverrideScalingModeChange {
-    required int32 override_scaling_mode = 1;
-}
-
 message TransparentRegionHintChange {
     repeated Rectangle region = 1;
 }
@@ -212,6 +208,23 @@
     required float radius = 1;
 }
 
+message BlurRegionsChange {
+    repeated BlurRegionChange blur_regions = 1;
+}
+
+message BlurRegionChange {
+    required uint32 blur_radius = 1;
+    required float corner_radius_tl = 2;
+    required float corner_radius_tr = 3;
+    required float corner_radius_bl = 4;
+    required float corner_radius_br = 5;
+    required float alpha = 6;
+    required int32 left = 7;
+    required int32 top = 8;
+    required int32 right = 9;
+    required int32 bottom = 10;
+}
+
 message Origin {
     required int32 pid = 1;
     required int32 uid = 2;
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 86e4f5d..5849212 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -387,10 +387,6 @@
             case SurfaceChange::SurfaceChangeCase::kMatrix:
                 setMatrix(transaction, change.id(), change.matrix());
                 break;
-            case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode:
-                setOverrideScalingMode(transaction, change.id(),
-                        change.override_scaling_mode());
-                break;
             case SurfaceChange::SurfaceChangeCase::kTransparentRegionHint:
                 setTransparentRegionHint(transaction, change.id(),
                         change.transparent_region_hint());
@@ -427,6 +423,9 @@
             case SurfaceChange::SurfaceChangeCase::kShadowRadius:
                 setShadowRadiusChange(transaction, change.id(), change.shadow_radius());
                 break;
+            case SurfaceChange::SurfaceChangeCase::kBlurRegions:
+                setBlurRegionsChange(transaction, change.id(), change.blur_regions());
+                break;
             default:
                 status = 1;
                 break;
@@ -525,12 +524,6 @@
     t.setMatrix(mLayers[id], mc.dsdx(), mc.dtdx(), mc.dsdy(), mc.dtdy());
 }
 
-void Replayer::setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
-        layer_id id, const OverrideScalingModeChange& osmc) {
-    ALOGV("Layer %d: Setting Override Scaling Mode -- mode=%d", id, osmc.override_scaling_mode());
-    t.setOverrideScalingMode(mLayers[id], osmc.override_scaling_mode());
-}
-
 void Replayer::setTransparentRegionHint(SurfaceComposerClient::Transaction& t,
         layer_id id, const TransparentRegionHintChange& trhc) {
     ALOGV("Setting Transparent Region Hint");
@@ -738,3 +731,24 @@
         layer_id id, const ShadowRadiusChange& c) {
     t.setShadowRadius(mLayers[id], c.radius());
 }
+
+void Replayer::setBlurRegionsChange(SurfaceComposerClient::Transaction& t,
+        layer_id id, const BlurRegionsChange& c) {
+    std::vector<BlurRegion> regions;
+    for(size_t i=0; i < c.blur_regions_size(); i++) {
+        auto protoRegion = c.blur_regions(i);
+        regions.push_back(BlurRegion{
+            .blurRadius = protoRegion.blur_radius(),
+            .alpha = protoRegion.alpha(),
+            .cornerRadiusTL = protoRegion.corner_radius_tl(),
+            .cornerRadiusTR = protoRegion.corner_radius_tr(),
+            .cornerRadiusBL = protoRegion.corner_radius_bl(),
+            .cornerRadiusBR = protoRegion.corner_radius_br(),
+            .left = protoRegion.left(),
+            .top = protoRegion.top(),
+            .right = protoRegion.right(),
+            .bottom = protoRegion.bottom()
+        });
+    }
+    t.setBlurRegions(mLayers[id], regions);
+}
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index 95857e1..a22262a 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -96,10 +96,10 @@
             layer_id id, const CornerRadiusChange& cc);
     void setBackgroundBlurRadius(SurfaceComposerClient::Transaction& t,
             layer_id id, const BackgroundBlurRadiusChange& cc);
+    void setBlurRegions(SurfaceComposerClient::Transaction& t,
+            layer_id id, const BlurRegionsChange& cc);
     void setMatrix(SurfaceComposerClient::Transaction& t,
             layer_id id, const MatrixChange& mc);
-    void setOverrideScalingMode(SurfaceComposerClient::Transaction& t,
-            layer_id id, const OverrideScalingModeChange& osmc);
     void setTransparentRegionHint(SurfaceComposerClient::Transaction& t,
             layer_id id, const TransparentRegionHintChange& trgc);
     void setLayerStack(SurfaceComposerClient::Transaction& t,
@@ -122,6 +122,8 @@
             layer_id id, const ReparentChildrenChange& c);
     void setShadowRadiusChange(SurfaceComposerClient::Transaction& t,
             layer_id id, const ShadowRadiusChange& c);
+    void setBlurRegionsChange(SurfaceComposerClient::Transaction& t,
+            layer_id id, const BlurRegionsChange& c);
 
     void setDisplaySurface(SurfaceComposerClient::Transaction& t,
             display_id id, const DispSurfaceChange& dsc);
diff --git a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
index d63d97f..58bfbf3 100644
--- a/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
+++ b/cmds/surfacereplayer/replayer/trace_creator/trace_creator.py
@@ -69,7 +69,6 @@
     print ("5. Crop Change")
     print ("6. Final Crop Change")
     print ("7. Matrix Change")
-    print ("8. Override Scaling Mode Change")
     print ("9. Transparent Region Hint Change")
     print ("10. Layer Stack Change")
     print ("11. Hidden Flag Change")
@@ -128,9 +127,6 @@
             change.matrix.dtdx,\
             change.matrix.dsdy,\
             change.matrix.dtdy = layer()
-        elif option == 8:
-            change.override_scaling_mode.override_scaling_mode \
-                                     = override_scaling_mode()
         elif option == 9:
             for rect in transparent_region_hint():
                 new = increment.transparent_region_hint.region.add()
@@ -227,11 +223,6 @@
 
     return float(dsdx)
 
-def override_scaling_mode():
-    mode = input("Enter override scaling mode: ")
-
-    return int(mode)
-
 def transparent_region_hint():
     num = input("Enter number of rectangles in region: ")
 
diff --git a/data/etc/cec_config.xml b/data/etc/cec_config.xml
new file mode 100644
index 0000000..42a45e4
--- /dev/null
+++ b/data/etc/cec_config.xml
@@ -0,0 +1,36 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<cec-settings>
+  <setting name="hdmi_cec_enabled"
+           user-configurable="true">
+    <allowed-values>
+      <value string-value="0" />
+      <value string-value="1" />
+    </allowed-values>
+    <default-value string-value="1" />
+  </setting>
+  <setting name="send_standby_on_sleep"
+           user-configurable="true">
+    <allowed-values>
+      <value string-value="to_tv" />
+      <value string-value="broadcast" />
+      <value string-value="none" />
+    </allowed-values>
+    <default-value string-value="to_tv" />
+  </setting>
+  <setting name="power_state_change_on_active_source_lost"
+           user-configurable="false">
+    <allowed-values>
+      <value string-value="none" />
+      <value string-value="standby_now" />
+    </allowed-values>
+    <default-value string-value="none" />
+  </setting>
+  <setting name="system_audio_mode_muting"
+           user-configurable="false">
+    <allowed-values>
+      <value string-value="0" />
+      <value string-value="1" />
+    </allowed-values>
+    <default-value string-value="1" />
+  </setting>
+</cec-settings>
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
index d7e6e41..3dd1534 100644
--- a/include/android/imagedecoder.h
+++ b/include/android/imagedecoder.h
@@ -158,7 +158,8 @@
  * - {@link ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT}: The format is not
  *   supported.
  */
-int AImageDecoder_createFromAAsset(struct AAsset* asset, AImageDecoder** outDecoder)
+int AImageDecoder_createFromAAsset(struct AAsset* _Nonnull asset,
+                                   AImageDecoder* _Nonnull * _Nonnull outDecoder)
         __INTRODUCED_IN(30);
 
 /**
@@ -189,7 +190,8 @@
  * - {@link ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT}: The format is not
  *   supported.
  */
-int AImageDecoder_createFromFd(int fd, AImageDecoder** outDecoder) __INTRODUCED_IN(30);
+int AImageDecoder_createFromFd(int fd, AImageDecoder* _Nonnull * _Nonnull outDecoder)
+        __INTRODUCED_IN(30);
 
 /**
  * Create a new AImageDecoder from a buffer.
@@ -218,15 +220,16 @@
  * - {@link ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT}: The format is not
  *   supported.
  */
-int AImageDecoder_createFromBuffer(const void* buffer, size_t length,
-                                   AImageDecoder** outDecoder) __INTRODUCED_IN(30);
+int AImageDecoder_createFromBuffer(const void* _Nonnull buffer, size_t length,
+                                   AImageDecoder* _Nonnull * _Nonnull outDecoder)
+        __INTRODUCED_IN(30);
 
 /**
  * Delete the AImageDecoder.
  *
  * Available since API level 30.
  */
-void AImageDecoder_delete(AImageDecoder* decoder) __INTRODUCED_IN(30);
+void AImageDecoder_delete(AImageDecoder* _Nonnull decoder) __INTRODUCED_IN(30);
 
 /**
  * Choose the desired output format.
@@ -247,7 +250,7 @@
  * - {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION}: The
  *   {@link AndroidBitmapFormat} is incompatible with the image.
  */
-int AImageDecoder_setAndroidBitmapFormat(AImageDecoder*,
+int AImageDecoder_setAndroidBitmapFormat(AImageDecoder* _Nonnull decoder,
         int32_t format) __INTRODUCED_IN(30);
 
 /**
@@ -270,7 +273,7 @@
  * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The
  *   {@link AImageDecoder} is null.
  */
-int AImageDecoder_setUnpremultipliedRequired(AImageDecoder*,
+int AImageDecoder_setUnpremultipliedRequired(AImageDecoder* _Nonnull decoder,
                                              bool unpremultipliedRequired) __INTRODUCED_IN(30);
 
 /**
@@ -295,7 +298,8 @@
  *   {@link AImageDecoder} is null or |dataspace| does not correspond to an
  *   {@link ADataSpace} value.
  */
-int AImageDecoder_setDataSpace(AImageDecoder*, int32_t dataspace) __INTRODUCED_IN(30);
+int AImageDecoder_setDataSpace(AImageDecoder* _Nonnull decoder, int32_t dataspace)
+        __INTRODUCED_IN(30);
 
 /**
  * Specify the output size for a decoded image.
@@ -324,7 +328,8 @@
  *   or the scale is incompatible with a previous call to
  *   {@link AImageDecoder_setUnpremultipliedRequired}(true).
  */
-int AImageDecoder_setTargetSize(AImageDecoder*, int32_t width, int32_t height) __INTRODUCED_IN(30);
+int AImageDecoder_setTargetSize(AImageDecoder* _Nonnull decoder, int32_t width,
+                                int32_t height) __INTRODUCED_IN(30);
 
 
 /**
@@ -353,8 +358,9 @@
  * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The
  *   {@link AImageDecoder}, |width| or |height| is null or |sampleSize| is < 1.
  */
-int AImageDecoder_computeSampledSize(const AImageDecoder*, int sampleSize,
-                                     int32_t* width, int32_t* height) __INTRODUCED_IN(30);
+int AImageDecoder_computeSampledSize(const AImageDecoder* _Nonnull decoder, int sampleSize,
+                                     int32_t* _Nonnull width, int32_t* _Nonnull height)
+        __INTRODUCED_IN(30);
 /**
  * Specify how to crop the output after scaling (if any).
  *
@@ -380,7 +386,7 @@
  *   {@link AImageDecoder} is null or the crop is not contained by the
  *   (possibly scaled) image dimensions.
  */
-int AImageDecoder_setCrop(AImageDecoder*, ARect crop) __INTRODUCED_IN(30);
+int AImageDecoder_setCrop(AImageDecoder* _Nonnull decoder, ARect crop) __INTRODUCED_IN(30);
 
 struct AImageDecoderHeaderInfo;
 /**
@@ -399,8 +405,8 @@
  *
  * Available since API level 30.
  */
-const AImageDecoderHeaderInfo* AImageDecoder_getHeaderInfo(
-        const AImageDecoder*) __INTRODUCED_IN(30);
+const AImageDecoderHeaderInfo* _Nonnull  AImageDecoder_getHeaderInfo(
+        const AImageDecoder* _Nonnull decoder) __INTRODUCED_IN(30);
 
 /**
  * Report the native width of the encoded image. This is also the logical
@@ -410,7 +416,8 @@
  *
  * Available since API level 30.
  */
-int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo* _Nonnull)
+        __INTRODUCED_IN(30);
 
 /**
  * Report the native height of the encoded image. This is also the logical
@@ -420,7 +427,8 @@
  *
  * Available since API level 30.
  */
-int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo* _Nonnull)
+        __INTRODUCED_IN(30);
 
 /**
  * Report the mimeType of the encoded image.
@@ -429,8 +437,8 @@
  *
  * @return a string literal describing the mime type.
  */
-const char* AImageDecoderHeaderInfo_getMimeType(
-        const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+const char* _Nonnull  AImageDecoderHeaderInfo_getMimeType(
+        const AImageDecoderHeaderInfo* _Nonnull) __INTRODUCED_IN(30);
 
 /**
  * Report the {@link AndroidBitmapFormat} the AImageDecoder will decode to
@@ -441,7 +449,7 @@
  * Available since API level 30.
  */
 int32_t AImageDecoderHeaderInfo_getAndroidBitmapFormat(
-        const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+        const AImageDecoderHeaderInfo* _Nonnull) __INTRODUCED_IN(30);
 
 /**
  * Report how the {@link AImageDecoder} will handle alpha by default. If the image
@@ -453,7 +461,7 @@
  * Available since API level 30.
  */
 int AImageDecoderHeaderInfo_getAlphaFlags(
-        const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+        const AImageDecoderHeaderInfo* _Nonnull) __INTRODUCED_IN(30);
 
 /**
  * Report the dataspace the AImageDecoder will decode to by default.
@@ -474,7 +482,7 @@
  *         no corresponding {@link ADataSpace}.
  */
 int32_t AImageDecoderHeaderInfo_getDataSpace(
-        const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+        const AImageDecoderHeaderInfo* _Nonnull) __INTRODUCED_IN(30);
 
 /**
  * Return the minimum stride that can be used in
@@ -489,13 +497,17 @@
  *
  * Available since API level 30.
  */
-size_t AImageDecoder_getMinimumStride(AImageDecoder*) __INTRODUCED_IN(30);
+size_t AImageDecoder_getMinimumStride(AImageDecoder* _Nonnull decoder) __INTRODUCED_IN(30);
 
 /**
  * Decode the image into pixels, using the settings of the {@link AImageDecoder}.
  *
  * Available since API level 30.
  *
+ * Starting in API level 31, it can be used to decode all of the frames of an
+ * animated image (i.e. GIF, WebP, HEIF) using new APIs (TODO (scroggo): list
+ * and describe here).
+ *
  * @param decoder Opaque object representing the decoder.
  * @param pixels On success, will be filled with the result
  *               of the decode. Must be large enough to hold |size| bytes.
@@ -523,12 +535,64 @@
  * - {@link ANDROID_IMAGE_DECODER_INTERNAL_ERROR}: Some other error, like a
  *   failure to allocate memory.
  */
-int AImageDecoder_decodeImage(AImageDecoder* decoder,
-                              void* pixels, size_t stride,
+int AImageDecoder_decodeImage(AImageDecoder* _Nonnull decoder,
+                              void* _Nonnull pixels, size_t stride,
                               size_t size) __INTRODUCED_IN(30);
 
 #endif // __ANDROID_API__ >= 30
 
+#if __ANDROID_API__ >= 31
+
+/**
+ * Return true iff the image is animated - i.e. has multiple frames.
+ *
+ * Introduced in API 31.
+ *
+ * This may require seeking past the first frame to verify whether
+ * there is a following frame (e.g. for GIF).
+ *
+ * Errors:
+ * - returns false if |decoder| is null.
+ */
+bool AImageDecoder_isAnimated(AImageDecoder* _Nonnull decoder)
+        __INTRODUCED_IN(31);
+
+enum {
+    /*
+     * Reported by {@link AImageDecoder_getRepeatCount} if the
+     * animation should repeat forever.
+     */
+    ANDROID_IMAGE_DECODER_INFINITE = INT32_MAX,
+};
+
+/**
+ * Report how many times the animation should repeat.
+ *
+ * Introduced in API 31.
+ *
+ * This does not include the first play through. e.g. a repeat
+ * count of 4 means that each frame is played 5 times.
+ *
+ * {@link ANDROID_IMAGE_DECODER_INFINITE} means to repeat forever.
+ *
+ * This may require seeking.
+ *
+ * For non-animated formats, this returns 0. It may return non-zero for
+ * an image with only one frame (i.e. {@link AImageDecoder_isAnimated} returns
+ * false) if the encoded image contains a repeat count.
+ *
+ * @return Number of times to repeat on success or a value
+ *         indicating the reason for the failure.
+ *
+ * Errors:
+ * - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER}: The AImageDecoder
+ *   is null.
+ */
+int32_t AImageDecoder_getRepeatCount(AImageDecoder* _Nonnull decoder);
+        __INTRODUCED_IN(31);
+
+#endif // __ANDROID_API__ >= 31
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/ftl/StaticVector.h b/include/ftl/StaticVector.h
new file mode 100644
index 0000000..b586e91
--- /dev/null
+++ b/include/ftl/StaticVector.h
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <memory>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+namespace android::ftl {
+
+// Fixed-capacity, statically allocated counterpart of std::vector. Akin to std::array, StaticVector
+// allocates contiguous storage for N elements of type T at compile time, but stores at most (rather
+// than exactly) N elements. Unlike std::array, its default constructor does not require T to have a
+// default constructor, since elements are constructed in-place as the vector grows. Operations that
+// insert an element, such as push_back and emplace, fail when the vector is full. The API otherwise
+// adheres to standard containers, except the unstable_erase operation that does not shift elements,
+// and the replace operation that destructively emplaces.
+//
+// StaticVector<T, 1> is analogous to an iterable std::optional, but StaticVector<T, 0> is an error.
+//
+// Example usage:
+//
+//     ftl::StaticVector<char, 3> vector;
+//     assert(vector.empty());
+//
+//     vector = {'a', 'b'};
+//     assert(vector.size() == 2u);
+//
+//     vector.push_back('c');
+//     assert(vector.full());
+//
+//     assert(!vector.push_back('d'));
+//     assert(vector.size() == 3u);
+//
+//     vector.unstable_erase(vector.begin());
+//     assert(vector == (ftl::StaticVector{'c', 'b'}));
+//
+//     vector.pop_back();
+//     assert(vector.back() == 'c');
+//
+//     const char array[] = "hi";
+//     vector = ftl::StaticVector(array);
+//     assert(vector == (ftl::StaticVector{'h', 'i', '\0'}));
+//
+template <typename T, size_t N>
+class StaticVector {
+    static_assert(N > 0);
+
+    template <typename I>
+    using IsInputIterator = std::is_base_of<std::input_iterator_tag,
+                                            typename std::iterator_traits<I>::iterator_category>;
+
+public:
+    using value_type = T;
+    using size_type = size_t;
+    using difference_type = ptrdiff_t;
+
+    using pointer = value_type*;
+    using reference = value_type&;
+    using iterator = pointer;
+    using reverse_iterator = std::reverse_iterator<iterator>;
+
+    using const_pointer = const value_type*;
+    using const_reference = const value_type&;
+    using const_iterator = const_pointer;
+    using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+    // Creates an empty vector.
+    StaticVector() = default;
+
+    // Copies and moves a vector, respectively.
+    StaticVector(const StaticVector& other) : StaticVector(other.begin(), other.end()) {}
+    StaticVector(StaticVector&& other) { swap<Empty>(other); }
+
+    // Copies at most N elements from a smaller convertible vector.
+    template <typename U, size_t M, typename = std::enable_if_t<M <= N>>
+    StaticVector(const StaticVector<U, M>& other) : StaticVector(other.begin(), other.end()) {}
+
+    // Copies at most N elements from an array.
+    template <typename U, size_t M>
+    explicit StaticVector(U (&array)[M]) : StaticVector(std::begin(array), std::end(array)) {}
+
+    // Copies at most N elements from the range [first, last).
+    template <typename Iterator, typename = std::enable_if_t<IsInputIterator<Iterator>{}>>
+    StaticVector(Iterator first, Iterator last)
+          : mSize(std::min(max_size(), static_cast<size_type>(std::distance(first, last)))) {
+        std::uninitialized_copy(first, first + mSize, begin());
+    }
+
+    // Constructs at most N elements. The template arguments T and N are inferred using the
+    // deduction guide defined below. Note that T is determined from the first element, and
+    // subsequent elements must have convertible types:
+    //
+    //     ftl::StaticVector vector = {1, 2, 3};
+    //     static_assert(std::is_same_v<decltype(vector), ftl::StaticVector<int, 3>>);
+    //
+    //     const auto copy = "quince"s;
+    //     auto move = "tart"s;
+    //     ftl::StaticVector vector = {copy, std::move(move)};
+    //
+    //     static_assert(std::is_same_v<decltype(vector), ftl::StaticVector<std::string, 2>>);
+    //
+    template <typename E, typename... Es,
+              typename = std::enable_if_t<std::is_constructible_v<value_type, E>>>
+    StaticVector(E&& element, Es&&... elements)
+          : StaticVector(std::index_sequence<0>{}, std::forward<E>(element),
+                         std::forward<Es>(elements)...) {
+        static_assert(sizeof...(elements) < N, "Too many elements");
+    }
+
+    // Constructs at most N elements. The template arguments T and N are inferred using the
+    // deduction guide defined below. Element types must be convertible to the specified T:
+    //
+    //     ftl::StaticVector vector(std::in_place_type<std::string>, "red", "velvet", "cake");
+    //     static_assert(std::is_same_v<decltype(vector), ftl::StaticVector<std::string, 3>>);
+    //
+    template <typename... Es>
+    explicit StaticVector(std::in_place_type_t<T>, Es... elements)
+          : StaticVector(std::forward<Es>(elements)...) {}
+
+    ~StaticVector() { std::destroy(begin(), end()); }
+
+    StaticVector& operator=(const StaticVector& other) {
+        StaticVector copy(other);
+        swap(copy);
+        return *this;
+    }
+
+    StaticVector& operator=(StaticVector&& other) {
+        std::destroy(begin(), end());
+        mSize = 0;
+        swap<Empty>(other);
+        return *this;
+    }
+
+    template <typename = void>
+    void swap(StaticVector&);
+
+    size_type max_size() const { return N; }
+    size_type size() const { return mSize; }
+
+    bool empty() const { return size() == 0; }
+    bool full() const { return size() == max_size(); }
+
+    iterator begin() { return std::launder(reinterpret_cast<pointer>(mData)); }
+    const_iterator begin() const { return cbegin(); }
+    const_iterator cbegin() const { return mut().begin(); }
+
+    iterator end() { return begin() + size(); }
+    const_iterator end() const { return cend(); }
+    const_iterator cend() const { return mut().end(); }
+
+    reverse_iterator rbegin() { return std::make_reverse_iterator(end()); }
+    const_reverse_iterator rbegin() const { return crbegin(); }
+    const_reverse_iterator crbegin() const { return mut().rbegin(); }
+
+    reverse_iterator rend() { return std::make_reverse_iterator(begin()); }
+    const_reverse_iterator rend() const { return crend(); }
+    const_reverse_iterator crend() const { return mut().rend(); }
+
+    iterator last() { return end() - 1; }
+    const_iterator last() const { return mut().last(); }
+
+    reference front() { return *begin(); }
+    const_reference front() const { return mut().front(); }
+
+    reference back() { return *last(); }
+    const_reference back() const { return mut().back(); }
+
+    reference operator[](size_type i) { return *(begin() + i); }
+    const_reference operator[](size_type i) const { return mut()[i]; }
+
+    // Replaces an element, and returns an iterator to it. If the vector is full, the element is not
+    // replaced, and the end iterator is returned.
+    template <typename... Args>
+    iterator replace(const_iterator cit, Args&&... args) {
+        if (full()) return end();
+        // Append element, and move into place if not last.
+        emplace_back(std::forward<Args>(args)...);
+        if (cit != last()) unstable_erase(cit);
+        return const_cast<iterator>(cit);
+    }
+
+    // Appends an element, and returns an iterator to it. If the vector is full, the element is not
+    // inserted, and the end iterator is returned.
+    template <typename... Args>
+    iterator emplace_back(Args&&... args) {
+        if (full()) return end();
+        const iterator it = construct_at(end(), std::forward<Args>(args)...);
+        ++mSize;
+        return it;
+    }
+
+    // Erases an element, but does not preserve order. Rather than shifting subsequent elements,
+    // this moves the last element to the slot of the erased element.
+    void unstable_erase(const_iterator it) {
+        std::destroy_at(it);
+        if (it != last()) {
+            // Move last element and destroy its source for destructor side effects.
+            construct_at(it, std::move(back()));
+            std::destroy_at(last());
+        }
+        --mSize;
+    }
+
+    bool push_back(value_type v) {
+        // Two statements for sequence point.
+        const iterator it = emplace_back(std::move(v));
+        return it != end();
+    }
+
+    void pop_back() { unstable_erase(last()); }
+
+private:
+    struct Empty {};
+
+    StaticVector& mut() const { return *const_cast<StaticVector*>(this); }
+
+    // Recursion for variadic constructor.
+    template <size_t I, typename E, typename... Es>
+    StaticVector(std::index_sequence<I>, E&& element, Es&&... elements)
+          : StaticVector(std::index_sequence<I + 1>{}, std::forward<Es>(elements)...) {
+        construct_at(begin() + I, std::forward<E>(element));
+    }
+
+    // Base case for variadic constructor.
+    template <size_t I>
+    explicit StaticVector(std::index_sequence<I>) : mSize(I) {}
+
+    // TODO: Replace with std::construct_at in C++20.
+    template <typename... Args>
+    static pointer construct_at(const_iterator it, Args&&... args) {
+        void* const ptr = const_cast<void*>(static_cast<const void*>(it));
+        return new (ptr) value_type{std::forward<Args>(args)...};
+    }
+
+    size_type mSize = 0;
+    std::aligned_storage_t<sizeof(value_type), alignof(value_type)> mData[N];
+};
+
+// Deduction guide for array constructor.
+template <typename T, size_t N>
+StaticVector(T (&)[N]) -> StaticVector<std::remove_cv_t<T>, N>;
+
+// Deduction guide for variadic constructor.
+template <typename T, typename... Us, typename V = std::decay_t<T>,
+          typename = std::enable_if_t<(std::is_constructible_v<V, Us> && ...)>>
+StaticVector(T&&, Us&&...) -> StaticVector<V, 1 + sizeof...(Us)>;
+
+// Deduction guide for in-place constructor.
+template <typename T, typename... Us>
+StaticVector(std::in_place_type_t<T>, Us&&...) -> StaticVector<T, sizeof...(Us)>;
+
+template <typename T, size_t N>
+template <typename E>
+void StaticVector<T, N>::swap(StaticVector& other) {
+    auto [to, from] = std::make_pair(this, &other);
+    if (from == this) return;
+
+    // Assume this vector has fewer elements, so the excess of the other vector will be moved to it.
+    auto [min, max] = std::make_pair(size(), other.size());
+
+    // No elements to swap if moving into an empty vector.
+    if constexpr (std::is_same_v<E, Empty>) {
+        assert(min == 0);
+    } else {
+        if (min > max) {
+            std::swap(from, to);
+            std::swap(min, max);
+        }
+
+        // Swap elements [0, min).
+        std::swap_ranges(begin(), begin() + min, other.begin());
+
+        // No elements to move if sizes are equal.
+        if (min == max) return;
+    }
+
+    // Move elements [min, max) and destroy their source for destructor side effects.
+    const auto [first, last] = std::make_pair(from->begin() + min, from->begin() + max);
+    std::uninitialized_move(first, last, to->begin() + min);
+    std::destroy(first, last);
+
+    std::swap(mSize, other.mSize);
+}
+
+template <typename T, size_t N>
+inline void swap(StaticVector<T, N>& lhs, StaticVector<T, N>& rhs) {
+    lhs.swap(rhs);
+}
+
+// TODO: Replace with operator<=> in C++20.
+template <typename T, size_t N, size_t M>
+inline bool operator==(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
+    return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
+}
+
+template <typename T, size_t N, size_t M>
+inline bool operator<(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
+    return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
+}
+
+template <typename T, size_t N, size_t M>
+inline bool operator>(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
+    return rhs < lhs;
+}
+
+template <typename T, size_t N, size_t M>
+inline bool operator!=(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
+    return !(lhs == rhs);
+}
+
+template <typename T, size_t N, size_t M>
+inline bool operator>=(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
+    return !(lhs < rhs);
+}
+
+template <typename T, size_t N, size_t M>
+inline bool operator<=(const StaticVector<T, N>& lhs, const StaticVector<T, M>& rhs) {
+    return !(rhs < lhs);
+}
+
+} // namespace android::ftl
diff --git a/include/gfx/.clang-format b/include/gfx/.clang-format
deleted file mode 100644
index 86763a0..0000000
--- a/include/gfx/.clang-format
+++ /dev/null
@@ -1,11 +0,0 @@
-BasedOnStyle: Google
-
-AccessModifierOffset: -2
-AllowShortFunctionsOnASingleLine: Inline
-BinPackParameters: false
-ColumnLimit: 100
-CommentPragmas: NOLINT:.*
-ConstructorInitializerAllOnOneLineOrOnePerLine: true
-ConstructorInitializerIndentWidth: 2
-ContinuationIndentWidth: 8
-IndentWidth: 4
diff --git a/include/input/Input.h b/include/input/Input.h
index 7d81fed..d3a9694 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -177,9 +177,7 @@
 
 namespace android {
 
-#ifdef __ANDROID__
 class Parcel;
-#endif
 
 const char* inputEventTypeToString(int32_t type);
 
@@ -346,10 +344,8 @@
         return getAxisValue(AMOTION_EVENT_AXIS_Y);
     }
 
-#ifdef __ANDROID__
     status_t readFromParcel(Parcel* parcel);
     status_t writeToParcel(Parcel* parcel) const;
-#endif
 
     bool operator==(const PointerCoords& other) const;
     inline bool operator!=(const PointerCoords& other) const {
@@ -708,10 +704,8 @@
     // Matrix is in row-major form and compatible with SkMatrix.
     void transform(const std::array<float, 9>& matrix);
 
-#ifdef __ANDROID__
     status_t readFromParcel(Parcel* parcel);
     status_t writeToParcel(Parcel* parcel) const;
-#endif
 
     static bool isTouchEvent(uint32_t source, int32_t action);
     inline bool isTouchEvent() const {
@@ -730,7 +724,7 @@
     static const char* getLabel(int32_t axis);
     static int32_t getAxisFromLabel(const char* label);
 
-    static const char* actionToString(int32_t action);
+    static std::string actionToString(int32_t action);
 
 protected:
     int32_t mAction;
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index d874347..339c7eb 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -19,9 +19,7 @@
 
 #include <stdint.h>
 
-#ifdef __ANDROID__
 #include <binder/IBinder.h>
-#endif
 
 #include <android-base/result.h>
 #include <input/Input.h>
@@ -134,13 +132,11 @@
     void tryRemapKey(int32_t scanCode, int32_t metaState,
             int32_t* outKeyCode, int32_t* outMetaState) const;
 
-#ifdef __ANDROID__
     /* Reads a key map from a parcel. */
     static std::shared_ptr<KeyCharacterMap> readFromParcel(Parcel* parcel);
 
     /* Writes a key map to a parcel. */
     void writeToParcel(Parcel* parcel) const;
-#endif
 
     KeyCharacterMap(const KeyCharacterMap& other);
 
diff --git a/libs/binder/MemoryHeapBase.cpp b/libs/binder/MemoryHeapBase.cpp
index e4ea60f..e1cbc19 100644
--- a/libs/binder/MemoryHeapBase.cpp
+++ b/libs/binder/MemoryHeapBase.cpp
@@ -49,7 +49,7 @@
     int fd = ashmem_create_region(name == nullptr ? "MemoryHeapBase" : name, size);
     ALOGE_IF(fd<0, "error creating ashmem region: %s", strerror(errno));
     if (fd >= 0) {
-        if (mapfd(fd, size) == NO_ERROR) {
+        if (mapfd(fd, true, size) == NO_ERROR) {
             if (flags & READ_ONLY) {
                 ashmem_set_prot_region(fd, PROT_READ);
             }
@@ -70,7 +70,7 @@
     if (fd >= 0) {
         const size_t pagesize = getpagesize();
         size = ((size + pagesize-1) & ~(pagesize-1));
-        if (mapfd(fd, size) == NO_ERROR) {
+        if (mapfd(fd, false, size) == NO_ERROR) {
             mDevice = device;
         }
     }
@@ -82,7 +82,7 @@
 {
     const size_t pagesize = getpagesize();
     size = ((size + pagesize-1) & ~(pagesize-1));
-    mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), size, offset);
+    mapfd(fcntl(fd, F_DUPFD_CLOEXEC, 0), false, size, offset);
 }
 
 status_t MemoryHeapBase::init(int fd, void *base, size_t size, int flags, const char* device)
@@ -98,7 +98,7 @@
     return NO_ERROR;
 }
 
-status_t MemoryHeapBase::mapfd(int fd, size_t size, off_t offset)
+status_t MemoryHeapBase::mapfd(int fd, bool writeableByCaller, size_t size, off_t offset)
 {
     if (size == 0) {
         // try to figure out the size automatically
@@ -116,8 +116,12 @@
     }
 
     if ((mFlags & DONT_MAP_LOCALLY) == 0) {
+        int prot = PROT_READ;
+        if (writeableByCaller || (mFlags & READ_ONLY) == 0) {
+            prot |= PROT_WRITE;
+        }
         void* base = (uint8_t*)mmap(nullptr, size,
-                PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
+                prot, MAP_SHARED, fd, offset);
         if (base == MAP_FAILED) {
             ALOGE("mmap(fd=%d, size=%zu) failed (%s)",
                     fd, size, strerror(errno));
diff --git a/libs/binder/ParcelableHolder.cpp b/libs/binder/ParcelableHolder.cpp
index e9df279..b2b8671 100644
--- a/libs/binder/ParcelableHolder.cpp
+++ b/libs/binder/ParcelableHolder.cpp
@@ -27,7 +27,6 @@
 namespace android {
 namespace os {
 status_t ParcelableHolder::writeToParcel(Parcel* p) const {
-    std::lock_guard<std::mutex> l(mMutex);
     RETURN_ON_FAILURE(p->writeInt32(static_cast<int32_t>(this->getStability())));
     if (this->mParcelPtr) {
         RETURN_ON_FAILURE(p->writeInt32(this->mParcelPtr->dataSize()));
@@ -53,7 +52,6 @@
 }
 
 status_t ParcelableHolder::readFromParcel(const Parcel* p) {
-    std::lock_guard<std::mutex> l(mMutex);
     this->mStability = static_cast<Stability>(p->readInt32());
     this->mParcelable = nullptr;
     this->mParcelableName = std::nullopt;
diff --git a/libs/binder/include/binder/MemoryHeapBase.h b/libs/binder/include/binder/MemoryHeapBase.h
index 52bd5de..0ece121 100644
--- a/libs/binder/include/binder/MemoryHeapBase.h
+++ b/libs/binder/include/binder/MemoryHeapBase.h
@@ -51,6 +51,8 @@
 
     /*
      * maps memory from ashmem, with the given name for debugging
+     * if the READ_ONLY flag is set, the memory will be writeable by the calling process,
+     * but not by others. this is NOT the case with the other ctors.
      */
     explicit MemoryHeapBase(size_t size, uint32_t flags = 0, char const* name = nullptr);
 
@@ -78,7 +80,7 @@
             int flags = 0, const char* device = nullptr);
 
 private:
-    status_t mapfd(int fd, size_t size, off_t offset = 0);
+    status_t mapfd(int fd, bool writeableByCaller, size_t size, off_t offset = 0);
 
     int         mFD;
     size_t      mSize;
diff --git a/libs/binder/include/binder/ParcelableHolder.h b/libs/binder/include/binder/ParcelableHolder.h
index b6814aa..4ea3dd3 100644
--- a/libs/binder/include/binder/ParcelableHolder.h
+++ b/libs/binder/include/binder/ParcelableHolder.h
@@ -59,7 +59,6 @@
 
     template <typename T>
     bool setParcelable(std::shared_ptr<T> p) {
-        std::lock_guard<std::mutex> l(mMutex);
         static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
         if (p && this->getStability() > p->getStability()) {
             return false;
@@ -73,7 +72,6 @@
     template <typename T>
     std::shared_ptr<T> getParcelable() const {
         static_assert(std::is_base_of<Parcelable, T>::value, "T must be derived from Parcelable");
-        std::lock_guard<std::mutex> l(mMutex);
         const std::string& parcelableDesc = T::getParcelableDescriptor();
         if (!this->mParcelPtr) {
             if (!this->mParcelable || !this->mParcelableName) {
@@ -103,7 +101,7 @@
         return std::shared_ptr<T>(mParcelable, reinterpret_cast<T*>(mParcelable.get()));
     }
 
-    Stability getStability() const override { return mStability; };
+    Stability getStability() const override { return mStability; }
 
     inline bool operator!=(const ParcelableHolder& rhs) const {
         return std::tie(mParcelable, mParcelPtr, mStability) !=
@@ -135,7 +133,6 @@
     mutable std::optional<std::string> mParcelableName;
     mutable std::unique_ptr<Parcel> mParcelPtr;
     Stability mStability;
-    mutable std::mutex mMutex;
 };
 } // namespace os
 } // namespace android
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 4fd0657..e4d86ae 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -35,6 +35,8 @@
     defaults: ["libbinder_ndk_host_user"],
     host_supported: true,
 
+    llndk_stubs: "libbinder_ndk.llndk",
+
     export_include_dirs: [
         "include_cpp",
         "include_ndk",
@@ -120,7 +122,7 @@
 }
 
 llndk_library {
-    name: "libbinder_ndk",
+    name: "libbinder_ndk.llndk",
     symbol_file: "libbinder_ndk.map.txt",
     export_include_dirs: [
         "include_cpp",
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
index 09949ea..054aebe 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcel_utils.h
@@ -45,7 +45,7 @@
     std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
     if (static_cast<size_t>(length) > vec->max_size()) return false;
 
-    vec->resize(length);
+    vec->resize(static_cast<size_t>(length));
     *outBuffer = vec->data();
     return true;
 }
@@ -66,7 +66,7 @@
     *vec = std::optional<std::vector<T>>(std::vector<T>{});
 
     if (static_cast<size_t>(length) > (*vec)->max_size()) return false;
-    (*vec)->resize(length);
+    (*vec)->resize(static_cast<size_t>(length));
 
     *outBuffer = (*vec)->data();
     return true;
@@ -90,7 +90,7 @@
     std::vector<T>* vec = static_cast<std::vector<T>*>(vectorData);
     if (static_cast<size_t>(length) > vec->max_size()) return false;
 
-    vec->resize(length);
+    vec->resize(static_cast<size_t>(length));
     return true;
 }
 
@@ -117,7 +117,7 @@
     *vec = std::optional<std::vector<T>>(std::vector<T>{});
 
     if (static_cast<size_t>(length) > (*vec)->max_size()) return false;
-    (*vec)->resize(length);
+    (*vec)->resize(static_cast<size_t>(length));
 
     return true;
 }
@@ -257,7 +257,7 @@
     if (length <= 0) return false;
 
     std::string* str = static_cast<std::string*>(stringData);
-    str->resize(length - 1);
+    str->resize(static_cast<size_t>(length) - 1);
     *buffer = &(*str)[0];
     return true;
 }
@@ -279,7 +279,7 @@
     }
 
     *str = std::optional<std::string>(std::string{});
-    (*str)->resize(length - 1);
+    (*str)->resize(static_cast<size_t>(length) - 1);
     *buffer = &(**str)[0];
     return true;
 }
@@ -303,7 +303,7 @@
     const std::vector<std::string>* vec = static_cast<const std::vector<std::string>*>(vectorData);
     const std::string& element = vec->at(index);
 
-    *outLength = element.size();
+    *outLength = static_cast<int32_t>(element.size());
     return element.c_str();
 }
 
@@ -337,7 +337,7 @@
         return nullptr;
     }
 
-    *outLength = element->size();
+    *outLength = static_cast<int32_t>(element->size());
     return element->c_str();
 }
 
@@ -345,7 +345,7 @@
  * Convenience API for writing a std::string.
  */
 static inline binder_status_t AParcel_writeString(AParcel* parcel, const std::string& str) {
-    return AParcel_writeString(parcel, str.c_str(), str.size());
+    return AParcel_writeString(parcel, str.c_str(), static_cast<int32_t>(str.size()));
 }
 
 /**
@@ -365,7 +365,7 @@
         return AParcel_writeString(parcel, nullptr, -1);
     }
 
-    return AParcel_writeString(parcel, str->c_str(), str->size());
+    return AParcel_writeString(parcel, str->c_str(), static_cast<int32_t>(str->size()));
 }
 
 /**
@@ -383,7 +383,7 @@
 static inline binder_status_t AParcel_writeVector(AParcel* parcel,
                                                   const std::vector<std::string>& vec) {
     const void* vectorData = static_cast<const void*>(&vec);
-    return AParcel_writeStringArray(parcel, vectorData, vec.size(),
+    return AParcel_writeStringArray(parcel, vectorData, static_cast<int32_t>(vec.size()),
                                     AParcel_stdVectorStringElementGetter);
 }
 
@@ -404,7 +404,8 @@
 static inline binder_status_t AParcel_writeVector(
         AParcel* parcel, const std::optional<std::vector<std::optional<std::string>>>& vec) {
     const void* vectorData = static_cast<const void*>(&vec);
-    return AParcel_writeStringArray(parcel, vectorData, (vec ? vec->size() : -1),
+    return AParcel_writeStringArray(parcel, vectorData,
+                                    (vec ? static_cast<int32_t>(vec->size()) : -1),
                                     AParcel_nullableStdVectorStringElementGetter);
 }
 
@@ -545,7 +546,7 @@
 template <typename P>
 static inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<P>& vec) {
     const void* vectorData = static_cast<const void*>(&vec);
-    return AParcel_writeParcelableArray(parcel, vectorData, vec.size(),
+    return AParcel_writeParcelableArray(parcel, vectorData, static_cast<int32_t>(vec.size()),
                                         AParcel_writeStdVectorParcelableElement<P>);
 }
 
@@ -564,7 +565,7 @@
  * Writes a vector of int32_t to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int32_t>& vec) {
-    return AParcel_writeInt32Array(parcel, vec.data(), vec.size());
+    return AParcel_writeInt32Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
 }
 
 /**
@@ -597,7 +598,7 @@
  * Writes a vector of uint32_t to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint32_t>& vec) {
-    return AParcel_writeUint32Array(parcel, vec.data(), vec.size());
+    return AParcel_writeUint32Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
 }
 
 /**
@@ -631,7 +632,7 @@
  * Writes a vector of int64_t to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<int64_t>& vec) {
-    return AParcel_writeInt64Array(parcel, vec.data(), vec.size());
+    return AParcel_writeInt64Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
 }
 
 /**
@@ -664,7 +665,7 @@
  * Writes a vector of uint64_t to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint64_t>& vec) {
-    return AParcel_writeUint64Array(parcel, vec.data(), vec.size());
+    return AParcel_writeUint64Array(parcel, vec.data(), static_cast<int32_t>(vec.size()));
 }
 
 /**
@@ -698,7 +699,7 @@
  * Writes a vector of float to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<float>& vec) {
-    return AParcel_writeFloatArray(parcel, vec.data(), vec.size());
+    return AParcel_writeFloatArray(parcel, vec.data(), static_cast<int32_t>(vec.size()));
 }
 
 /**
@@ -731,7 +732,7 @@
  * Writes a vector of double to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<double>& vec) {
-    return AParcel_writeDoubleArray(parcel, vec.data(), vec.size());
+    return AParcel_writeDoubleArray(parcel, vec.data(), static_cast<int32_t>(vec.size()));
 }
 
 /**
@@ -764,8 +765,8 @@
  * Writes a vector of bool to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<bool>& vec) {
-    return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec), vec.size(),
-                                  AParcel_stdVectorGetter<bool>);
+    return AParcel_writeBoolArray(parcel, static_cast<const void*>(&vec),
+                                  static_cast<int32_t>(vec.size()), AParcel_stdVectorGetter<bool>);
 }
 
 /**
@@ -801,7 +802,7 @@
  * Writes a vector of char16_t to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<char16_t>& vec) {
-    return AParcel_writeCharArray(parcel, vec.data(), vec.size());
+    return AParcel_writeCharArray(parcel, vec.data(), static_cast<int32_t>(vec.size()));
 }
 
 /**
@@ -834,7 +835,8 @@
  * Writes a vector of uint8_t to the next location in a non-null parcel.
  */
 inline binder_status_t AParcel_writeVector(AParcel* parcel, const std::vector<uint8_t>& vec) {
-    return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(vec.data()), vec.size());
+    return AParcel_writeByteArray(parcel, reinterpret_cast<const int8_t*>(vec.data()),
+                                  static_cast<int32_t>(vec.size()));
 }
 
 /**
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 6701518..dfcf4dc 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -25,6 +25,8 @@
  */
 
 #pragma once
+#include <android/binder_parcel_utils.h>
+#include <optional>
 
 namespace ndk {
 // Also see Parcelable.h in libbinder.
@@ -33,6 +35,89 @@
     STABILITY_LOCAL,
     STABILITY_VINTF,  // corresponds to @VintfStability
 };
+#define RETURN_ON_FAILURE(expr)                   \
+    do {                                          \
+        binder_status_t _status = (expr);         \
+        if (_status != STATUS_OK) return _status; \
+    } while (false)
+
+class AParcelableHolder {
+   public:
+    AParcelableHolder() = delete;
+    explicit AParcelableHolder(parcelable_stability_t stability)
+        : mParcel(AParcel_create()), mStability(stability) {}
+
+    virtual ~AParcelableHolder() = default;
+
+    binder_status_t writeToParcel(AParcel* parcel) const {
+        RETURN_ON_FAILURE(AParcel_writeInt32(parcel, static_cast<int32_t>(this->mStability)));
+        RETURN_ON_FAILURE(AParcel_writeInt32(parcel, AParcel_getDataSize(this->mParcel.get())));
+        RETURN_ON_FAILURE(AParcel_appendFrom(this->mParcel.get(), parcel, 0,
+                                             AParcel_getDataSize(this->mParcel.get())));
+        return STATUS_OK;
+    }
+
+    binder_status_t readFromParcel(const AParcel* parcel) {
+        AParcel_reset(mParcel.get());
+
+        RETURN_ON_FAILURE(AParcel_readInt32(parcel, &this->mStability));
+        int32_t dataSize;
+        binder_status_t status = AParcel_readInt32(parcel, &dataSize);
+
+        if (status != STATUS_OK || dataSize < 0) {
+            return status != STATUS_OK ? status : STATUS_BAD_VALUE;
+        }
+
+        int32_t dataStartPos = AParcel_getDataPosition(parcel);
+
+        if (dataStartPos > INT32_MAX - dataSize) {
+            return STATUS_BAD_VALUE;
+        }
+
+        status = AParcel_appendFrom(parcel, mParcel.get(), dataStartPos, dataSize);
+        if (status != STATUS_OK) {
+            return status;
+        }
+        return AParcel_setDataPosition(parcel, dataStartPos + dataSize);
+    }
+
+    template <typename T>
+    bool setParcelable(T* p) {
+        if (p && this->mStability > T::_aidl_stability) {
+            return false;
+        }
+        AParcel_reset(mParcel.get());
+        AParcel_writeString(mParcel.get(), T::descriptor, strlen(T::descriptor));
+        p->writeToParcel(mParcel.get());
+        return true;
+    }
+
+    template <typename T>
+    std::unique_ptr<T> getParcelable() const {
+        const std::string parcelableDesc(T::descriptor);
+        AParcel_setDataPosition(mParcel.get(), 0);
+        if (AParcel_getDataSize(mParcel.get()) == 0) {
+            return nullptr;
+        }
+        std::string parcelableDescInParcel;
+        binder_status_t status = AParcel_readString(mParcel.get(), &parcelableDescInParcel);
+        if (status != STATUS_OK || parcelableDesc != parcelableDescInParcel) {
+            return nullptr;
+        }
+        std::unique_ptr<T> ret = std::make_unique<T>();
+        status = ret->readFromParcel(this->mParcel.get());
+        if (status != STATUS_OK) {
+            return nullptr;
+        }
+        return std::move(ret);
+    }
+
+   private:
+    mutable ndk::ScopedAParcel mParcel;
+    parcelable_stability_t mStability;
+};
+
+#undef RETURN_ON_FAILURE
 }  // namespace ndk
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index a031e29..93c3f32 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -1120,6 +1120,53 @@
 // @END-PRIMITIVE-READ-WRITE
 
 #endif  //__ANDROID_API__ >= 29
+#if __ANDROID_API__ >= 31
+/**
+ * Reset the parcel to the initial status.
+ *
+ * Available since API level 31.
+ *
+ * \param parcel The parcel of which to be reset.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AParcel_reset(AParcel* parcel) __INTRODUCED_IN(31);
+
+/**
+ * Gets the size of the parcel.
+ *
+ * Available since API level 31.
+ *
+ * \param parcel The parcel of which to get the size.
+ *
+ * \return The size of the parcel.
+ */
+int32_t AParcel_getDataSize(const AParcel* parcel) __INTRODUCED_IN(31);
+
+/**
+ * Copy the data of a parcel to other parcel.
+ *
+ * Available since API level 31.
+ *
+ * \param from The source
+ * \param to The detination
+ * \param start The position where the copied data starts.
+ * \param size The amount of data which will be copied.
+ *
+ * \return STATUS_OK on success.
+ */
+binder_status_t AParcel_appendFrom(const AParcel* from, AParcel* to, int32_t start, int32_t size)
+        __INTRODUCED_IN(31);
+
+/**
+ * Creates a parcel.
+ *
+ * Available since API level 31.
+ *
+ * \return A parcel which is not related to any IBinder objects.
+ */
+AParcel* AParcel_create() __INTRODUCED_IN(31);
+#endif  //__ANDROID_API__ >= 31
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/libbinder_ndk.map.txt b/libs/binder/ndk/libbinder_ndk.map.txt
index 1701fb5..947cc98 100644
--- a/libs/binder/ndk/libbinder_ndk.map.txt
+++ b/libs/binder/ndk/libbinder_ndk.map.txt
@@ -120,6 +120,11 @@
     AServiceManager_isDeclared; # apex llndk
     AServiceManager_registerLazyService; # llndk
     AServiceManager_waitForService; # apex llndk
+
+    AParcel_reset;
+    AParcel_getDataSize;
+    AParcel_appendFrom;
+    AParcel_create;
 };
 
 LIBBINDER_NDK_PLATFORM {
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index 722ae23..2f95318 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -647,4 +647,22 @@
     return parcel->get()->allowFds();
 }
 
+binder_status_t AParcel_reset(AParcel* parcel) {
+    parcel->get()->freeData();
+    return STATUS_OK;
+}
+
+int32_t AParcel_getDataSize(const AParcel* parcel) {
+    return parcel->get()->dataSize();
+}
+
+binder_status_t AParcel_appendFrom(const AParcel* from, AParcel* to, int32_t start, int32_t size) {
+    status_t status = to->get()->appendFrom(from->get(), start, size);
+    return PruneStatusT(status);
+}
+
+AParcel* AParcel_create() {
+    return new AParcel(nullptr);
+}
+
 // @END
diff --git a/libs/binder/parcel_fuzzer/Android.bp b/libs/binder/parcel_fuzzer/Android.bp
index 1a67898..c5b3d80 100644
--- a/libs/binder/parcel_fuzzer/Android.bp
+++ b/libs/binder/parcel_fuzzer/Android.bp
@@ -18,6 +18,7 @@
     ],
     static_libs: [
         "libbase",
+        "libbinder_random_parcel",
         "libcgrouprc",
         "libcgrouprc_format",
         "libcutils",
@@ -47,3 +48,20 @@
     // produced, you may find uncommenting the below line very useful.
     // cflags: ["-DENABLE_LOG_FUZZ"],
 }
+
+cc_library_static {
+    name: "libbinder_random_parcel",
+    host_supported: true,
+    srcs: [
+        "random_fd.cpp",
+        "random_parcel.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libcutils",
+        "libutils",
+    ],
+    local_include_dirs: ["include_random_parcel"],
+    export_include_dirs: ["include_random_parcel"],
+}
diff --git a/libs/binder/parcel_fuzzer/binder_ndk.cpp b/libs/binder/parcel_fuzzer/binder_ndk.cpp
index 29da8f7..008780c 100644
--- a/libs/binder/parcel_fuzzer/binder_ndk.cpp
+++ b/libs/binder/parcel_fuzzer/binder_ndk.cpp
@@ -18,6 +18,7 @@
 #include "binder_ndk.h"
 
 #include <android/binder_parcel_utils.h>
+#include <android/binder_parcelable_utils.h>
 
 #include "util.h"
 
@@ -54,6 +55,25 @@
             binder_status_t status = AParcel_readStatusHeader(p.aParcel(), t.getR());
             FUZZ_LOG() << "read status header: " << status;
         },
+        [](const NdkParcelAdapter& p, uint8_t /*data*/) {
+            FUZZ_LOG() << "about to getDataSize the parcel";
+            AParcel_getDataSize(p.aParcel());
+            FUZZ_LOG() << "getDataSize done";
+        },
+        [](const NdkParcelAdapter& p, uint8_t data) {
+            FUZZ_LOG() << "about to read a ParcelableHolder";
+            ndk::AParcelableHolder ph {(data % 2 == 1) ? ndk::STABILITY_LOCAL : ndk::STABILITY_VINTF};
+            binder_status_t status = AParcel_readParcelable(p.aParcel(), &ph);
+            FUZZ_LOG() << "read the ParcelableHolder: " << status;
+        },
+        [](const NdkParcelAdapter& p, uint8_t data) {
+            FUZZ_LOG() << "about to appendFrom";
+            AParcel* parcel = AParcel_create();
+            binder_status_t status = AParcel_appendFrom(p.aParcel(), parcel, 0, data);
+            AParcel_delete(parcel);
+            FUZZ_LOG() << "appendFrom: " << status;
+        },
+
         PARCEL_READ(int32_t, AParcel_readInt32),
         PARCEL_READ(uint32_t, AParcel_readUint32),
         PARCEL_READ(int64_t, AParcel_readInt64),
diff --git a/libs/binder/parcel_fuzzer/random_fd.h b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
similarity index 100%
rename from libs/binder/parcel_fuzzer/random_fd.h
rename to libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_fd.h
diff --git a/libs/binder/parcel_fuzzer/random_parcel.h b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
similarity index 88%
rename from libs/binder/parcel_fuzzer/random_parcel.h
rename to libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
index 2923c47..b92a6a9 100644
--- a/libs/binder/parcel_fuzzer/random_parcel.h
+++ b/libs/binder/parcel_fuzzer/include_random_parcel/fuzzbinder/random_parcel.h
@@ -16,12 +16,9 @@
 
 #pragma once
 
-#include "binder_ndk.h"
-
 #include <binder/Parcel.h>
 #include <fuzzer/FuzzedDataProvider.h>
 
 namespace android {
 void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
-void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider);
 } // namespace android
diff --git a/libs/binder/parcel_fuzzer/main.cpp b/libs/binder/parcel_fuzzer/main.cpp
index 46bf417..386c70b 100644
--- a/libs/binder/parcel_fuzzer/main.cpp
+++ b/libs/binder/parcel_fuzzer/main.cpp
@@ -18,10 +18,10 @@
 #include "binder.h"
 #include "binder_ndk.h"
 #include "hwbinder.h"
-#include "random_parcel.h"
 #include "util.h"
 
 #include <android-base/logging.h>
+#include <fuzzbinder/random_parcel.h>
 #include <fuzzer/FuzzedDataProvider.h>
 
 #include <cstdlib>
@@ -30,9 +30,14 @@
 using android::fillRandomParcel;
 
 void fillRandomParcel(::android::hardware::Parcel* p, FuzzedDataProvider&& provider) {
+    // TODO: functionality to create random parcels for libhwbinder parcels
     std::vector<uint8_t> input = provider.ConsumeRemainingBytes<uint8_t>();
     p->setData(input.data(), input.size());
 }
+static void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider) {
+    // fill underlying parcel using functions to fill random libbinder parcel
+    fillRandomParcel(p->parcel(), std::move(provider));
+}
 
 template <typename P>
 void doFuzz(const char* backend, const std::vector<ParcelRead<P>>& reads,
diff --git a/libs/binder/parcel_fuzzer/random_fd.cpp b/libs/binder/parcel_fuzzer/random_fd.cpp
index eb80ece..cef6adb 100644
--- a/libs/binder/parcel_fuzzer/random_fd.cpp
+++ b/libs/binder/parcel_fuzzer/random_fd.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "random_fd.h"
+#include <fuzzbinder/random_fd.h>
 
 #include <fcntl.h>
 
diff --git a/libs/binder/parcel_fuzzer/random_parcel.cpp b/libs/binder/parcel_fuzzer/random_parcel.cpp
index 3dae904..9ca4c8a 100644
--- a/libs/binder/parcel_fuzzer/random_parcel.cpp
+++ b/libs/binder/parcel_fuzzer/random_parcel.cpp
@@ -14,20 +14,15 @@
  * limitations under the License.
  */
 
-#include "random_parcel.h"
-
-#include "random_fd.h"
+#include <fuzzbinder/random_parcel.h>
 
 #include <android-base/logging.h>
 #include <binder/IServiceManager.h>
+#include <fuzzbinder/random_fd.h>
 #include <utils/String16.h>
 
 namespace android {
 
-void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider) {
-    fillRandomParcel(p->parcel(), std::move(provider));
-}
-
 class NamedBinder : public BBinder {
 public:
     NamedBinder(const String16& descriptor) : mDescriptor(descriptor) {}
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 5e785b6..6058430 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -425,6 +425,7 @@
 
     uint64_t newLastUpdate = lastUpdate ? *lastUpdate : 0;
     do {
+        if (key.bucket > (gNCpus - 1) / CPUS_PER_ENTRY) return {};
         if (lastUpdate) {
             auto uidUpdated = uidUpdatedSince(key.uid, *lastUpdate, &newLastUpdate);
             if (!uidUpdated.has_value()) return {};
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index ea2a200..0d5f412 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -387,6 +387,28 @@
     }
 }
 
+TEST(TimeInStateTest, AllUidConcurrentTimesFailsOnInvalidBucket) {
+    uint32_t uid = 0;
+    {
+        // Find an unused UID
+        auto map = getUidsConcurrentTimes();
+        ASSERT_TRUE(map.has_value());
+        ASSERT_FALSE(map->empty());
+        for (const auto &kv : *map) uid = std::max(uid, kv.first);
+        ++uid;
+    }
+    android::base::unique_fd fd{
+        bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
+    ASSERT_GE(fd, 0);
+    uint32_t nCpus = get_nprocs_conf();
+    uint32_t maxBucket = (nCpus - 1) / CPUS_PER_ENTRY;
+    time_key_t key = {.uid = uid, .bucket = maxBucket + 1};
+    std::vector<concurrent_val_t> vals(nCpus);
+    ASSERT_FALSE(writeToMapEntry(fd, &key, vals.data(), BPF_NOEXIST));
+    EXPECT_FALSE(getUidsConcurrentTimes().has_value());
+    ASSERT_FALSE(deleteMapEntry(fd, &key));
+}
+
 TEST(TimeInStateTest, AllUidTimesConsistent) {
     auto tisMap = getUidsCpuFreqTimes();
     ASSERT_TRUE(tisMap.has_value());
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 8f092f6..143fa13 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -33,6 +33,7 @@
         "/system/bin/mediaextractor", // media.extractor
         "/system/bin/mediametrics", // media.metrics
         "/system/bin/mediaserver",
+        "/system/bin/mediatranscoding", // media.transcoding
         "/system/bin/netd",
         "/system/bin/sdcard",
         "/apex/com.android.os.statsd/bin/statsd",
diff --git a/libs/ftl/Android.bp b/libs/ftl/Android.bp
new file mode 100644
index 0000000..e11be57
--- /dev/null
+++ b/libs/ftl/Android.bp
@@ -0,0 +1,16 @@
+cc_test {
+    name: "ftl_test",
+    test_suites: ["device-tests"],
+    sanitize: {
+        address: true,
+    },
+    srcs: [
+        "StaticVector_test.cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+        "-Wpedantic",
+    ],
+}
diff --git a/libs/ftl/StaticVector_test.cpp b/libs/ftl/StaticVector_test.cpp
new file mode 100644
index 0000000..06e4659
--- /dev/null
+++ b/libs/ftl/StaticVector_test.cpp
@@ -0,0 +1,347 @@
+/*
+ * 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 <ftl/StaticVector.h>
+#include <gtest/gtest.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <utility>
+
+using namespace std::string_literals;
+
+namespace android::test {
+
+using ftl::StaticVector;
+
+// Keep in sync with example usage in header file.
+TEST(StaticVector, Example) {
+    ftl::StaticVector<char, 3> vector;
+    EXPECT_TRUE(vector.empty());
+
+    vector = {'a', 'b'};
+    EXPECT_EQ(vector.size(), 2u);
+
+    vector.push_back('c');
+    EXPECT_TRUE(vector.full());
+
+    EXPECT_FALSE(vector.push_back('d'));
+    EXPECT_EQ(vector.size(), 3u);
+
+    vector.unstable_erase(vector.begin());
+    EXPECT_EQ(vector, (ftl::StaticVector{'c', 'b'}));
+
+    vector.pop_back();
+    EXPECT_EQ(vector.back(), 'c');
+
+    const char array[] = "hi";
+    vector = ftl::StaticVector(array);
+    EXPECT_EQ(vector, (ftl::StaticVector{'h', 'i', '\0'}));
+}
+
+TEST(StaticVector, Construct) {
+    {
+        // Default constructor.
+        StaticVector<std::string, 2> vector;
+        EXPECT_TRUE(vector.empty());
+    }
+    {
+        // Array constructor.
+        const float kFloats[] = {.1f, .2f, .3f};
+        StaticVector vector(kFloats);
+        EXPECT_EQ(vector, (StaticVector{.1f, .2f, .3f}));
+    }
+    {
+        // Iterator constructor.
+        const char chars[] = "abcdef";
+        std::string string(chars);
+        StaticVector<char, sizeof(chars)> vector(string.begin(), string.end());
+
+        EXPECT_STREQ(vector.begin(), chars);
+    }
+    {
+        // Variadic constructor with same types.
+        StaticVector vector = {1, 2, 3};
+
+        static_assert(std::is_same_v<decltype(vector), StaticVector<int, 3>>);
+        EXPECT_EQ(vector, (StaticVector{1, 2, 3}));
+    }
+    {
+        // Variadic constructor with different types.
+        const auto copy = "quince"s;
+        auto move = "tart"s;
+        StaticVector vector = {copy, std::move(move)};
+
+        static_assert(std::is_same_v<decltype(vector), StaticVector<std::string, 2>>);
+        EXPECT_EQ(vector, (StaticVector{"quince"s, "tart"s}));
+    }
+    {
+        // In-place constructor with same types.
+        StaticVector vector(std::in_place_type<std::string>, "red", "velvet", "cake");
+
+        static_assert(std::is_same_v<decltype(vector), StaticVector<std::string, 3>>);
+        EXPECT_EQ(vector, (StaticVector{"red"s, "velvet"s, "cake"s}));
+    }
+    {
+        // In-place constructor with different types.
+        const auto copy = "red"s;
+        auto move = "velvet"s;
+        std::initializer_list<char> list = {'c', 'a', 'k', 'e'};
+        StaticVector vector(std::in_place_type<std::string>, copy.c_str(), std::move(move), list);
+
+        static_assert(std::is_same_v<decltype(vector), StaticVector<std::string, 3>>);
+        EXPECT_EQ(vector, (StaticVector{"red"s, "velvet"s, "cake"s}));
+    }
+}
+
+TEST(StaticVector, String) {
+    StaticVector<char, 10> chars;
+    char c = 'a';
+    std::generate_n(std::back_inserter(chars), chars.max_size(), [&c] { return c++; });
+    chars.back() = '\0';
+
+    EXPECT_STREQ(chars.begin(), "abcdefghi");
+
+    // Constructor takes iterator range.
+    const char kString[] = "123456";
+    StaticVector<char, 10> string(std::begin(kString), std::end(kString));
+
+    EXPECT_STREQ(string.begin(), "123456");
+    EXPECT_EQ(string.size(), 7u);
+
+    // Similar to emplace, but replaces rather than inserts.
+    const auto it = string.replace(string.begin() + 5, '\0');
+    EXPECT_NE(it, string.end());
+    EXPECT_STREQ(string.begin(), "12345");
+
+    swap(chars, string);
+
+    EXPECT_STREQ(chars.begin(), "12345");
+    EXPECT_STREQ(string.begin(), "abcdefghi");
+}
+
+TEST(StaticVector, CopyableElement) {
+    struct Pair {
+        const int a, b;
+        bool operator==(Pair p) const { return p.a == a && p.b == b; }
+    };
+
+    StaticVector<Pair, 5> pairs;
+
+    EXPECT_TRUE(pairs.empty());
+    EXPECT_EQ(pairs.max_size(), 5u);
+
+    for (size_t i = 0; i < pairs.max_size(); ++i) {
+        EXPECT_EQ(pairs.size(), i);
+
+        const int a = static_cast<int>(i) * 2;
+        const auto it = pairs.emplace_back(a, a + 1);
+        ASSERT_NE(it, pairs.end());
+        EXPECT_EQ(*it, (Pair{a, a + 1}));
+    }
+
+    EXPECT_TRUE(pairs.full());
+    EXPECT_EQ(pairs.size(), 5u);
+
+    // Insertion fails if the vector is full.
+    const auto it = pairs.emplace_back(10, 11);
+    EXPECT_EQ(it, pairs.end());
+
+    EXPECT_EQ(pairs, (StaticVector{Pair{0, 1}, Pair{2, 3}, Pair{4, 5}, Pair{6, 7}, Pair{8, 9}}));
+
+    // Constructor takes at most N elements.
+    StaticVector<int, 6> sums = {0, 0, 0, 0, 0, -1};
+    EXPECT_TRUE(sums.full());
+
+    // Random-access iterators comply with standard.
+    std::transform(pairs.begin(), pairs.end(), sums.begin(), [](Pair p) { return p.a + p.b; });
+    EXPECT_EQ(sums, (StaticVector{1, 5, 9, 13, 17, -1}));
+
+    sums.pop_back();
+    std::reverse(sums.begin(), sums.end());
+
+    EXPECT_EQ(sums, (StaticVector{17, 13, 9, 5, 1}));
+}
+
+TEST(StaticVector, MovableElement) {
+    // Construct std::string elements in-place from C-style strings. Without std::in_place_type, the
+    // element type would be deduced from the first element, i.e. const char*.
+    StaticVector strings(std::in_place_type<std::string>, "", "", "", "cake", "velvet", "red", "");
+    strings.pop_back();
+
+    EXPECT_EQ(strings.max_size(), 7u);
+    EXPECT_EQ(strings.size(), 6u);
+
+    // Erase "cake" and append a substring copy.
+    {
+        auto it = std::find_if(strings.begin(), strings.end(),
+                               [](const auto& s) { return !s.empty(); });
+        ASSERT_FALSE(it == strings.end());
+        EXPECT_EQ(*it, "cake");
+
+        strings.unstable_erase(it);
+
+        // Construct std::string from first 4 characters of C-style string.
+        it = strings.emplace_back("cakewalk", 4u);
+        ASSERT_NE(it, strings.end());
+        EXPECT_EQ(*it, "cake"s);
+    }
+
+    strings[1] = "quince"s;
+
+    // Replace last empty string with "tart".
+    {
+        const auto rit = std::find(strings.rbegin(), strings.rend(), std::string());
+        ASSERT_FALSE(rit == strings.rend());
+
+        std::initializer_list<char> list = {'t', 'a', 'r', 't'};
+        const auto it = strings.replace(rit.base() - 1, list);
+        EXPECT_NE(it, strings.end());
+    }
+
+    strings.front().assign("pie");
+
+    EXPECT_EQ(strings, (StaticVector{"pie"s, "quince"s, "tart"s, "red"s, "velvet"s, "cake"s}));
+}
+
+TEST(StaticVector, ReverseTruncate) {
+    StaticVector<std::string, 10> strings("pie", "quince", "tart", "red", "velvet", "cake");
+    EXPECT_FALSE(strings.full());
+
+    for (auto it = strings.begin(); it != strings.end(); ++it) {
+        strings.replace(it, strings.back());
+        strings.pop_back();
+    }
+
+    EXPECT_EQ(strings, (StaticVector{"cake"s, "velvet"s, "red"s}));
+}
+
+TEST(StaticVector, Sort) {
+    StaticVector<std::string, 7> strings("pie", "quince", "tart", "red", "velvet", "cake");
+    EXPECT_FALSE(strings.full());
+
+    auto sorted = std::move(strings);
+    EXPECT_TRUE(strings.empty());
+
+    std::sort(sorted.begin(), sorted.end());
+    EXPECT_EQ(sorted, (StaticVector{"cake"s, "pie"s, "quince"s, "red"s, "tart"s, "velvet"s}));
+
+    // Constructor takes array reference.
+    {
+        const char* kStrings[] = {"cake", "lie"};
+        strings = StaticVector(kStrings);
+    }
+
+    EXPECT_GT(sorted, strings);
+    swap(sorted, strings);
+    EXPECT_LT(sorted, strings);
+
+    // Append remaining elements, such that "pie" is the only difference.
+    sorted.replace(sorted.end(), "quince");
+    for (const char* str : {"red", "tart", "velvet"}) sorted.emplace_back(str);
+
+    EXPECT_NE(sorted, strings);
+
+    sorted.replace(sorted.begin() + 1, "pie");
+    EXPECT_EQ(sorted, strings);
+}
+
+namespace {
+
+struct DestroyCounts {
+    DestroyCounts(int& live, int& dead) : counts{live, dead} {}
+    DestroyCounts(const DestroyCounts& other) : counts(other.counts) {}
+    DestroyCounts(DestroyCounts&& other) : counts(other.counts) { other.alive = false; }
+    ~DestroyCounts() { ++(alive ? counts.live : counts.dead); }
+
+    struct {
+        int& live;
+        int& dead;
+    } counts;
+
+    bool alive = true;
+};
+
+void swap(DestroyCounts& lhs, DestroyCounts& rhs) {
+    std::swap(lhs.alive, rhs.alive);
+}
+
+} // namespace
+
+TEST(StaticVector, Destroy) {
+    int live = 0;
+    int dead = 0;
+
+    { StaticVector<DestroyCounts, 5> counts; }
+    EXPECT_EQ(0, live);
+    EXPECT_EQ(0, dead);
+
+    {
+        StaticVector<DestroyCounts, 5> counts;
+        counts.emplace_back(live, dead);
+        counts.emplace_back(live, dead);
+        counts.emplace_back(live, dead);
+    }
+    EXPECT_EQ(3, live);
+    EXPECT_EQ(0, dead);
+
+    live = 0;
+    {
+        StaticVector<DestroyCounts, 5> counts;
+        counts.emplace_back(live, dead);
+        counts.emplace_back(live, dead);
+        counts.emplace_back(live, dead);
+
+        auto copy = counts;
+    }
+    EXPECT_EQ(6, live);
+    EXPECT_EQ(0, dead);
+
+    live = 0;
+    {
+        StaticVector<DestroyCounts, 5> counts;
+        counts.emplace_back(live, dead);
+        counts.emplace_back(live, dead);
+        counts.emplace_back(live, dead);
+
+        auto move = std::move(counts);
+    }
+    EXPECT_EQ(3, live);
+    EXPECT_EQ(3, dead);
+
+    live = dead = 0;
+    {
+        StaticVector<DestroyCounts, 5> counts1;
+        counts1.emplace_back(live, dead);
+        counts1.emplace_back(live, dead);
+        counts1.emplace_back(live, dead);
+
+        StaticVector<DestroyCounts, 5> counts2;
+        counts2.emplace_back(live, dead);
+
+        swap(counts1, counts2);
+
+        EXPECT_EQ(0, live);
+        EXPECT_EQ(2, dead);
+
+        dead = 0;
+    }
+    EXPECT_EQ(4, live);
+    EXPECT_EQ(0, dead);
+}
+
+} // namespace android::test
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index 66fb295..cc31cd5 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -38,14 +38,14 @@
     ],
 
     shared_libs: [
-        "android.hardware.graphics.common-ndk_platform",
+        "android.hardware.graphics.common-unstable-ndk_platform",
         "android.hardware.graphics.mapper@4.0",
         "libhidlbase",
         "liblog",
     ],
 
     export_shared_lib_headers: [
-        "android.hardware.graphics.common-ndk_platform",
+        "android.hardware.graphics.common-unstable-ndk_platform",
         "android.hardware.graphics.mapper@4.0",
         "libhidlbase",
     ],
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index 87f7972..ff64d65 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -23,6 +23,7 @@
 #include <gui/BLASTBufferQueue.h>
 #include <gui/BufferItemConsumer.h>
 #include <gui/GLConsumer.h>
+#include <gui/Surface.h>
 
 #include <utils/Trace.h>
 
@@ -213,12 +214,9 @@
     ATRACE_CALL();
     BQA_LOGV("processNextBufferLocked useNextTransaction=%s", toString(useNextTransaction));
 
-    // Wait to acquire a buffer if there are no frames available or we have acquired the maximum
+    // Wait to acquire a buffer if there are no frames available or we have acquired the max
     // number of buffers.
-    // As a special case, we wait for the first callback before acquiring the second buffer so we
-    // can ensure the first buffer is presented if multiple buffers are queued in succession.
-    if (mNumFrameAvailable == 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1 ||
-        (!mInitialCallbackReceived && mNumAcquired == 1)) {
+    if (mNumFrameAvailable == 0 || maxBuffersAcquired()) {
         BQA_LOGV("processNextBufferLocked waiting for frame available or callback");
         return;
     }
@@ -241,6 +239,7 @@
 
     status_t status = mBufferItemConsumer->acquireBuffer(&bufferItem, -1, false);
     if (status != OK) {
+        BQA_LOGE("Failed to acquire a buffer, err=%s", statusToString(status).c_str());
         return;
     }
     auto buffer = bufferItem.mGraphicBuffer;
@@ -248,14 +247,15 @@
 
     if (buffer == nullptr) {
         mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
+        BQA_LOGE("Buffer was empty");
         return;
     }
 
     if (rejectBuffer(bufferItem)) {
         BQA_LOGE("rejecting buffer:configured size=%dx%d, buffer{size=%dx%d transform=%d}", mWidth,
                  mHeight, buffer->getWidth(), buffer->getHeight(), bufferItem.mTransform);
-        mBufferItemConsumer->releaseBuffer(bufferItem, Fence::NO_FENCE);
-        return;
+        // TODO(b/168917217) temporarily don't reject buffers until we can synchronize buffer size
+        // changes from ViewRootImpl.
     }
 
     mNumAcquired++;
@@ -302,23 +302,31 @@
     return item.mCrop;
 }
 
-void BLASTBufferQueue::onFrameAvailable(const BufferItem& /*item*/) {
+void BLASTBufferQueue::onFrameAvailable(const BufferItem& item) {
     ATRACE_CALL();
     std::unique_lock _lock{mMutex};
 
     const bool nextTransactionSet = mNextTransaction != nullptr;
-    BQA_LOGV("onFrameAvailable nextTransactionSet=%s", toString(nextTransactionSet));
+    BQA_LOGV("onFrameAvailable framenumber=%" PRIu64 " nextTransactionSet=%s mFlushShadowQueue=%s",
+             item.mFrameNumber, toString(nextTransactionSet), toString(mFlushShadowQueue));
 
-    if (nextTransactionSet) {
-        while (mNumFrameAvailable > 0 || mNumAcquired == MAX_ACQUIRED_BUFFERS + 1) {
+    if (nextTransactionSet || mFlushShadowQueue) {
+        while (mNumFrameAvailable > 0 || maxBuffersAcquired()) {
+            BQA_LOGV("waiting in onFrameAvailable...");
             mCallbackCV.wait(_lock);
         }
     }
+    mFlushShadowQueue = false;
     // add to shadow queue
     mNumFrameAvailable++;
     processNextBufferLocked(true);
 }
 
+void BLASTBufferQueue::onFrameReplaced(const BufferItem& item) {
+    BQA_LOGV("onFrameReplaced framenumber=%" PRIu64, item.mFrameNumber);
+    // Do nothing since we are not storing unacquired buffer items locally.
+}
+
 void BLASTBufferQueue::setNextTransaction(SurfaceComposerClient::Transaction* t) {
     std::lock_guard _lock{mMutex};
     mNextTransaction = t;
@@ -341,4 +349,72 @@
     // reject buffers if the buffer size doesn't match.
     return bufWidth != mWidth || bufHeight != mHeight;
 }
+
+// Check if we have acquired the maximum number of buffers.
+// As a special case, we wait for the first callback before acquiring the second buffer so we
+// can ensure the first buffer is presented if multiple buffers are queued in succession.
+bool BLASTBufferQueue::maxBuffersAcquired() const {
+    return mNumAcquired == MAX_ACQUIRED_BUFFERS + 1 ||
+            (!mInitialCallbackReceived && mNumAcquired == 1);
+}
+
+class BBQSurface : public Surface {
+private:
+    sp<BLASTBufferQueue> mBbq;
+public:
+    BBQSurface(const sp<IGraphicBufferProducer>& igbp, bool controlledByApp,
+               const sp<IBinder>& scHandle, const sp<BLASTBufferQueue>& bbq)
+          : Surface(igbp, controlledByApp, scHandle), mBbq(bbq) {}
+
+    void allocateBuffers() override {
+        uint32_t reqWidth = mReqWidth ? mReqWidth : mUserWidth;
+        uint32_t reqHeight = mReqHeight ? mReqHeight : mUserHeight;
+        auto gbp = getIGraphicBufferProducer();
+        std::thread ([reqWidth, reqHeight, gbp=getIGraphicBufferProducer(),
+                      reqFormat=mReqFormat, reqUsage=mReqUsage] () {
+            gbp->allocateBuffers(reqWidth, reqHeight,
+                                 reqFormat, reqUsage);
+
+        }).detach();
+    }
+
+    status_t setFrameRate(float frameRate, int8_t compatibility) override {
+        if (!ValidateFrameRate(frameRate, compatibility, "BBQSurface::setFrameRate")) {
+            return BAD_VALUE;
+        }
+        return mBbq->setFrameRate(frameRate, compatibility);
+    }
+
+    status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId) override {
+        return mBbq->setFrameTimelineVsync(frameTimelineVsyncId);
+    }
+};
+
+// TODO: Can we coalesce this with frame updates? Need to confirm
+// no timing issues.
+status_t BLASTBufferQueue::setFrameRate(float frameRate, int8_t compatibility) {
+    std::unique_lock _lock{mMutex};
+    SurfaceComposerClient::Transaction t;
+
+    return t.setFrameRate(mSurfaceControl, frameRate, compatibility)
+        .apply();
+}
+
+status_t BLASTBufferQueue::setFrameTimelineVsync(int64_t frameTimelineVsyncId) {
+    std::unique_lock _lock{mMutex};
+    SurfaceComposerClient::Transaction t;
+
+    return t.setFrameTimelineVsync(mSurfaceControl, frameTimelineVsyncId)
+        .apply();
+}
+
+sp<Surface> BLASTBufferQueue::getSurface(bool includeSurfaceControlHandle) {
+    std::unique_lock _lock{mMutex};
+    sp<IBinder> scHandle = nullptr;
+    if (includeSurfaceControlHandle && mSurfaceControl) {
+        scHandle = mSurfaceControl->getHandle();
+    }
+    return new BBQSurface(mProducer, true, scHandle, this);
+}
+
 } // namespace android
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 7e894b4..abfee61 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -73,8 +73,8 @@
         nsecs_t vsyncTimestamp;
         PhysicalDisplayId vsyncDisplayId;
         uint32_t vsyncCount;
-        int64_t vsyncId;
-        if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncId)) {
+        VsyncEventData vsyncEventData;
+        if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
             ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "", this,
                   ns2ms(static_cast<nsecs_t>(vsyncTimestamp)));
         }
@@ -117,13 +117,14 @@
     nsecs_t vsyncTimestamp;
     PhysicalDisplayId vsyncDisplayId;
     uint32_t vsyncCount;
-    int64_t vsyncId;
-    if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncId)) {
+    VsyncEventData vsyncEventData;
+    if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount, &vsyncEventData)) {
         ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64
               ", displayId=%s, count=%d, vsyncId=%" PRId64,
-              this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount, vsyncId);
+              this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
+              vsyncEventData.id);
         mWaitingForVsync = false;
-        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncId);
+        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
     }
 
     return 1; // keep the callback
@@ -131,11 +132,11 @@
 
 bool DisplayEventDispatcher::processPendingEvents(nsecs_t* outTimestamp,
                                                   PhysicalDisplayId* outDisplayId,
-                                                  uint32_t* outCount, int64_t* outVsyncId) {
+                                                  uint32_t* outCount,
+                                                  VsyncEventData* outVsyncEventData) {
     bool gotVsync = false;
     DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
     ssize_t n;
-    *outVsyncId = 0;
     while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
         ALOGV("dispatcher %p ~ Read %d events.", this, int(n));
         for (ssize_t i = 0; i < n; i++) {
@@ -148,7 +149,8 @@
                     *outTimestamp = ev.header.timestamp;
                     *outDisplayId = ev.header.displayId;
                     *outCount = ev.vsync.count;
-                    *outVsyncId = ev.vsync.vsyncId;
+                    outVsyncEventData->id = ev.vsync.vsyncId;
+                    outVsyncEventData->deadlineTimestamp = ev.vsync.deadlineTimestamp;
                     break;
                 case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
                     dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 964195d..6f92233 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -888,7 +888,7 @@
     }
 
     virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                  int32_t defaultConfig,
+                                                  int32_t defaultConfig, bool allowGroupSwitching,
                                                   float primaryRefreshRateMin,
                                                   float primaryRefreshRateMax,
                                                   float appRequestRefreshRateMin,
@@ -909,6 +909,11 @@
             ALOGE("setDesiredDisplayConfigSpecs failed to write defaultConfig: %d", result);
             return result;
         }
+        result = data.writeBool(allowGroupSwitching);
+        if (result != NO_ERROR) {
+            ALOGE("setDesiredDisplayConfigSpecs failed to write allowGroupSwitching: %d", result);
+            return result;
+        }
         result = data.writeFloat(primaryRefreshRateMin);
         if (result != NO_ERROR) {
             ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMin: %d", result);
@@ -943,12 +948,14 @@
 
     virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
                                                   int32_t* outDefaultConfig,
+                                                  bool* outAllowGroupSwitching,
                                                   float* outPrimaryRefreshRateMin,
                                                   float* outPrimaryRefreshRateMax,
                                                   float* outAppRequestRefreshRateMin,
                                                   float* outAppRequestRefreshRateMax) {
-        if (!outDefaultConfig || !outPrimaryRefreshRateMin || !outPrimaryRefreshRateMax ||
-            !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) {
+        if (!outDefaultConfig || !outAllowGroupSwitching || !outPrimaryRefreshRateMin ||
+            !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin ||
+            !outAppRequestRefreshRateMax) {
             return BAD_VALUE;
         }
         Parcel data, reply;
@@ -973,6 +980,11 @@
             ALOGE("getDesiredDisplayConfigSpecs failed to read defaultConfig: %d", result);
             return result;
         }
+        result = reply.readBool(outAllowGroupSwitching);
+        if (result != NO_ERROR) {
+            ALOGE("getDesiredDisplayConfigSpecs failed to read allowGroupSwitching: %d", result);
+            return result;
+        }
         result = reply.readFloat(outPrimaryRefreshRateMin);
         if (result != NO_ERROR) {
             ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMin: %d", result);
@@ -1829,6 +1841,13 @@
                 ALOGE("setDesiredDisplayConfigSpecs: failed to read defaultConfig: %d", result);
                 return result;
             }
+            bool allowGroupSwitching;
+            result = data.readBool(&allowGroupSwitching);
+            if (result != NO_ERROR) {
+                ALOGE("setDesiredDisplayConfigSpecs: failed to read allowGroupSwitching: %d",
+                      result);
+                return result;
+            }
             float primaryRefreshRateMin;
             result = data.readFloat(&primaryRefreshRateMin);
             if (result != NO_ERROR) {
@@ -1857,10 +1876,10 @@
                       result);
                 return result;
             }
-            result =
-                    setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
-                                                 primaryRefreshRateMax, appRequestRefreshRateMin,
-                                                 appRequestRefreshRateMax);
+            result = setDesiredDisplayConfigSpecs(displayToken, defaultConfig, allowGroupSwitching,
+                                                  primaryRefreshRateMin, primaryRefreshRateMax,
+                                                  appRequestRefreshRateMin,
+                                                  appRequestRefreshRateMax);
             if (result != NO_ERROR) {
                 ALOGE("setDesiredDisplayConfigSpecs: failed to call setDesiredDisplayConfigSpecs: "
                       "%d",
@@ -1874,13 +1893,14 @@
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> displayToken = data.readStrongBinder();
             int32_t defaultConfig;
+            bool allowGroupSwitching;
             float primaryRefreshRateMin;
             float primaryRefreshRateMax;
             float appRequestRefreshRateMin;
             float appRequestRefreshRateMax;
 
             status_t result =
-                    getDesiredDisplayConfigSpecs(displayToken, &defaultConfig,
+                    getDesiredDisplayConfigSpecs(displayToken, &defaultConfig, &allowGroupSwitching,
                                                  &primaryRefreshRateMin, &primaryRefreshRateMax,
                                                  &appRequestRefreshRateMin,
                                                  &appRequestRefreshRateMax);
@@ -1896,6 +1916,12 @@
                 ALOGE("getDesiredDisplayConfigSpecs: failed to write defaultConfig: %d", result);
                 return result;
             }
+            result = reply->writeBool(allowGroupSwitching);
+            if (result != NO_ERROR) {
+                ALOGE("getDesiredDisplayConfigSpecs: failed to write allowGroupSwitching: %d",
+                      result);
+                return result;
+            }
             result = reply->writeFloat(primaryRefreshRateMin);
             if (result != NO_ERROR) {
                 ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMin: %d",
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 8594ab3..9722f36 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -44,7 +44,6 @@
         cornerRadius(0.0f),
         backgroundBlurRadius(0),
         barrierFrameNumber(0),
-        overrideScalingMode(-1),
         transform(0),
         transformToDisplayInverse(false),
         crop(Rect::INVALID_RECT),
@@ -86,7 +85,6 @@
     SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, barrierSurfaceControl_legacy);
     SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, reparentSurfaceControl);
     SAFE_PARCEL(output.writeUint64, barrierFrameNumber);
-    SAFE_PARCEL(output.writeInt32, overrideScalingMode);
     SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, relativeLayerSurfaceControl);
     SAFE_PARCEL(SurfaceControl::writeNullableToParcel, output, parentSurfaceControlForChild);
     SAFE_PARCEL(output.writeFloat, color.r);
@@ -148,6 +146,21 @@
     SAFE_PARCEL(output.writeByte, frameRateCompatibility);
     SAFE_PARCEL(output.writeUint32, fixedTransformHint);
     SAFE_PARCEL(output.writeUint64, frameNumber);
+    SAFE_PARCEL(output.writeInt64, frameTimelineVsyncId);
+
+    SAFE_PARCEL(output.writeUint32, blurRegions.size());
+    for (auto region : blurRegions) {
+        SAFE_PARCEL(output.writeUint32, region.blurRadius);
+        SAFE_PARCEL(output.writeFloat, region.cornerRadiusTL);
+        SAFE_PARCEL(output.writeFloat, region.cornerRadiusTR);
+        SAFE_PARCEL(output.writeFloat, region.cornerRadiusBL);
+        SAFE_PARCEL(output.writeFloat, region.cornerRadiusBR);
+        SAFE_PARCEL(output.writeFloat, region.alpha);
+        SAFE_PARCEL(output.writeInt32, region.left);
+        SAFE_PARCEL(output.writeInt32, region.top);
+        SAFE_PARCEL(output.writeInt32, region.right);
+        SAFE_PARCEL(output.writeInt32, region.bottom);
+    }
     return NO_ERROR;
 }
 
@@ -176,7 +189,6 @@
     SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &barrierSurfaceControl_legacy);
     SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &reparentSurfaceControl);
     SAFE_PARCEL(input.readUint64, &barrierFrameNumber);
-    SAFE_PARCEL(input.readInt32, &overrideScalingMode);
 
     SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &relativeLayerSurfaceControl);
     SAFE_PARCEL(SurfaceControl::readNullableFromParcel, input, &parentSurfaceControlForChild);
@@ -253,6 +265,25 @@
     SAFE_PARCEL(input.readUint32, &tmpUint32);
     fixedTransformHint = static_cast<ui::Transform::RotationFlags>(tmpUint32);
     SAFE_PARCEL(input.readUint64, &frameNumber);
+    SAFE_PARCEL(input.readInt64, &frameTimelineVsyncId);
+
+    uint32_t numRegions = 0;
+    SAFE_PARCEL(input.readUint32, &numRegions);
+    blurRegions.clear();
+    for (uint32_t i = 0; i < numRegions; i++) {
+        BlurRegion region;
+        SAFE_PARCEL(input.readUint32, &region.blurRadius);
+        SAFE_PARCEL(input.readFloat, &region.cornerRadiusTL);
+        SAFE_PARCEL(input.readFloat, &region.cornerRadiusTR);
+        SAFE_PARCEL(input.readFloat, &region.cornerRadiusBL);
+        SAFE_PARCEL(input.readFloat, &region.cornerRadiusBR);
+        SAFE_PARCEL(input.readFloat, &region.alpha);
+        SAFE_PARCEL(input.readInt32, &region.left);
+        SAFE_PARCEL(input.readInt32, &region.top);
+        SAFE_PARCEL(input.readInt32, &region.right);
+        SAFE_PARCEL(input.readInt32, &region.bottom);
+        blurRegions.push_back(region);
+    }
     return NO_ERROR;
 }
 
@@ -376,15 +407,15 @@
         what |= eBackgroundBlurRadiusChanged;
         backgroundBlurRadius = other.backgroundBlurRadius;
     }
+    if (other.what & eBlurRegionsChanged) {
+        what |= eBlurRegionsChanged;
+        blurRegions = other.blurRegions;
+    }
     if (other.what & eDeferTransaction_legacy) {
         what |= eDeferTransaction_legacy;
         barrierSurfaceControl_legacy = other.barrierSurfaceControl_legacy;
         barrierFrameNumber = other.barrierFrameNumber;
     }
-    if (other.what & eOverrideScalingModeChanged) {
-        what |= eOverrideScalingModeChanged;
-        overrideScalingMode = other.overrideScalingMode;
-    }
     if (other.what & eReparentChildren) {
         what |= eReparentChildren;
         reparentSurfaceControl = other.reparentSurfaceControl;
@@ -593,6 +624,7 @@
     SAFE_PARCEL(output.writeBool, captureSecureLayers);
     SAFE_PARCEL(output.writeInt32, uid);
     SAFE_PARCEL(output.writeInt32, static_cast<int32_t>(dataspace));
+    SAFE_PARCEL(output.writeBool, allowProtected);
     return NO_ERROR;
 }
 
@@ -606,6 +638,7 @@
     SAFE_PARCEL(input.readInt32, &uid);
     SAFE_PARCEL(input.readInt32, &value);
     dataspace = static_cast<ui::Dataspace>(value);
+    SAFE_PARCEL(input.readBool, &allowProtected);
     return NO_ERROR;
 }
 
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 9ce8442..c1155ab 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -63,7 +63,8 @@
 
 } // namespace
 
-Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp)
+Surface::Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp,
+                 const sp<IBinder>& surfaceControlHandle)
       : mGraphicBufferProducer(bufferProducer),
         mCrop(Rect::EMPTY_RECT),
         mBufferAge(0),
@@ -111,6 +112,7 @@
     mProducerControlledByApp = controlledByApp;
     mSwapIntervalZero = false;
     mMaxBufferCount = NUM_BUFFER_SLOTS;
+    mSurfaceControlHandle = surfaceControlHandle;
 }
 
 Surface::~Surface() {
@@ -1521,7 +1523,7 @@
     auto frameTimelineVsyncId = static_cast<int64_t>(va_arg(args, int64_t));
 
     ALOGV("Surface::dispatchSetFrameTimelineVsync");
-    return composerService()->setFrameTimelineVsync(mGraphicBufferProducer, frameTimelineVsyncId);
+    return setFrameTimelineVsync(frameTimelineVsyncId);
 }
 
 bool Surface::transformToDisplayInverse() {
@@ -2288,4 +2290,9 @@
     return composerService()->setFrameRate(mGraphicBufferProducer, frameRate, compatibility);
 }
 
+status_t Surface::setFrameTimelineVsync(int64_t frameTimelineVsyncId) {
+    return composerService()->setFrameTimelineVsync(mGraphicBufferProducer,
+        frameTimelineVsyncId);
+}
+
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 0068ccf..039e900 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -695,8 +695,6 @@
         }
     }
 
-    mListenerCallbacks.clear();
-
     cacheBuffers();
 
     Vector<ComposerState> composerStates;
@@ -709,10 +707,7 @@
         composerStates.add(kv.second);
     }
 
-    mComposerStates.clear();
-
-    displayStates = mDisplayStates;
-    mDisplayStates.clear();
+    displayStates = std::move(mDisplayStates);
 
     if (mForceSynchronous) {
         flags |= ISurfaceComposer::eSynchronous;
@@ -733,21 +728,16 @@
         flags |= ISurfaceComposer::eExplicitEarlyWakeupEnd;
     }
 
-    mForceSynchronous = false;
-    mAnimation = false;
-    mEarlyWakeup = false;
-    mExplicitEarlyWakeupStart = false;
-    mExplicitEarlyWakeupEnd = false;
-
-    uint64_t transactionId = mId;
-    mId = generateId();
-
     sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
     sf->setTransactionState(mFrameTimelineVsyncId, composerStates, displayStates, flags, applyToken,
                             mInputWindowCommands, mDesiredPresentTime,
                             {} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
-                            hasListenerCallbacks, listenerCallbacks, transactionId);
-    mInputWindowCommands.clear();
+                            hasListenerCallbacks, listenerCallbacks, mId);
+    mId = generateId();
+
+    // Clear the current states and flags
+    clear();
+
     mStatus = NO_ERROR;
     return NO_ERROR;
 }
@@ -1027,6 +1017,18 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setBlurRegions(
+        const sp<SurfaceControl>& sc, const std::vector<BlurRegion>& blurRegions) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+    s->what |= layer_state_t::eBlurRegionsChanged;
+    s->blurRegions = blurRegions;
+    return *this;
+}
+
 SurfaceComposerClient::Transaction&
 SurfaceComposerClient::Transaction::deferTransactionUntil_legacy(
         const sp<SurfaceControl>& sc, const sp<SurfaceControl>& barrierSurfaceControl,
@@ -1353,35 +1355,6 @@
     return *this;
 }
 
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setOverrideScalingMode(
-        const sp<SurfaceControl>& sc, int32_t overrideScalingMode) {
-    layer_state_t* s = getLayerState(sc);
-    if (!s) {
-        mStatus = BAD_INDEX;
-        return *this;
-    }
-
-    switch (overrideScalingMode) {
-        case NATIVE_WINDOW_SCALING_MODE_FREEZE:
-        case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
-        case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP:
-        case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP:
-        case -1:
-            break;
-        default:
-            ALOGE("unknown scaling mode: %d",
-                    overrideScalingMode);
-            mStatus = BAD_VALUE;
-            return *this;
-    }
-
-    s->what |= layer_state_t::eOverrideScalingModeChanged;
-    s->overrideScalingMode = overrideScalingMode;
-
-    registerSurfaceControlForCallback(sc);
-    return *this;
-}
-
 #ifndef NO_INPUT
 SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo(
         const sp<SurfaceControl>& sc,
@@ -1539,6 +1512,19 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setFrameTimelineVsync(
+        const sp<SurfaceControl>& sc, int64_t frameTimelineVsyncId) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+
+    s->what |= layer_state_t::eFrameTimelineVsyncChanged;
+    s->frameTimelineVsyncId = frameTimelineVsyncId;
+    return *this;
+}
+
 // ---------------------------------------------------------------------------
 
 DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
@@ -1654,11 +1640,11 @@
 
 sp<SurfaceControl> SurfaceComposerClient::createSurface(const String8& name, uint32_t w, uint32_t h,
                                                         PixelFormat format, uint32_t flags,
-                                                        SurfaceControl* parent,
+                                                        const sp<IBinder>& parentHandle,
                                                         LayerMetadata metadata,
                                                         uint32_t* outTransformHint) {
     sp<SurfaceControl> s;
-    createSurfaceChecked(name, w, h, format, &s, flags, parent, std::move(metadata),
+    createSurfaceChecked(name, w, h, format, &s, flags, parentHandle, std::move(metadata),
                          outTransformHint);
     return s;
 }
@@ -1695,20 +1681,16 @@
 status_t SurfaceComposerClient::createSurfaceChecked(const String8& name, uint32_t w, uint32_t h,
                                                      PixelFormat format,
                                                      sp<SurfaceControl>* outSurface, uint32_t flags,
-                                                     SurfaceControl* parent, LayerMetadata metadata,
+                                                     const sp<IBinder>& parentHandle,
+                                                     LayerMetadata metadata,
                                                      uint32_t* outTransformHint) {
     sp<SurfaceControl> sur;
     status_t err = mStatus;
 
     if (mStatus == NO_ERROR) {
         sp<IBinder> handle;
-        sp<IBinder> parentHandle;
         sp<IGraphicBufferProducer> gbp;
 
-        if (parent != nullptr) {
-            parentHandle = parent->getHandle();
-        }
-
         uint32_t transformHint = 0;
         int32_t id = -1;
         err = mClient->createSurface(name, w, h, format, flags, parentHandle, std::move(metadata),
@@ -1803,27 +1785,24 @@
     return ComposerService::getComposerService()->getActiveConfig(display);
 }
 
-status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                             int32_t defaultConfig,
-                                                             float primaryRefreshRateMin,
-                                                             float primaryRefreshRateMax,
-                                                             float appRequestRefreshRateMin,
-                                                             float appRequestRefreshRateMax) {
+status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(
+        const sp<IBinder>& displayToken, int32_t defaultConfig, bool allowGroupSwitching,
+        float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin,
+        float appRequestRefreshRateMax) {
     return ComposerService::getComposerService()
-            ->setDesiredDisplayConfigSpecs(displayToken, defaultConfig, primaryRefreshRateMin,
-                                           primaryRefreshRateMax, appRequestRefreshRateMin,
-                                           appRequestRefreshRateMax);
+            ->setDesiredDisplayConfigSpecs(displayToken, defaultConfig, allowGroupSwitching,
+                                           primaryRefreshRateMin, primaryRefreshRateMax,
+                                           appRequestRefreshRateMin, appRequestRefreshRateMax);
 }
 
-status_t SurfaceComposerClient::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                             int32_t* outDefaultConfig,
-                                                             float* outPrimaryRefreshRateMin,
-                                                             float* outPrimaryRefreshRateMax,
-                                                             float* outAppRequestRefreshRateMin,
-                                                             float* outAppRequestRefreshRateMax) {
+status_t SurfaceComposerClient::getDesiredDisplayConfigSpecs(
+        const sp<IBinder>& displayToken, int32_t* outDefaultConfig, bool* outAllowGroupSwitching,
+        float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax,
+        float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) {
     return ComposerService::getComposerService()
-            ->getDesiredDisplayConfigSpecs(displayToken, outDefaultConfig, outPrimaryRefreshRateMin,
-                                           outPrimaryRefreshRateMax, outAppRequestRefreshRateMin,
+            ->getDesiredDisplayConfigSpecs(displayToken, outDefaultConfig, outAllowGroupSwitching,
+                                           outPrimaryRefreshRateMin, outPrimaryRefreshRateMax,
+                                           outAppRequestRefreshRateMin,
                                            outAppRequestRefreshRateMax);
 }
 
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 5b1a018..2300e81 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -72,9 +72,10 @@
     sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
         return mProducer;
     }
+    sp<Surface> getSurface(bool includeSurfaceControlHandle);
 
     void onBufferFreed(const wp<GraphicBuffer>&/* graphicBuffer*/) override { /* TODO */ }
-    void onFrameReplaced(const BufferItem& item) override {onFrameAvailable(item);}
+    void onFrameReplaced(const BufferItem& item) override;
     void onFrameAvailable(const BufferItem& item) override;
 
     void transactionCallback(nsecs_t latchTime, const sp<Fence>& presentFence,
@@ -82,6 +83,10 @@
     void setNextTransaction(SurfaceComposerClient::Transaction *t);
 
     void update(const sp<SurfaceControl>& surface, uint32_t width, uint32_t height);
+    void flushShadowQueue() { mFlushShadowQueue = true; }
+
+    status_t setFrameRate(float frameRate, int8_t compatibility);
+    status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId);
 
     virtual ~BLASTBufferQueue() = default;
 
@@ -93,9 +98,10 @@
     BLASTBufferQueue(const BLASTBufferQueue& rhs);
 
     void processNextBufferLocked(bool useNextTransaction) REQUIRES(mMutex);
-    Rect computeCrop(const BufferItem& item);
+    Rect computeCrop(const BufferItem& item) REQUIRES(mMutex);
     // Return true if we need to reject the buffer based on the scaling mode and the buffer size.
-    bool rejectBuffer(const BufferItem& item) const;
+    bool rejectBuffer(const BufferItem& item) const REQUIRES(mMutex);
+    bool maxBuffersAcquired() const REQUIRES(mMutex);
 
     std::string mName;
     sp<SurfaceControl> mSurfaceControl;
@@ -130,6 +136,9 @@
     sp<BLASTBufferItemConsumer> mBufferItemConsumer;
 
     SurfaceComposerClient::Transaction* mNextTransaction GUARDED_BY(mMutex);
+    // If set to true, the next queue buffer will wait until the shadow queue has been processed by
+    // the adapter.
+    bool mFlushShadowQueue = false;
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index cf598ea..c65618b 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -20,6 +20,17 @@
 
 namespace android {
 
+struct VsyncEventData {
+    // The Vsync Id corresponsing to this vsync event. This will be used to
+    // populate ISurfaceComposer::setFrameTimelineVsync and
+    // SurfaceComposerClient::setFrameTimelineVsync
+    int64_t id = ISurfaceComposer::INVALID_VSYNC_ID;
+
+    // The deadline in CLOCK_MONOTONIC that the app needs to complete its
+    // frame by (both on the CPU and the GPU)
+    int64_t deadlineTimestamp = std::numeric_limits<int64_t>::max();
+};
+
 class DisplayEventDispatcher : public LooperCallback {
 public:
     explicit DisplayEventDispatcher(
@@ -44,7 +55,7 @@
     bool mWaitingForVsync;
 
     virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
-                               int64_t vsyncId) = 0;
+                               VsyncEventData vsyncEventData) = 0;
     virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
                                  bool connected) = 0;
     virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
@@ -54,6 +65,6 @@
     virtual void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) = 0;
 
     bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
-                              uint32_t* outCount, int64_t* outVsyncId);
+                              uint32_t* outCount, VsyncEventData* outVsyncEventData);
 };
 } // namespace android
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index a416147..5cd9356 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -395,7 +395,7 @@
      * returned from getDisplayConfigs().
      */
     virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                  int32_t defaultConfig,
+                                                  int32_t defaultConfig, bool allowGroupSwitching,
                                                   float primaryRefreshRateMin,
                                                   float primaryRefreshRateMax,
                                                   float appRequestRefreshRateMin,
@@ -403,6 +403,7 @@
 
     virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
                                                   int32_t* outDefaultConfig,
+                                                  bool* outAllowGroupSwitching,
                                                   float* outPrimaryRefreshRateMin,
                                                   float* outPrimaryRefreshRateMax,
                                                   float* outAppRequestRefreshRateMin,
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index ff395ec..a73d9a6 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -51,6 +51,7 @@
 #include <gui/LayerMetadata.h>
 #include <gui/SurfaceControl.h>
 #include <math/vec3.h>
+#include <ui/BlurRegion.h>
 #include <ui/GraphicTypes.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -94,7 +95,7 @@
         eLayerStackChanged = 0x00000080,
         eCropChanged_legacy = 0x00000100,
         eDeferTransaction_legacy = 0x00000200,
-        eOverrideScalingModeChanged = 0x00000400,
+        /* was ScalingModeChanged, now available 0x00000400, */
         eShadowRadiusChanged = 0x00000800,
         eReparentChildren = 0x00001000,
         eDetachChildren = 0x00002000,
@@ -127,6 +128,8 @@
         eProducerDisconnect = 0x100'00000000,
         eFixedTransformHintChanged = 0x200'00000000,
         eFrameNumberChanged = 0x400'00000000,
+        eFrameTimelineVsyncChanged = 0x800'00000000,
+        eBlurRegionsChanged = 0x1000'00000000,
     };
 
     layer_state_t();
@@ -163,7 +166,6 @@
     sp<SurfaceControl> barrierSurfaceControl_legacy;
     sp<SurfaceControl> reparentSurfaceControl;
     uint64_t barrierFrameNumber;
-    int32_t overrideScalingMode;
 
     sp<SurfaceControl> relativeLayerSurfaceControl;
 
@@ -186,6 +188,7 @@
     int32_t api;
     sp<NativeHandle> sidebandStream;
     mat4 colorTransform;
+    std::vector<BlurRegion> blurRegions;
 
 #ifndef NO_INPUT
     sp<InputWindowHandle> inputHandle = new InputWindowHandle();
@@ -228,6 +231,8 @@
     // Used by BlastBufferQueue to forward the framenumber generated by the
     // graphics producer.
     uint64_t frameNumber;
+
+    int64_t frameTimelineVsyncId;
 };
 
 struct ComposerState {
@@ -319,6 +324,14 @@
     // NOTE: In normal cases, we want the screen to be captured in display's colorspace.
     ui::Dataspace dataspace = ui::Dataspace::UNKNOWN;
 
+    // The receiver of the capture can handle protected buffer. A protected buffer has
+    // GRALLOC_USAGE_PROTECTED usage bit and must not be accessed unprotected behaviour.
+    // Any read/write access from unprotected context will result in undefined behaviour.
+    // Protected contents are typically DRM contents. This has no direct implication to the
+    // secure property of the surface, which is specified by the application explicitly to avoid
+    // the contents being accessed/captured by screenshot or unsecure display.
+    bool allowProtected = false;
+
     virtual status_t write(Parcel& output) const;
     virtual status_t read(const Parcel& input);
 };
@@ -346,7 +359,7 @@
     sp<GraphicBuffer> buffer;
     bool capturedSecureLayers{false};
     ui::Dataspace capturedDataspace{ui::Dataspace::V0_SRGB};
-    status_t result = NO_ERROR;
+    status_t result = OK;
 
     status_t write(Parcel& output) const;
     status_t read(const Parcel& input);
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index a68f2e7..4aa076e 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -68,7 +68,6 @@
     : public ANativeObjectBase<ANativeWindow, Surface, RefBase>
 {
 public:
-
     /*
      * creates a Surface from the given IGraphicBufferProducer (which concrete
      * implementation is a BufferQueue).
@@ -83,9 +82,15 @@
      *
      * the controlledByApp flag indicates that this Surface (producer) is
      * controlled by the application. This flag is used at connect time.
+     *
+     * Pass in the SurfaceControlHandle to store a weak reference to the layer
+     * that the Surface was created from. This handle can be used to create a
+     * child surface without using the IGBP to identify the layer. This is used
+     * for surfaces created by the BlastBufferQueue whose IGBP is created on the
+     * client and cannot be verified in SF.
      */
-    explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer,
-            bool controlledByApp = false);
+    explicit Surface(const sp<IGraphicBufferProducer>& bufferProducer, bool controlledByApp = false,
+                     const sp<IBinder>& surfaceControlHandle = nullptr);
 
     /* getIGraphicBufferProducer() returns the IGraphicBufferProducer this
      * Surface was created with. Usually it's an error to use the
@@ -93,6 +98,8 @@
      */
     sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
 
+    sp<IBinder> getSurfaceControlHandle() const { return mSurfaceControlHandle; }
+
     /* convenience function to check that the given surface is non NULL as
      * well as its IGraphicBufferProducer */
     static bool isValid(const sp<Surface>& surface) {
@@ -120,7 +127,7 @@
      * delay during dequeueBuffer. If there are already the maximum number of
      * buffers allocated, this function has no effect.
      */
-    void allocateBuffers();
+    virtual void allocateBuffers();
 
     /* Sets the generation number on the IGraphicBufferProducer and updates the
      * generation number on any buffers attached to the Surface after this call.
@@ -179,7 +186,8 @@
     status_t getUniqueId(uint64_t* outId) const;
     status_t getConsumerUsage(uint64_t* outUsage) const;
 
-    status_t setFrameRate(float frameRate, int8_t compatibility);
+    virtual status_t setFrameRate(float frameRate, int8_t compatibility);
+    virtual status_t setFrameTimelineVsync(int64_t frameTimelineVsyncId);
 
 protected:
     virtual ~Surface();
@@ -540,6 +548,11 @@
     bool mEnableFrameTimestamps = false;
     std::unique_ptr<ProducerFrameEventHistory> mFrameEventHistory;
 
+    // Reference to the SurfaceFlinger layer that was used to create this
+    // surface. This is only populated when the Surface is created from
+    // a BlastBufferQueue.
+    sp<IBinder> mSurfaceControlHandle;
+
     bool mReportRemovedBuffers = false;
     std::vector<sp<GraphicBuffer>> mRemovedBuffers;
     int mMaxBufferCount;
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 277060f..73909a3 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -29,6 +29,7 @@
 #include <utils/SortedVector.h>
 #include <utils/threads.h>
 
+#include <ui/BlurRegion.h>
 #include <ui/ConfigStoreTypes.h>
 #include <ui/DisplayedFrameStats.h>
 #include <ui/FrameStats.h>
@@ -120,13 +121,15 @@
 
     // Sets the refresh rate boundaries for the display.
     static status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                 int32_t defaultConfig, float primaryRefreshRateMin,
+                                                 int32_t defaultConfig, bool allowGroupSwitching,
+                                                 float primaryRefreshRateMin,
                                                  float primaryRefreshRateMax,
                                                  float appRequestRefreshRateMin,
                                                  float appRequestRefreshRateMax);
     // Gets the refresh rate boundaries for the display.
     static status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
                                                  int32_t* outDefaultConfig,
+                                                 bool* outAllowGroupSwitching,
                                                  float* outPrimaryRefreshRateMin,
                                                  float* outPrimaryRefreshRateMax,
                                                  float* outAppRequestRefreshRateMin,
@@ -253,13 +256,13 @@
     static sp<SurfaceComposerClient> getDefault();
 
     //! Create a surface
-    sp<SurfaceControl> createSurface(const String8& name,              // name of the surface
-                                     uint32_t w,                       // width in pixel
-                                     uint32_t h,                       // height in pixel
-                                     PixelFormat format,               // pixel-format desired
-                                     uint32_t flags = 0,               // usage flags
-                                     SurfaceControl* parent = nullptr, // parent
-                                     LayerMetadata metadata = LayerMetadata(), // metadata
+    sp<SurfaceControl> createSurface(const String8& name, // name of the surface
+                                     uint32_t w,          // width in pixel
+                                     uint32_t h,          // height in pixel
+                                     PixelFormat format,  // pixel-format desired
+                                     uint32_t flags = 0,  // usage flags
+                                     const sp<IBinder>& parentHandle = nullptr, // parentHandle
+                                     LayerMetadata metadata = LayerMetadata(),  // metadata
                                      uint32_t* outTransformHint = nullptr);
 
     status_t createSurfaceChecked(const String8& name, // name of the surface
@@ -267,9 +270,9 @@
                                   uint32_t h,          // height in pixel
                                   PixelFormat format,  // pixel-format desired
                                   sp<SurfaceControl>* outSurface,
-                                  uint32_t flags = 0,                       // usage flags
-                                  SurfaceControl* parent = nullptr,         // parent
-                                  LayerMetadata metadata = LayerMetadata(), // metadata
+                                  uint32_t flags = 0,                        // usage flags
+                                  const sp<IBinder>& parentHandle = nullptr, // parentHandle
+                                  LayerMetadata metadata = LayerMetadata(),  // metadata
                                   uint32_t* outTransformHint = nullptr);
 
     //! Create a surface
@@ -437,6 +440,8 @@
         Transaction& setCornerRadius(const sp<SurfaceControl>& sc, float cornerRadius);
         Transaction& setBackgroundBlurRadius(const sp<SurfaceControl>& sc,
                                              int backgroundBlurRadius);
+        Transaction& setBlurRegions(const sp<SurfaceControl>& sc,
+                                    const std::vector<BlurRegion>& regions);
         Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
         Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key, const Parcel& p);
         // Defers applying any changes made in this transaction until the Layer
@@ -501,11 +506,6 @@
         // Sometimes the WindowManager needs to extend their lifetime slightly
         // in order to perform an exit animation or prevent flicker.
         Transaction& detachChildren(const sp<SurfaceControl>& sc);
-        // Set an override scaling mode as documented in <system/window.h>
-        // the override scaling mode will take precedence over any client
-        // specified scaling mode. -1 will clear the override scaling mode.
-        Transaction& setOverrideScalingMode(const sp<SurfaceControl>& sc,
-                int32_t overrideScalingMode);
 
 #ifndef NO_INPUT
         Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info);
@@ -537,6 +537,9 @@
         // Sets the frame timeline vsync id received from choreographer that corresponds
         // to the transaction.
         Transaction& setFrameTimelineVsync(int64_t frameTimelineVsyncId);
+        // Variant that only applies to a specific SurfaceControl.
+        Transaction& setFrameTimelineVsync(const sp<SurfaceControl>& sc,
+                int64_t frameTimelineVsyncId);
 
         status_t setDisplaySurface(const sp<IBinder>& token,
                 const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/libs/gui/include/gui/view/Surface.h b/libs/gui/include/gui/view/Surface.h
index cc64fd4..f7dcbc6 100644
--- a/libs/gui/include/gui/view/Surface.h
+++ b/libs/gui/include/gui/view/Surface.h
@@ -21,6 +21,7 @@
 #include <utils/StrongPointer.h>
 #include <utils/String16.h>
 
+#include <binder/IBinder.h>
 #include <binder/Parcelable.h>
 
 namespace android {
@@ -43,6 +44,7 @@
 
     String16 name;
     sp<IGraphicBufferProducer> graphicBufferProducer;
+    sp<IBinder> surfaceControlHandle;
 
     virtual status_t writeToParcel(Parcel* parcel) const override;
     virtual status_t readFromParcel(const Parcel* parcel) override;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 5a376da..0cd3962 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -844,7 +844,7 @@
         return NO_ERROR;
     }
     status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
-                                          int32_t /*defaultConfig*/,
+                                          int32_t /*defaultConfig*/, bool /*allowGroupSwitching*/,
                                           float /*primaryRefreshRateMin*/,
                                           float /*primaryRefreshRateMax*/,
                                           float /*appRequestRefreshRateMin*/,
@@ -853,6 +853,7 @@
     }
     status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
                                           int32_t* /*outDefaultConfig*/,
+                                          bool* /*outAllowGroupSwitching*/,
                                           float* /*outPrimaryRefreshRateMin*/,
                                           float* /*outPrimaryRefreshRateMax*/,
                                           float* /*outAppRequestRefreshRateMin*/,
diff --git a/libs/gui/view/Surface.cpp b/libs/gui/view/Surface.cpp
index d64dfd5..3e49de6 100644
--- a/libs/gui/view/Surface.cpp
+++ b/libs/gui/view/Surface.cpp
@@ -45,7 +45,9 @@
         if (res != OK) return res;
     }
 
-    return IGraphicBufferProducer::exportToParcel(graphicBufferProducer, parcel);
+    res = IGraphicBufferProducer::exportToParcel(graphicBufferProducer, parcel);
+    if (res != OK) return res;
+    return parcel->writeStrongBinder(surfaceControlHandle);
 }
 
 status_t Surface::readFromParcel(const Parcel* parcel) {
@@ -68,6 +70,7 @@
     }
 
     graphicBufferProducer = IGraphicBufferProducer::createFromParcel(parcel);
+    surfaceControlHandle = parcel->readStrongBinder();
     return OK;
 }
 
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index d8c3e6f..fce3000 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -40,8 +40,11 @@
         "Keyboard.cpp",
         "KeyCharacterMap.cpp",
         "KeyLayoutMap.cpp",
+        "LatencyStatistics.cpp",
         "PropertyMap.cpp",
         "TouchVideoFrame.cpp",
+        "VelocityControl.cpp",
+        "VelocityTracker.cpp",
         "VirtualKeyMap.cpp",
     ],
 
@@ -69,9 +72,6 @@
             srcs: [
                 "InputTransport.cpp",
                 "InputWindow.cpp",
-                "LatencyStatistics.cpp",
-                "VelocityControl.cpp",
-                "VelocityTracker.cpp",
                 "android/FocusRequest.aidl",
                 "android/InputApplicationInfo.aidl",
                 "android/os/IInputConstants.aidl",
@@ -99,12 +99,33 @@
             shared: {
                 enabled: false,
             },
+            include_dirs: [
+                "frameworks/native/libs/arect/include",
+            ],
+        },
+        linux_glibc: {
+            srcs: [
+                "InputTransport.cpp",
+                "InputWindow.cpp",
+                "android/FocusRequest.aidl",
+                "android/InputApplicationInfo.aidl",
+                "android/os/IInputConstants.aidl",
+                "android/os/IInputFlinger.aidl",
+                "android/os/ISetInputWindowsListener.aidl",
+                "android/os/TouchOcclusionMode.aidl",
+            ],
+            static_libs: [
+                "libhostgraphics",
+            ],
+            shared_libs: [
+                "libbinder",
+            ],
         },
     },
 
     aidl: {
         local_include_dirs: ["."],
-        export_aidl_headers: true
+        export_aidl_headers: true,
     },
 }
 
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index fb2f186..ad7db75 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -19,18 +19,22 @@
 
 #include <attestation/HmacKeyManager.h>
 #include <cutils/compiler.h>
+#include <inttypes.h>
 #include <limits.h>
 #include <string.h>
 
+#include <android-base/stringprintf.h>
 #include <input/Input.h>
 #include <input/InputDevice.h>
 #include <input/InputEventLabels.h>
 
-#ifdef __ANDROID__
 #include <binder/Parcel.h>
+#ifdef __ANDROID__
 #include <sys/random.h>
 #endif
 
+using android::base::StringPrintf;
+
 namespace android {
 
 const char* motionClassificationToString(MotionClassification classification) {
@@ -250,7 +254,6 @@
     setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset);
 }
 
-#ifdef __ANDROID__
 status_t PointerCoords::readFromParcel(Parcel* parcel) {
     bits = parcel->readInt64();
 
@@ -274,7 +277,6 @@
     }
     return OK;
 }
-#endif
 
 void PointerCoords::tooManyAxes(int axis) {
     ALOGW("Could not set value for axis %d because the PointerCoords structure is full and "
@@ -536,7 +538,6 @@
     }
 }
 
-#ifdef __ANDROID__
 static status_t readFromParcel(ui::Transform& transform, const Parcel& parcel) {
     float dsdx, dtdx, tx, dtdy, dsdy, ty;
     status_t status = parcel.readFloat(&dsdx);
@@ -673,7 +674,6 @@
     }
     return OK;
 }
-#endif
 
 bool MotionEvent::isTouchEvent(uint32_t source, int32_t action) {
     if (source & AINPUT_SOURCE_CLASS_POINTER) {
@@ -700,23 +700,37 @@
     return InputEventLookup::getAxisByLabel(label);
 }
 
-const char* MotionEvent::actionToString(int32_t action) {
+std::string MotionEvent::actionToString(int32_t action) {
     // Convert MotionEvent action to string
     switch (action & AMOTION_EVENT_ACTION_MASK) {
         case AMOTION_EVENT_ACTION_DOWN:
             return "DOWN";
-        case AMOTION_EVENT_ACTION_MOVE:
-            return "MOVE";
         case AMOTION_EVENT_ACTION_UP:
             return "UP";
+        case AMOTION_EVENT_ACTION_MOVE:
+            return "MOVE";
         case AMOTION_EVENT_ACTION_CANCEL:
             return "CANCEL";
+        case AMOTION_EVENT_ACTION_OUTSIDE:
+            return "OUTSIDE";
         case AMOTION_EVENT_ACTION_POINTER_DOWN:
             return "POINTER_DOWN";
         case AMOTION_EVENT_ACTION_POINTER_UP:
             return "POINTER_UP";
+        case AMOTION_EVENT_ACTION_HOVER_MOVE:
+            return "HOVER_MOVE";
+        case AMOTION_EVENT_ACTION_SCROLL:
+            return "SCROLL";
+        case AMOTION_EVENT_ACTION_HOVER_ENTER:
+            return "HOVER_ENTER";
+        case AMOTION_EVENT_ACTION_HOVER_EXIT:
+            return "HOVER_EXIT";
+        case AMOTION_EVENT_ACTION_BUTTON_PRESS:
+            return "BUTTON_PRESS";
+        case AMOTION_EVENT_ACTION_BUTTON_RELEASE:
+            return "BUTTON_RELEASE";
     }
-    return "UNKNOWN";
+    return android::base::StringPrintf("%" PRId32, action);
 }
 
 // --- FocusEvent ---
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 7ac8a2e..2623ecd 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -19,10 +19,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#ifdef __ANDROID__
 #include <binder/Parcel.h>
-#endif
-
 #include <android/keycodes.h>
 #include <attestation/HmacKeyManager.h>
 #include <input/InputEventLabels.h>
@@ -590,7 +587,6 @@
     }
 }
 
-#ifdef __ANDROID__
 std::shared_ptr<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
     if (parcel == nullptr) {
         ALOGE("%s: Null parcel", __func__);
@@ -676,7 +672,6 @@
         parcel->writeInt32(0);
     }
 }
-#endif
 
 
 // --- KeyCharacterMap::Key ---
diff --git a/libs/input/TEST_MAPPING b/libs/input/TEST_MAPPING
new file mode 100644
index 0000000..9626d8d
--- /dev/null
+++ b/libs/input/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "imports": [
+    {
+      "path": "frameworks/native/services/inputflinger"
+    }
+  ]
+}
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 44147a5..b23aade 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -30,7 +30,8 @@
         "liblog",
         "libui",
         "libutils",
-    ]
+    ],
+    test_suites: ["device-tests"],
 }
 
 // NOTE: This is a compile time test, and does not need to be
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 1452745..4f53dc9 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -54,8 +54,12 @@
 };
 
 TEST_F(InputPublisherAndConsumerTest, GetChannel_ReturnsTheChannel) {
+    ASSERT_NE(nullptr, mPublisher->getChannel());
+    ASSERT_NE(nullptr, mConsumer->getChannel());
     EXPECT_EQ(mServerChannel.get(), mPublisher->getChannel().get());
     EXPECT_EQ(mClientChannel.get(), mConsumer->getChannel().get());
+    ASSERT_EQ(mPublisher->getChannel()->getConnectionToken(),
+              mConsumer->getChannel()->getConnectionToken());
 }
 
 void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 470f28f..9e515cd 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -129,13 +129,14 @@
     static Choreographer* getForThread();
     virtual ~Choreographer() override EXCLUDES(gChoreographers.lock);
     int64_t getVsyncId() const;
+    int64_t getFrameDeadline() const;
 
 
 private:
     Choreographer(const Choreographer&) = delete;
 
     void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
-                       int64_t vsyncId) override;
+                       VsyncEventData vsyncEventData) override;
     void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
     void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t configId,
                                nsecs_t vsyncPeriod) override;
@@ -149,7 +150,7 @@
     std::vector<RefreshRateCallback> mRefreshRateCallbacks;
 
     nsecs_t mLatestVsyncPeriod = -1;
-    int64_t mLastVsyncId = -1;
+    VsyncEventData mLastVsyncEventData;
 
     const sp<Looper> mLooper;
     const std::thread::id mThreadId;
@@ -354,7 +355,8 @@
 // TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the
 // internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for
 // the internal display implicitly.
-void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t, int64_t vsyncId) {
+void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t,
+                                  VsyncEventData vsyncEventData) {
     std::vector<FrameCallback> callbacks{};
     {
         std::lock_guard<std::mutex> _l{mLock};
@@ -364,7 +366,7 @@
             mFrameCallbacks.pop();
         }
     }
-    mLastVsyncId = vsyncId;
+    mLastVsyncEventData = vsyncEventData;
     for (const auto& cb : callbacks) {
         if (cb.callback64 != nullptr) {
             cb.callback64(timestamp, cb.data);
@@ -410,7 +412,11 @@
 }
 
 int64_t Choreographer::getVsyncId() const {
-    return mLastVsyncId;
+    return mLastVsyncEventData.id;
+}
+
+int64_t Choreographer::getFrameDeadline() const {
+    return mLastVsyncEventData.deadlineTimestamp;
 }
 
 } // namespace android
@@ -492,6 +498,10 @@
     return AChoreographer_to_Choreographer(choreographer)->getVsyncId();
 }
 
+int64_t AChoreographer_getFrameDeadline(const AChoreographer* choreographer) {
+    return AChoreographer_to_Choreographer(choreographer)->getFrameDeadline();
+}
+
 } // namespace android
 
 /* Glue for the NDK interface */
diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h
index 1d57c15..d3a4a66 100644
--- a/libs/nativedisplay/include-private/private/android/choreographer.h
+++ b/libs/nativedisplay/include-private/private/android/choreographer.h
@@ -35,6 +35,13 @@
 // this function from anywhere else will return an undefined value.
 int64_t AChoreographer_getVsyncId(const AChoreographer* choreographer);
 
+// Returns the deadline timestamp (in CLOCK_MONOTONIC) of the last frame callback.
+// Client are expected to call this function from their frame callback function
+// to get the deadline and use it to know whether a frame is likely to miss
+// presentation. Calling this function from anywhere else will return an undefined
+// value.
+int64_t AChoreographer_getFrameDeadline(const AChoreographer* choreographer);
+
 // Trampoline functions allowing libandroid.so to define the NDK symbols without including
 // the entirety of libnativedisplay as a whole static lib. As libnativedisplay
 // maintains global state, libnativedisplay can never be directly statically
diff --git a/libs/nativedisplay/libnativedisplay.map.txt b/libs/nativedisplay/libnativedisplay.map.txt
index 5ed2e49..fda6a20 100644
--- a/libs/nativedisplay/libnativedisplay.map.txt
+++ b/libs/nativedisplay/libnativedisplay.map.txt
@@ -30,6 +30,7 @@
       android::AChoreographer_routeUnregisterRefreshRateCallback*;
       android::AChoreographer_signalRefreshRateCallbacks*;
       android::AChoreographer_getVsyncId*;
+      android::AChoreographer_getFrameDeadline*;
       android::ADisplay_acquirePhysicalDisplays*;
       android::ADisplay_release*;
       android::ADisplay_getMaxSupportedFps*;
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 52d73e0..07e5d86 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -40,6 +40,7 @@
 
 cc_library {
     name: "libnativewindow",
+    llndk_stubs: "libnativewindow.llndk",
     export_include_dirs: [
         "include",
         "include-private",
@@ -95,7 +96,7 @@
 }
 
 llndk_library {
-    name: "libnativewindow",
+    name: "libnativewindow.llndk",
     symbol_file: "libnativewindow.map.txt",
     unversioned: true,
     export_include_dirs: ["include"],
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 6adcbea..13577f7 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -735,9 +735,9 @@
     bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(),
                                                    buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
     if (!created) {
-        ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
-              buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
-              buffer->getPixelFormat());
+        ALOGE("Failed to create image. id=%" PRIx64 " size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
+              buffer->getId(), buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
+              buffer->getUsage(), buffer->getPixelFormat());
         return NO_INIT;
     }
 
@@ -1218,6 +1218,11 @@
             texCoords[2] = vec2(1.0, 1.0);
             texCoords[3] = vec2(1.0, 0.0);
             setupLayerTexturing(texture);
+
+            // Do not cache protected EGLImage, protected memory is limited.
+            if (gBuf->getUsage() & GRALLOC_USAGE_PROTECTED) {
+                unbindExternalTextureBuffer(gBuf->getId());
+            }
         }
 
         const half3 solidColor = layer->source.solidColor;
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 95e9367..d8d989e 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -21,6 +21,7 @@
 #include <math/mat4.h>
 #include <math/vec3.h>
 #include <renderengine/Texture.h>
+#include <ui/BlurRegion.h>
 #include <ui/Fence.h>
 #include <ui/FloatRect.h>
 #include <ui/GraphicBuffer.h>
@@ -151,6 +152,8 @@
     ShadowSettings shadow;
 
     int backgroundBlurRadius = 0;
+
+    std::vector<BlurRegion> blurRegions;
 };
 
 // Keep in sync with custom comparison function in
@@ -182,7 +185,29 @@
             lhs.length == rhs.length && lhs.casterIsTranslucent == rhs.casterIsTranslucent;
 }
 
+static inline bool operator==(const BlurRegion& lhs, const BlurRegion& rhs) {
+    return lhs.alpha == rhs.alpha && lhs.cornerRadiusTL == rhs.cornerRadiusTL &&
+            lhs.cornerRadiusTR == rhs.cornerRadiusTR && lhs.cornerRadiusBL == rhs.cornerRadiusBL &&
+            lhs.cornerRadiusBR == rhs.cornerRadiusBR && lhs.blurRadius == rhs.blurRadius &&
+            lhs.left == rhs.left && lhs.top == rhs.top && lhs.right == rhs.right &&
+            lhs.bottom == rhs.bottom;
+}
+
+static inline bool operator!=(const BlurRegion& lhs, const BlurRegion& rhs) {
+    return !(lhs == rhs);
+}
+
 static inline bool operator==(const LayerSettings& lhs, const LayerSettings& rhs) {
+    if (lhs.blurRegions.size() != rhs.blurRegions.size()) {
+        return false;
+    }
+    const auto size = lhs.blurRegions.size();
+    for (size_t i = 0; i < size; i++) {
+        if (lhs.blurRegions[i] != rhs.blurRegions[i]) {
+            return false;
+        }
+    }
+
     return lhs.geometry == rhs.geometry && lhs.source == rhs.source && lhs.alpha == rhs.alpha &&
             lhs.sourceDataspace == rhs.sourceDataspace &&
             lhs.colorTransform == rhs.colorTransform &&
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 69ad189..03c8e80 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -23,6 +23,14 @@
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <GLES2/gl2.h>
+#include <sync/sync.h>
+#include <ui/BlurRegion.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Trace.h>
+#include "../gl/GLExtensions.h"
+#include "SkiaGLRenderEngine.h"
+#include "filters/BlurFilter.h"
+
 #include <GrContextOptions.h>
 #include <SkCanvas.h>
 #include <SkColorFilter.h>
@@ -500,10 +508,25 @@
         SkPaint paint;
         const auto& bounds = layer->geometry.boundaries;
         const auto dest = getSkRect(bounds);
+        std::unordered_map<uint32_t, sk_sp<SkSurface>> cachedBlurs;
 
-        if (layer->backgroundBlurRadius > 0) {
-            ATRACE_NAME("BackgroundBlur");
-            mBlurFilter->draw(canvas, surface, layer->backgroundBlurRadius);
+        if (mBlurFilter) {
+            if (layer->backgroundBlurRadius > 0) {
+                ATRACE_NAME("BackgroundBlur");
+                auto blurredSurface =
+                        mBlurFilter->draw(canvas, surface, layer->backgroundBlurRadius);
+                cachedBlurs[layer->backgroundBlurRadius] = blurredSurface;
+            }
+            if (layer->blurRegions.size() > 0) {
+                for (auto region : layer->blurRegions) {
+                    if (cachedBlurs[region.blurRadius]) {
+                        continue;
+                    }
+                    ATRACE_NAME("BlurRegion");
+                    auto blurredSurface = mBlurFilter->generate(canvas, surface, region.blurRadius);
+                    cachedBlurs[region.blurRadius] = blurredSurface;
+                }
+            }
         }
 
         if (layer->source.buffer.buffer) {
@@ -571,7 +594,11 @@
         } else {
             ATRACE_NAME("DrawColor");
             const auto color = layer->source.solidColor;
-            paint.setColor(SkColor4f{.fR = color.r, .fG = color.g, .fB = color.b, layer->alpha});
+            paint.setShader(SkShaders::Color(SkColor4f{.fR = color.r,
+                                                       .fG = color.g,
+                                                       .fB = color.b,
+                                                       layer->alpha},
+                                             nullptr));
         }
 
         paint.setColorFilter(SkColorFilters::Matrix(toSkColorMatrix(display.colorTransform)));
@@ -580,6 +607,10 @@
         canvas->save();
         canvas->concat(getSkM44(layer->geometry.positionTransform));
 
+        for (const auto effectRegion : layer->blurRegions) {
+            drawBlurRegion(canvas, effectRegion, dest, cachedBlurs[effectRegion.blurRadius]);
+        }
+
         if (layer->shadow.length > 0) {
             const auto rect = layer->geometry.roundedCornersRadius > 0
                     ? getSkRect(layer->geometry.roundedCornersCrop)
@@ -592,6 +623,7 @@
         } else {
             canvas->drawRect(dest, paint);
         }
+
         canvas->restore();
     }
     {
@@ -678,6 +710,34 @@
                               flags);
 }
 
+void SkiaGLRenderEngine::drawBlurRegion(SkCanvas* canvas, const BlurRegion& effectRegion,
+                                        const SkRect& layerBoundaries,
+                                        sk_sp<SkSurface> blurredSurface) {
+    ATRACE_CALL();
+    SkPaint paint;
+    paint.setAlpha(static_cast<int>(effectRegion.alpha * 255));
+    const auto rect = SkRect::MakeLTRB(effectRegion.left, effectRegion.top, effectRegion.right,
+                                       effectRegion.bottom);
+
+    const auto matrix = mBlurFilter->getShaderMatrix(
+            SkMatrix::MakeTrans(layerBoundaries.left(), layerBoundaries.top()));
+    paint.setShader(blurredSurface->makeImageSnapshot()->makeShader(matrix));
+
+    if (effectRegion.cornerRadiusTL > 0 || effectRegion.cornerRadiusTR > 0 ||
+        effectRegion.cornerRadiusBL > 0 || effectRegion.cornerRadiusBR > 0) {
+        const SkVector radii[4] =
+                {SkVector::Make(effectRegion.cornerRadiusTL, effectRegion.cornerRadiusTL),
+                 SkVector::Make(effectRegion.cornerRadiusTR, effectRegion.cornerRadiusTR),
+                 SkVector::Make(effectRegion.cornerRadiusBL, effectRegion.cornerRadiusBL),
+                 SkVector::Make(effectRegion.cornerRadiusBR, effectRegion.cornerRadiusBR)};
+        SkRRect roundedRect;
+        roundedRect.setRectRadii(rect, radii);
+        canvas->drawRRect(roundedRect, paint);
+    } else {
+        canvas->drawRect(rect, paint);
+    }
+}
+
 EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
                                                 EGLContext shareContext, bool useContextPriority,
                                                 Protection protection) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index ed4ba11..0143445 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -75,6 +75,8 @@
     bool waitFence(base::unique_fd fenceFd);
     void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
                     const ShadowSettings& shadowSettings);
+    void drawBlurRegion(SkCanvas* canvas, const BlurRegion& blurRegion, const SkRect& layerBounds,
+                        sk_sp<SkSurface> blurrendSurface);
 
     EGLDisplay mEGLDisplay;
     EGLConfig mEGLConfig;
diff --git a/libs/renderengine/skia/filters/BlurFilter.cpp b/libs/renderengine/skia/filters/BlurFilter.cpp
index eb791a7..f6a316f 100644
--- a/libs/renderengine/skia/filters/BlurFilter.cpp
+++ b/libs/renderengine/skia/filters/BlurFilter.cpp
@@ -55,8 +55,10 @@
     mBlurEffect = std::move(blurEffect);
 }
 
-void BlurFilter::draw(SkCanvas* canvas, sk_sp<SkSurface> input, const uint32_t blurRadius) const {
+sk_sp<SkSurface> BlurFilter::generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
+                                      const uint32_t blurRadius) const {
     ATRACE_CALL();
+
     // Kawase is an approximation of Gaussian, but it behaves differently from it.
     // A radius transformation is required for approximating them, and also to introduce
     // non-integer steps, necessary to smoothly interpolate large radii.
@@ -72,8 +74,10 @@
     const float stepY = radiusByPasses;
 
     // start by drawing and downscaling and doing the first blur pass
+    SkFilterOptions linear = {SkSamplingMode::kLinear, SkMipmapMode::kNone};
     SkRuntimeShaderBuilder blurBuilder(mBlurEffect);
-    blurBuilder.child("input") = input->makeImageSnapshot()->makeShader();
+    blurBuilder.child("input") =
+            input->makeImageSnapshot()->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
     blurBuilder.uniform("in_inverseScale") = kInverseInputScale;
     blurBuilder.uniform("in_blurOffset") =
             SkV2{stepX * kInverseInputScale, stepY * kInverseInputScale};
@@ -97,7 +101,9 @@
         for (auto i = 1; i < numberOfPasses; i++) {
             const float stepScale = (float)i * kInputScale;
 
-            blurBuilder.child("input") = readSurface->makeImageSnapshot()->makeShader();
+            blurBuilder.child("input") =
+                    readSurface->makeImageSnapshot()->makeShader(SkTileMode::kClamp,
+                                                                 SkTileMode::kClamp, linear);
             blurBuilder.uniform("in_inverseScale") = 1.0f;
             blurBuilder.uniform("in_blurOffset") = SkV2{stepX * stepScale, stepY * stepScale};
 
@@ -107,25 +113,35 @@
             drawSurface->getCanvas()->drawIRect(scaledInfo.bounds(), paint);
 
             // Swap buffers for next iteration
-            auto tmp = drawSurface;
+            const auto tmp = drawSurface;
             drawSurface = readSurface;
             readSurface = tmp;
             blurBuilder.child("input") = nullptr;
         }
         lastDrawTarget = readSurface;
     }
+    lastDrawTarget->flushAndSubmit();
+    return lastDrawTarget;
+}
 
-    drawSurface->flushAndSubmit();
+sk_sp<SkSurface> BlurFilter::draw(SkCanvas* canvas, const sk_sp<SkSurface> input,
+                                  const uint32_t blurRadius) const {
+    ATRACE_CALL();
+    auto surface = generate(canvas, input, blurRadius);
 
-    // do the final composition, with alpha blending to hide downscaling artifacts.
-    {
-        SkPaint paint;
-        paint.setShader(lastDrawTarget->makeImageSnapshot()->makeShader(
-                SkMatrix::MakeScale(kInverseInputScale)));
-        paint.setFilterQuality(kLow_SkFilterQuality);
-        paint.setAlpha(std::min(1.0f, (float)blurRadius / kMaxCrossFadeRadius) * 255);
-        canvas->drawIRect(SkIRect::MakeWH(input->width(), input->height()), paint);
-    }
+    SkPaint paint;
+    const auto image = surface->makeImageSnapshot();
+    paint.setShader(image->makeShader(SkMatrix::MakeScale(kInverseInputScale)));
+    paint.setFilterQuality(kLow_SkFilterQuality);
+    paint.setAlpha(std::min(1.0f, (float)blurRadius / kMaxCrossFadeRadius) * 255);
+    canvas->drawIRect(SkIRect::MakeWH(input->width(), input->height()), paint);
+    return surface;
+}
+
+SkMatrix BlurFilter::getShaderMatrix(const SkMatrix& transformMatrix) const {
+    SkMatrix matrix;
+    matrix.setConcat(transformMatrix, SkMatrix::MakeScale(kInverseInputScale));
+    return matrix;
 }
 
 } // namespace skia
diff --git a/libs/renderengine/skia/filters/BlurFilter.h b/libs/renderengine/skia/filters/BlurFilter.h
index 94b3673..6f973d7 100644
--- a/libs/renderengine/skia/filters/BlurFilter.h
+++ b/libs/renderengine/skia/filters/BlurFilter.h
@@ -47,8 +47,14 @@
     explicit BlurFilter();
     virtual ~BlurFilter(){};
 
-    // Execute blur passes, rendering to a canvas.
-    void draw(SkCanvas* canvas, sk_sp<SkSurface> input, const uint32_t radius) const;
+    // Execute blur, saving it to a texture
+    sk_sp<SkSurface> generate(SkCanvas* canvas, const sk_sp<SkSurface> input,
+                              const uint32_t radius) const;
+    // Same as generate but also drawing to the screen
+    sk_sp<SkSurface> draw(SkCanvas* canvas, const sk_sp<SkSurface> input,
+                          const uint32_t radius) const;
+    // Returns a matrix that should be applied to the blur shader
+    SkMatrix getShaderMatrix(const SkMatrix& transformMatrix) const;
 
 private:
     sk_sp<SkRuntimeEffect> mBlurEffect;
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 3fa2e53..7c68aaa 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -140,7 +140,7 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.allocator@4.0",
-        "android.hardware.graphics.common-ndk_platform",
+        "android.hardware.graphics.common-unstable-ndk_platform",
         "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
@@ -157,7 +157,7 @@
 
     export_shared_lib_headers: [
         "android.hardware.graphics.common@1.2",
-        "android.hardware.graphics.common-ndk_platform",
+        "android.hardware.graphics.common-unstable-ndk_platform",
         "android.hardware.graphics.mapper@4.0",
         "libgralloctypes",
     ],
@@ -243,6 +243,8 @@
     name: "libui_host_common",
     srcs: [
         "Rect.cpp",
-        "PixelFormat.cpp"
+        "Region.cpp",
+        "PixelFormat.cpp",
+        "Transform.cpp"
     ],
 }
diff --git a/libs/binder/parcel_fuzzer/random_parcel.h b/libs/ui/include/ui/BlurRegion.h
similarity index 67%
copy from libs/binder/parcel_fuzzer/random_parcel.h
copy to libs/ui/include/ui/BlurRegion.h
index 2923c47..c5a5d47 100644
--- a/libs/binder/parcel_fuzzer/random_parcel.h
+++ b/libs/ui/include/ui/BlurRegion.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2020 The Android Open Source Project
+ * 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.
@@ -16,12 +16,21 @@
 
 #pragma once
 
-#include "binder_ndk.h"
-
-#include <binder/Parcel.h>
-#include <fuzzer/FuzzedDataProvider.h>
+#include <inttypes.h>
 
 namespace android {
-void fillRandomParcel(Parcel* p, FuzzedDataProvider&& provider);
-void fillRandomParcel(NdkParcelAdapter* p, FuzzedDataProvider&& provider);
-} // namespace android
+
+struct BlurRegion {
+    uint32_t blurRadius;
+    float cornerRadiusTL;
+    float cornerRadiusTR;
+    float cornerRadiusBL;
+    float cornerRadiusBR;
+    float alpha;
+    int left;
+    int top;
+    int right;
+    int bottom;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp b/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp
index afde5f7..1703f48 100644
--- a/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp
+++ b/libs/vr/libpdx/fuzz/serialization_fuzzer.cpp
@@ -52,7 +52,7 @@
 
 // Fuzzer for Serialization operations, this is mostly just lifted from the
 // existing test cases to use fuzzed values as inputs.
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+void FuzzSerializeDeserialize(const uint8_t* data, size_t size) {
   FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
   Payload result;
 
@@ -106,6 +106,10 @@
   Deserialize(&vec_val, &result);
   Serialize(t1_val, &result);
   Deserialize(&t1_val, &result);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  FuzzSerializeDeserialize(data, size);
 
   return 0;
 }
diff --git a/opengl/Android.bp b/opengl/Android.bp
index 9ca8b0b..393ced7 100644
--- a/opengl/Android.bp
+++ b/opengl/Android.bp
@@ -53,25 +53,25 @@
 }
 
 llndk_library {
-    name: "libEGL",
+    name: "libEGL.llndk",
     symbol_file: "libs/libEGL.map.txt",
     export_include_dirs: ["include"],
 }
 
 llndk_library {
-    name: "libGLESv1_CM",
+    name: "libGLESv1_CM.llndk",
     symbol_file: "libs/libGLESv1_CM.map.txt",
     export_include_dirs: ["include"],
 }
 
 llndk_library {
-    name: "libGLESv2",
+    name: "libGLESv2.llndk",
     symbol_file: "libs/libGLESv2.map.txt",
     export_include_dirs: ["include"],
 }
 
 llndk_library {
-    name: "libGLESv3",
+    name: "libGLESv3.llndk",
     symbol_file: "libs/libGLESv3.map.txt",
     export_include_dirs: ["include"],
 }
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index 3c76c62..77d887c 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -128,6 +128,7 @@
 cc_library_shared {
     name: "libEGL",
     defaults: ["egl_libs_defaults"],
+    llndk_stubs: "libEGL.llndk",
     srcs: [
         "EGL/egl_tls.cpp",
         "EGL/egl_cache.cpp",
@@ -193,6 +194,7 @@
 cc_library_shared {
     name: "libGLESv1_CM",
     defaults: ["gles_libs_defaults"],
+    llndk_stubs: "libGLESv1_CM.llndk",
     srcs: ["GLES_CM/gl.cpp"],
     cflags: ["-DLOG_TAG=\"libGLESv1\""],
     version_script: "libGLESv1_CM.map.txt",
@@ -204,6 +206,7 @@
 cc_library_shared {
     name: "libGLESv2",
     defaults: ["gles_libs_defaults"],
+    llndk_stubs: "libGLESv2.llndk",
     srcs: ["GLES2/gl2.cpp"],
     cflags: ["-DLOG_TAG=\"libGLESv2\""],
 
@@ -218,6 +221,7 @@
 cc_library_shared {
     name: "libGLESv3",
     defaults: ["gles_libs_defaults"],
+    llndk_stubs: "libGLESv3.llndk",
     srcs: ["GLES2/gl2.cpp"],
     cflags: ["-DLOG_TAG=\"libGLESv3\""],
 }
diff --git a/opengl/tools/glgen/src/JniCodeEmitter.java b/opengl/tools/glgen/src/JniCodeEmitter.java
index 9c80212..59ef3c8 100644
--- a/opengl/tools/glgen/src/JniCodeEmitter.java
+++ b/opengl/tools/glgen/src/JniCodeEmitter.java
@@ -15,6 +15,7 @@
  */
 
 import java.io.PrintStream;
+import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -201,6 +202,33 @@
         out.println(iii + ");");
     }
 
+    // Function to automatically generate properly formatted function calls that
+    // comply with clang format rules
+    public static String formatFunctionCall(String indent, String functionCall) {
+        final int MAXLEN = 100;
+        String tokens[] = functionCall.split("\\(|\\)", 2);
+        String params[] = tokens[1].split(",\\s*");
+        String formatted = indent + tokens[0] + "(";
+        char[] chars = new char[indent.length() + tokens[0].length() + 1];
+        Arrays.fill(chars, ' ');
+        String multiIndent = new String(chars);
+        ArrayList<String> lines = new ArrayList<String>();
+        for(int i = 0; i < params.length; i++) {
+            String terminator = ((i == params.length - 1) ? "" : ",");
+            if(indent.length() + formatted.length() + params[i].length() > MAXLEN) {
+                lines.add(formatted);
+                if (!indent.equals(multiIndent)) {
+                    indent = multiIndent;
+                }
+                formatted = indent + params[i] + terminator;
+            } else {
+              formatted += (i == 0 ? "" : " ") + params[i] + terminator;
+            }
+        }
+        lines.add(formatted);
+        return String.join("\n", lines);
+    }
+
     void printIfcheckPostamble(PrintStream out, boolean isBuffer, boolean emitExceptionCheck,
             String iii) {
         printIfcheckPostamble(out, isBuffer, emitExceptionCheck,
@@ -1538,14 +1566,19 @@
                                         "_exception ? JNI_ABORT : 0" : "0")) +
                                 ");");
                         } else {
-                            out.println(indent + indent +
+                            String bufferOffset = numBufferArgs <= 1 ? "_bufferOffset" :
+                                "_" + cfunc.getArgName(cIndex) + "BufferOffset";
+                            String typeCast = "(char *)" + cfunc.getArgName(cIndex);
+                            String withOffset = "(void *)(" + typeCast + " - " + bufferOffset + ")";
+                            String releasePointerCall = (
                                 "releasePointer(_env, " + array + ", " +
-                                cfunc.getArgName(cIndex) +
+                                withOffset +
                                 ", " +
                                 (cfunc.getArgType(cIndex).isConst() ?
                                     "JNI_FALSE" : (emitExceptionCheck ?
                                         "_exception ? JNI_FALSE : JNI_TRUE" : "JNI_TRUE")) +
                                 ");");
+                            out.println(formatFunctionCall(indent + indent, releasePointerCall));
                         }
                         out.println(indent + "}");
                     }
diff --git a/services/gpuservice/gpumem/GpuMem.cpp b/services/gpuservice/gpumem/GpuMem.cpp
index c78322e..3aa862f 100644
--- a/services/gpuservice/gpumem/GpuMem.cpp
+++ b/services/gpuservice/gpumem/GpuMem.cpp
@@ -43,18 +43,21 @@
     // Make sure bpf programs are loaded
     bpf::waitForProgsLoaded();
 
-    int fd = bpf::bpfFdGet(kGpuMemTotalProgPath, BPF_F_RDONLY);
+    errno = 0;
+    int fd = bpf::retrieveProgram(kGpuMemTotalProgPath);
     if (fd < 0) {
-        ALOGE("Failed to retrieve pinned program from %s", kGpuMemTotalProgPath);
+        ALOGE("Failed to retrieve pinned program from %s [%d(%s)]", kGpuMemTotalProgPath, errno,
+              strerror(errno));
         return;
     }
 
     // Attach the program to the tracepoint, and the tracepoint is automatically enabled here.
+    errno = 0;
     int count = 0;
     while (bpf_attach_tracepoint(fd, kGpuMemTraceGroup, kGpuMemTotalTracepoint) < 0) {
         if (++count > kGpuWaitTimeout) {
-            ALOGE("Failed to attach bpf program to %s/%s tracepoint", kGpuMemTraceGroup,
-                  kGpuMemTotalTracepoint);
+            ALOGE("Failed to attach bpf program to %s/%s tracepoint [%d(%s)]", kGpuMemTraceGroup,
+                  kGpuMemTotalTracepoint, errno, strerror(errno));
             return;
         }
         // Retry until GPU driver loaded or timeout.
@@ -62,9 +65,11 @@
     }
 
     // Use the read-only wrapper BpfMapRO to properly retrieve the read-only map.
+    errno = 0;
     auto map = bpf::BpfMapRO<uint64_t, uint64_t>(kGpuMemTotalMapPath);
     if (!map.isValid()) {
-        ALOGE("Failed to create bpf map from %s", kGpuMemTotalMapPath);
+        ALOGE("Failed to create bpf map from %s [%d(%s)]", kGpuMemTotalMapPath, errno,
+              strerror(errno));
         return;
     }
     setGpuMemTotalMap(map);
diff --git a/services/gpuservice/tests/unittests/Android.bp b/services/gpuservice/tests/unittests/Android.bp
index db81f5d..940a26b 100644
--- a/services/gpuservice/tests/unittests/Android.bp
+++ b/services/gpuservice/tests/unittests/Android.bp
@@ -38,4 +38,5 @@
     static_libs: [
         "libgmock",
     ],
+    require_root: true,
 }
diff --git a/services/gpuservice/tests/unittests/AndroidTest.xml b/services/gpuservice/tests/unittests/AndroidTest.xml
index 66f51c7..72976a8 100644
--- a/services/gpuservice/tests/unittests/AndroidTest.xml
+++ b/services/gpuservice/tests/unittests/AndroidTest.xml
@@ -18,6 +18,7 @@
         <option name="cleanup" value="true" />
         <option name="push" value="gpuservice_unittest->/data/local/tmp/gpuservice_unittest" />
     </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
     <option name="test-suite-tag" value="apct" />
     <test class="com.android.tradefed.testtype.GTest" >
         <option name="native-test-device-path" value="/data/local/tmp" />
diff --git a/services/inputflinger/TEST_MAPPING b/services/inputflinger/TEST_MAPPING
index 824c01e..33520b2 100644
--- a/services/inputflinger/TEST_MAPPING
+++ b/services/inputflinger/TEST_MAPPING
@@ -7,6 +7,18 @@
           "include-filter": "android.server.wm.WindowInputTests"
         }
       ]
+    },
+    {
+      "name": "libinput_tests"
+    },
+    {
+      "name": "inputflinger_tests"
+    },
+    {
+      "name": "InputTests"
+    },
+    {
+      "name": "libinputservice_test"
     }
   ]
 }
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 34fa239..29df00b 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -59,7 +59,6 @@
 
 EventEntry::EventEntry(int32_t id, Type type, nsecs_t eventTime, uint32_t policyFlags)
       : id(id),
-        refCount(1),
         type(type),
         eventTime(eventTime),
         policyFlags(policyFlags),
@@ -70,15 +69,6 @@
     releaseInjectionState();
 }
 
-void EventEntry::release() {
-    refCount -= 1;
-    if (refCount == 0) {
-        delete this;
-    } else {
-        ALOG_ASSERT(refCount > 0);
-    }
-}
-
 void EventEntry::releaseInjectionState() {
     if (injectionState) {
         injectionState->release();
@@ -151,11 +141,12 @@
     if (!GetBoolProperty("ro.debuggable", false)) {
         return "KeyEvent";
     }
-    return StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32 ", action=%s, "
+    return StringPrintf("KeyEvent(deviceId=%d, eventTime=%" PRIu64
+                        ", source=0x%08x, displayId=%" PRId32 ", action=%s, "
                         "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, "
                         "repeatCount=%d), policyFlags=0x%08x",
-                        deviceId, source, displayId, KeyEvent::actionToString(action), flags,
-                        keyCode, scanCode, metaState, repeatCount, policyFlags);
+                        deviceId, eventTime, source, displayId, KeyEvent::actionToString(action),
+                        flags, keyCode, scanCode, metaState, repeatCount, policyFlags);
 }
 
 void KeyEntry::recycle() {
@@ -210,15 +201,16 @@
         return "MotionEvent";
     }
     std::string msg;
-    msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32
+    msg += StringPrintf("MotionEvent(deviceId=%d, eventTime=%" PRIu64
+                        ", source=0x%08x, displayId=%" PRId32
                         ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, "
                         "buttonState=0x%08x, "
                         "classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, "
                         "xCursorPosition=%0.1f, yCursorPosition=%0.1f, pointers=[",
-                        deviceId, source, displayId, MotionEvent::actionToString(action),
-                        actionButton, flags, metaState, buttonState,
-                        motionClassificationToString(classification), edgeFlags, xPrecision,
-                        yPrecision, xCursorPosition, yCursorPosition);
+                        deviceId, eventTime, source, displayId,
+                        MotionEvent::actionToString(action).c_str(), actionButton, flags, metaState,
+                        buttonState, motionClassificationToString(classification), edgeFlags,
+                        xPrecision, yPrecision, xCursorPosition, yCursorPosition);
 
     for (uint32_t i = 0; i < pointerCount; i++) {
         if (i) {
@@ -235,22 +227,16 @@
 
 volatile int32_t DispatchEntry::sNextSeqAtomic;
 
-DispatchEntry::DispatchEntry(EventEntry* eventEntry, int32_t targetFlags, ui::Transform transform,
-                             float globalScaleFactor)
+DispatchEntry::DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
+                             ui::Transform transform, float globalScaleFactor)
       : seq(nextSeq()),
-        eventEntry(eventEntry),
+        eventEntry(std::move(eventEntry)),
         targetFlags(targetFlags),
         transform(transform),
         globalScaleFactor(globalScaleFactor),
         deliveryTime(0),
         resolvedAction(0),
-        resolvedFlags(0) {
-    eventEntry->refCount += 1;
-}
-
-DispatchEntry::~DispatchEntry() {
-    eventEntry->release();
-}
+        resolvedFlags(0) {}
 
 uint32_t DispatchEntry::nextSeq() {
     // Sequence number 0 is reserved and will never be returned.
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 47f75cbe..2b18180 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -54,7 +54,6 @@
     }
 
     int32_t id;
-    mutable int32_t refCount;
     Type type;
     nsecs_t eventTime;
     uint32_t policyFlags;
@@ -79,13 +78,12 @@
         return isInjected() || IdGenerator::getSource(id) != IdGenerator::Source::INPUT_READER;
     }
 
-    void release();
-
     virtual std::string getDescription() const = 0;
 
-protected:
     EventEntry(int32_t id, Type type, nsecs_t eventTime, uint32_t policyFlags);
     virtual ~EventEntry();
+
+protected:
     void releaseInjectionState();
 };
 
@@ -93,7 +91,6 @@
     explicit ConfigurationChangedEntry(int32_t id, nsecs_t eventTime);
     std::string getDescription() const override;
 
-protected:
     virtual ~ConfigurationChangedEntry();
 };
 
@@ -103,7 +100,6 @@
     DeviceResetEntry(int32_t id, nsecs_t eventTime, int32_t deviceId);
     std::string getDescription() const override;
 
-protected:
     virtual ~DeviceResetEntry();
 };
 
@@ -116,7 +112,6 @@
                std::string_view reason);
     std::string getDescription() const override;
 
-protected:
     virtual ~FocusEntry();
 };
 
@@ -149,7 +144,6 @@
     std::string getDescription() const override;
     void recycle();
 
-protected:
     virtual ~KeyEntry();
 };
 
@@ -182,7 +176,6 @@
                 float xOffset, float yOffset);
     std::string getDescription() const override;
 
-protected:
     virtual ~MotionEntry();
 };
 
@@ -190,7 +183,7 @@
 struct DispatchEntry {
     const uint32_t seq; // unique sequence number, never 0
 
-    EventEntry* eventEntry; // the event to dispatch
+    std::shared_ptr<EventEntry> eventEntry; // the event to dispatch
     int32_t targetFlags;
     ui::Transform transform;
     float globalScaleFactor;
@@ -205,9 +198,8 @@
     int32_t resolvedAction;
     int32_t resolvedFlags;
 
-    DispatchEntry(EventEntry* eventEntry, int32_t targetFlags, ui::Transform transform,
-                  float globalScaleFactor);
-    ~DispatchEntry();
+    DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
+                  ui::Transform transform, float globalScaleFactor);
 
     inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; }
 
@@ -252,7 +244,7 @@
     // parameters for the command (usage varies by command)
     sp<Connection> connection;
     nsecs_t eventTime;
-    KeyEntry* keyEntry;
+    std::shared_ptr<KeyEntry> keyEntry;
     std::shared_ptr<InputApplicationHandle> inputApplicationHandle;
     std::string reason;
     int32_t userActivityEventType;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index d7aea4e..3135c19 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -37,6 +37,10 @@
 // Log debug messages about input focus tracking.
 static constexpr bool DEBUG_FOCUS = false;
 
+// Log debug messages about touch occlusion
+// STOPSHIP(b/169067926): Set to false
+static constexpr bool DEBUG_TOUCH_OCCLUSION = true;
+
 // Log debug messages about the app switch latency optimization.
 #define DEBUG_APP_SWITCH 0
 
@@ -311,19 +315,19 @@
 }
 
 static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
-                                                          EventEntry* eventEntry,
+                                                          std::shared_ptr<EventEntry> eventEntry,
                                                           int32_t inputTargetFlags) {
     if (inputTarget.useDefaultPointerTransform()) {
         const ui::Transform& transform = inputTarget.getDefaultPointerTransform();
-        return std::make_unique<DispatchEntry>(eventEntry, // increments ref
-                                               inputTargetFlags, transform,
+        return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform,
                                                inputTarget.globalScaleFactor);
     }
 
     ALOG_ASSERT(eventEntry->type == EventEntry::Type::MOTION);
     const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
 
-    PointerCoords pointerCoords[motionEntry.pointerCount];
+    std::vector<PointerCoords> pointerCoords;
+    pointerCoords.resize(motionEntry.pointerCount);
 
     // Use the first pointer information to normalize all other pointers. This could be any pointer
     // as long as all other pointers are normalized to the same value and the final DispatchEntry
@@ -347,17 +351,18 @@
         pointerCoords[pointerIndex].transform(inverseFirstTransform);
     }
 
-    MotionEntry* combinedMotionEntry =
-            new MotionEntry(motionEntry.id, motionEntry.eventTime, motionEntry.deviceId,
-                            motionEntry.source, motionEntry.displayId, motionEntry.policyFlags,
-                            motionEntry.action, motionEntry.actionButton, motionEntry.flags,
-                            motionEntry.metaState, motionEntry.buttonState,
-                            motionEntry.classification, motionEntry.edgeFlags,
-                            motionEntry.xPrecision, motionEntry.yPrecision,
-                            motionEntry.xCursorPosition, motionEntry.yCursorPosition,
-                            motionEntry.downTime, motionEntry.pointerCount,
-                            motionEntry.pointerProperties, pointerCoords, 0 /* xOffset */,
-                            0 /* yOffset */);
+    std::unique_ptr<MotionEntry> combinedMotionEntry =
+            std::make_unique<MotionEntry>(motionEntry.id, motionEntry.eventTime,
+                                          motionEntry.deviceId, motionEntry.source,
+                                          motionEntry.displayId, motionEntry.policyFlags,
+                                          motionEntry.action, motionEntry.actionButton,
+                                          motionEntry.flags, motionEntry.metaState,
+                                          motionEntry.buttonState, motionEntry.classification,
+                                          motionEntry.edgeFlags, motionEntry.xPrecision,
+                                          motionEntry.yPrecision, motionEntry.xCursorPosition,
+                                          motionEntry.yCursorPosition, motionEntry.downTime,
+                                          motionEntry.pointerCount, motionEntry.pointerProperties,
+                                          pointerCoords.data(), 0 /* xOffset */, 0 /* yOffset */);
 
     if (motionEntry.injectionState) {
         combinedMotionEntry->injectionState = motionEntry.injectionState;
@@ -365,10 +370,8 @@
     }
 
     std::unique_ptr<DispatchEntry> dispatchEntry =
-            std::make_unique<DispatchEntry>(combinedMotionEntry, // increments ref
-                                            inputTargetFlags, firstPointerTransform,
-                                            inputTarget.globalScaleFactor);
-    combinedMotionEntry->release();
+            std::make_unique<DispatchEntry>(std::move(combinedMotionEntry), inputTargetFlags,
+                                            firstPointerTransform, inputTarget.globalScaleFactor);
     return dispatchEntry;
 }
 
@@ -557,9 +560,7 @@
             mNoFocusedWindowTimeoutTime = std::nullopt;
             return LONG_LONG_MIN;
         } else {
-            // Keep waiting
-            const nsecs_t millisRemaining = ns2ms(*mNoFocusedWindowTimeoutTime - currentTime);
-            ALOGW("Still no focused window. Will drop the event in %" PRId64 "ms", millisRemaining);
+            // Keep waiting. We will drop the event when mNoFocusedWindowTimeoutTime comes.
             nextAnrCheck = *mNoFocusedWindowTimeoutTime;
         }
     }
@@ -673,22 +674,24 @@
 
     switch (mPendingEvent->type) {
         case EventEntry::Type::CONFIGURATION_CHANGED: {
-            ConfigurationChangedEntry* typedEntry =
-                    static_cast<ConfigurationChangedEntry*>(mPendingEvent);
+            const ConfigurationChangedEntry& typedEntry =
+                    static_cast<const ConfigurationChangedEntry&>(*mPendingEvent);
             done = dispatchConfigurationChangedLocked(currentTime, typedEntry);
             dropReason = DropReason::NOT_DROPPED; // configuration changes are never dropped
             break;
         }
 
         case EventEntry::Type::DEVICE_RESET: {
-            DeviceResetEntry* typedEntry = static_cast<DeviceResetEntry*>(mPendingEvent);
+            const DeviceResetEntry& typedEntry =
+                    static_cast<const DeviceResetEntry&>(*mPendingEvent);
             done = dispatchDeviceResetLocked(currentTime, typedEntry);
             dropReason = DropReason::NOT_DROPPED; // device resets are never dropped
             break;
         }
 
         case EventEntry::Type::FOCUS: {
-            FocusEntry* typedEntry = static_cast<FocusEntry*>(mPendingEvent);
+            std::shared_ptr<FocusEntry> typedEntry =
+                    std::static_pointer_cast<FocusEntry>(mPendingEvent);
             dispatchFocusLocked(currentTime, typedEntry);
             done = true;
             dropReason = DropReason::NOT_DROPPED; // focus events are never dropped
@@ -696,37 +699,38 @@
         }
 
         case EventEntry::Type::KEY: {
-            KeyEntry* typedEntry = static_cast<KeyEntry*>(mPendingEvent);
+            std::shared_ptr<KeyEntry> keyEntry = std::static_pointer_cast<KeyEntry>(mPendingEvent);
             if (isAppSwitchDue) {
-                if (isAppSwitchKeyEvent(*typedEntry)) {
+                if (isAppSwitchKeyEvent(*keyEntry)) {
                     resetPendingAppSwitchLocked(true);
                     isAppSwitchDue = false;
                 } else if (dropReason == DropReason::NOT_DROPPED) {
                     dropReason = DropReason::APP_SWITCH;
                 }
             }
-            if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
+            if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *keyEntry)) {
                 dropReason = DropReason::STALE;
             }
             if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
                 dropReason = DropReason::BLOCKED;
             }
-            done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
+            done = dispatchKeyLocked(currentTime, keyEntry, &dropReason, nextWakeupTime);
             break;
         }
 
         case EventEntry::Type::MOTION: {
-            MotionEntry* typedEntry = static_cast<MotionEntry*>(mPendingEvent);
+            std::shared_ptr<MotionEntry> motionEntry =
+                    std::static_pointer_cast<MotionEntry>(mPendingEvent);
             if (dropReason == DropReason::NOT_DROPPED && isAppSwitchDue) {
                 dropReason = DropReason::APP_SWITCH;
             }
-            if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *typedEntry)) {
+            if (dropReason == DropReason::NOT_DROPPED && isStaleEvent(currentTime, *motionEntry)) {
                 dropReason = DropReason::STALE;
             }
             if (dropReason == DropReason::NOT_DROPPED && mNextUnblockedEvent) {
                 dropReason = DropReason::BLOCKED;
             }
-            done = dispatchMotionLocked(currentTime, typedEntry, &dropReason, nextWakeupTime);
+            done = dispatchMotionLocked(currentTime, motionEntry, &dropReason, nextWakeupTime);
             break;
         }
     }
@@ -802,17 +806,18 @@
     return false;
 }
 
-bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
+bool InputDispatcher::enqueueInboundEventLocked(std::unique_ptr<EventEntry> newEntry) {
     bool needWake = mInboundQueue.empty();
-    mInboundQueue.push_back(entry);
+    mInboundQueue.push_back(std::move(newEntry));
+    EventEntry& entry = *(mInboundQueue.back());
     traceInboundQueueLengthLocked();
 
-    switch (entry->type) {
+    switch (entry.type) {
         case EventEntry::Type::KEY: {
             // Optimize app switch latency.
             // If the application takes too long to catch up then we drop all events preceding
             // the app switch key.
-            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*entry);
+            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(entry);
             if (isAppSwitchKeyEvent(keyEntry)) {
                 if (keyEntry.action == AKEY_EVENT_ACTION_DOWN) {
                     mAppSwitchSawKeyDown = true;
@@ -831,8 +836,8 @@
         }
 
         case EventEntry::Type::MOTION: {
-            if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(*entry))) {
-                mNextUnblockedEvent = entry;
+            if (shouldPruneInboundQueueLocked(static_cast<MotionEntry&>(entry))) {
+                mNextUnblockedEvent = mInboundQueue.back();
                 needWake = true;
             }
             break;
@@ -851,11 +856,9 @@
     return needWake;
 }
 
-void InputDispatcher::addRecentEventLocked(EventEntry* entry) {
-    entry->refCount += 1;
+void InputDispatcher::addRecentEventLocked(std::shared_ptr<EventEntry> entry) {
     mRecentQueue.push_back(entry);
     if (mRecentQueue.size() > RECENT_QUEUE_MAX_SIZE) {
-        mRecentQueue.front()->release();
         mRecentQueue.pop_front();
     }
 }
@@ -1035,7 +1038,7 @@
 
 void InputDispatcher::drainInboundQueueLocked() {
     while (!mInboundQueue.empty()) {
-        EventEntry* entry = mInboundQueue.front();
+        std::shared_ptr<EventEntry> entry = mInboundQueue.front();
         mInboundQueue.pop_front();
         releaseInboundEventLocked(entry);
     }
@@ -1049,66 +1052,48 @@
     }
 }
 
-void InputDispatcher::releaseInboundEventLocked(EventEntry* entry) {
+void InputDispatcher::releaseInboundEventLocked(std::shared_ptr<EventEntry> entry) {
     InjectionState* injectionState = entry->injectionState;
     if (injectionState && injectionState->injectionResult == InputEventInjectionResult::PENDING) {
 #if DEBUG_DISPATCH_CYCLE
         ALOGD("Injected inbound event was dropped.");
 #endif
-        setInjectionResult(entry, InputEventInjectionResult::FAILED);
+        setInjectionResult(*entry, InputEventInjectionResult::FAILED);
     }
     if (entry == mNextUnblockedEvent) {
         mNextUnblockedEvent = nullptr;
     }
     addRecentEventLocked(entry);
-    entry->release();
 }
 
 void InputDispatcher::resetKeyRepeatLocked() {
     if (mKeyRepeatState.lastKeyEntry) {
-        mKeyRepeatState.lastKeyEntry->release();
         mKeyRepeatState.lastKeyEntry = nullptr;
     }
 }
 
-KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) {
-    KeyEntry* entry = mKeyRepeatState.lastKeyEntry;
+std::shared_ptr<KeyEntry> InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) {
+    std::shared_ptr<KeyEntry> entry = mKeyRepeatState.lastKeyEntry;
 
-    // Reuse the repeated key entry if it is otherwise unreferenced.
     uint32_t policyFlags = entry->policyFlags &
             (POLICY_FLAG_RAW_MASK | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED);
-    if (entry->refCount == 1) {
-        entry->recycle();
-        entry->id = mIdGenerator.nextId();
-        entry->eventTime = currentTime;
-        entry->policyFlags = policyFlags;
-        entry->repeatCount += 1;
-    } else {
-        KeyEntry* newEntry =
-                new KeyEntry(mIdGenerator.nextId(), currentTime, entry->deviceId, entry->source,
-                             entry->displayId, policyFlags, entry->action, entry->flags,
-                             entry->keyCode, entry->scanCode, entry->metaState,
-                             entry->repeatCount + 1, entry->downTime);
 
-        mKeyRepeatState.lastKeyEntry = newEntry;
-        entry->release();
+    std::shared_ptr<KeyEntry> newEntry =
+            std::make_unique<KeyEntry>(mIdGenerator.nextId(), currentTime, entry->deviceId,
+                                       entry->source, entry->displayId, policyFlags, entry->action,
+                                       entry->flags, entry->keyCode, entry->scanCode,
+                                       entry->metaState, entry->repeatCount + 1, entry->downTime);
 
-        entry = newEntry;
-    }
-    entry->syntheticRepeat = true;
-
-    // Increment reference count since we keep a reference to the event in
-    // mKeyRepeatState.lastKeyEntry in addition to the one we return.
-    entry->refCount += 1;
-
+    newEntry->syntheticRepeat = true;
+    mKeyRepeatState.lastKeyEntry = newEntry;
     mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay;
-    return entry;
+    return newEntry;
 }
 
 bool InputDispatcher::dispatchConfigurationChangedLocked(nsecs_t currentTime,
-                                                         ConfigurationChangedEntry* entry) {
+                                                         const ConfigurationChangedEntry& entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry->eventTime);
+    ALOGD("dispatchConfigurationChanged - eventTime=%" PRId64, entry.eventTime);
 #endif
 
     // Reset key repeating in case a keyboard device was added or removed or something.
@@ -1117,19 +1102,20 @@
     // Enqueue a command to run outside the lock to tell the policy that the configuration changed.
     std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
             &InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
-    commandEntry->eventTime = entry->eventTime;
+    commandEntry->eventTime = entry.eventTime;
     postCommandLocked(std::move(commandEntry));
     return true;
 }
 
-bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime, DeviceResetEntry* entry) {
+bool InputDispatcher::dispatchDeviceResetLocked(nsecs_t currentTime,
+                                                const DeviceResetEntry& entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry->eventTime,
-          entry->deviceId);
+    ALOGD("dispatchDeviceReset - eventTime=%" PRId64 ", deviceId=%d", entry.eventTime,
+          entry.deviceId);
 #endif
 
     CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, "device was reset");
-    options.deviceId = entry->deviceId;
+    options.deviceId = entry.deviceId;
     synthesizeCancelationEventsForAllConnectionsLocked(options);
     return true;
 }
@@ -1143,20 +1129,23 @@
         mPendingEvent = nullptr;
     }
 
-    FocusEntry* focusEntry =
-            new FocusEntry(mIdGenerator.nextId(), now(), windowToken, hasFocus, reason);
+    std::unique_ptr<FocusEntry> focusEntry =
+            std::make_unique<FocusEntry>(mIdGenerator.nextId(), now(), windowToken, hasFocus,
+                                         reason);
 
     // This event should go to the front of the queue, but behind all other focus events
     // Find the last focus event, and insert right after it
-    std::deque<EventEntry*>::reverse_iterator it =
+    std::deque<std::shared_ptr<EventEntry>>::reverse_iterator it =
             std::find_if(mInboundQueue.rbegin(), mInboundQueue.rend(),
-                         [](EventEntry* event) { return event->type == EventEntry::Type::FOCUS; });
+                         [](const std::shared_ptr<EventEntry>& event) {
+                             return event->type == EventEntry::Type::FOCUS;
+                         });
 
     // Maintain the order of focus events. Insert the entry after all other focus events.
-    mInboundQueue.insert(it.base(), focusEntry);
+    mInboundQueue.insert(it.base(), std::move(focusEntry));
 }
 
-void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime, FocusEntry* entry) {
+void InputDispatcher::dispatchFocusLocked(nsecs_t currentTime, std::shared_ptr<FocusEntry> entry) {
     std::shared_ptr<InputChannel> channel = getInputChannelLocked(entry->connectionToken);
     if (channel == nullptr) {
         return; // Window has gone away
@@ -1172,7 +1161,7 @@
     dispatchEventLocked(currentTime, entry, {target});
 }
 
-bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry,
+bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry,
                                         DropReason* dropReason, nsecs_t* nextWakeupTime) {
     // Preprocessing.
     if (!entry->dispatchInProgress) {
@@ -1200,10 +1189,9 @@
                 mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout;
             }
             mKeyRepeatState.lastKeyEntry = entry;
-            entry->refCount += 1;
         } else if (entry->action == AKEY_EVENT_ACTION_UP && mKeyRepeatState.lastKeyEntry &&
                    mKeyRepeatState.lastKeyEntry->deviceId != entry->deviceId) {
-            // The stale device releases the key, reset staleDeviceId.
+            // The key on device 'deviceId' is still down, do not stop key repeat
 #if DEBUG_INBOUND_EVENT_DETAILS
             ALOGD("deviceId=%d got KEY_UP as stale", entry->deviceId);
 #endif
@@ -1246,7 +1234,6 @@
             }
             commandEntry->keyEntry = entry;
             postCommandLocked(std::move(commandEntry));
-            entry->refCount += 1;
             return false; // wait for the command to run
         } else {
             entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
@@ -1259,7 +1246,7 @@
 
     // Clean up if dropping the event.
     if (*dropReason != DropReason::NOT_DROPPED) {
-        setInjectionResult(entry,
+        setInjectionResult(*entry,
                            *dropReason == DropReason::POLICY ? InputEventInjectionResult::SUCCEEDED
                                                              : InputEventInjectionResult::FAILED);
         mReporter->reportDroppedKey(entry->id);
@@ -1274,7 +1261,7 @@
         return false;
     }
 
-    setInjectionResult(entry, injectionResult);
+    setInjectionResult(*entry, injectionResult);
     if (injectionResult != InputEventInjectionResult::SUCCEEDED) {
         return true;
     }
@@ -1298,7 +1285,7 @@
 #endif
 }
 
-bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry,
+bool InputDispatcher::dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr<MotionEntry> entry,
                                            DropReason* dropReason, nsecs_t* nextWakeupTime) {
     ATRACE_CALL();
     // Preprocessing.
@@ -1310,7 +1297,7 @@
 
     // Clean up if dropping the event.
     if (*dropReason != DropReason::NOT_DROPPED) {
-        setInjectionResult(entry,
+        setInjectionResult(*entry,
                            *dropReason == DropReason::POLICY ? InputEventInjectionResult::SUCCEEDED
                                                              : InputEventInjectionResult::FAILED);
         return true;
@@ -1337,7 +1324,7 @@
         return false;
     }
 
-    setInjectionResult(entry, injectionResult);
+    setInjectionResult(*entry, injectionResult);
     if (injectionResult == InputEventInjectionResult::PERMISSION_DENIED) {
         ALOGW("Permission denied, dropping the motion (isPointer=%s)", toString(isPointerEvent));
         return true;
@@ -1411,7 +1398,8 @@
 #endif
 }
 
-void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, EventEntry* eventEntry,
+void InputDispatcher::dispatchEventLocked(nsecs_t currentTime,
+                                          std::shared_ptr<EventEntry> eventEntry,
                                           const std::vector<InputTarget>& inputTargets) {
     ATRACE_CALL();
 #if DEBUG_DISPATCH_CYCLE
@@ -1774,6 +1762,12 @@
             TouchOcclusionInfo occlusionInfo =
                     computeTouchOcclusionInfoLocked(newTouchedWindowHandle, x, y);
             if (!isTouchTrustedLocked(occlusionInfo)) {
+                if (DEBUG_TOUCH_OCCLUSION) {
+                    ALOGD("Stack of obscuring windows during untrusted touch (%d, %d):", x, y);
+                    for (const auto& log : occlusionInfo.debugInfo) {
+                        ALOGD("%s", log.c_str());
+                    }
+                }
                 onUntrustedTouchLocked(occlusionInfo.obscuringPackage);
                 if (mBlockUntrustedTouchesMode == BlockUntrustedTouchesMode::BLOCK) {
                     ALOGW("Dropping untrusted touch event due to %s/%d",
@@ -2184,6 +2178,15 @@
     auto otherInfo = otherHandle->getInfo();
     if (!otherInfo->visible) {
         return false;
+    } else if (otherInfo->alpha == 0 &&
+               otherInfo->flags.test(InputWindowInfo::Flag::NOT_TOUCHABLE)) {
+        // Those act as if they were invisible, so we don't need to flag them.
+        // We do want to potentially flag touchable windows even if they have 0
+        // opacity, since they can consume touches and alter the effects of the
+        // user interaction (eg. apps that rely on
+        // FLAG_WINDOW_IS_PARTIALLY_OBSCURED should still be told about those
+        // windows), hence we also check for FLAG_NOT_TOUCHABLE.
+        return false;
     } else if (info->ownerUid == otherInfo->ownerUid) {
         // If ownerUid is the same we don't generate occlusion events as there
         // is no security boundary within an uid.
@@ -2215,7 +2218,8 @@
  */
 InputDispatcher::TouchOcclusionInfo InputDispatcher::computeTouchOcclusionInfoLocked(
         const sp<InputWindowHandle>& windowHandle, int32_t x, int32_t y) const {
-    int32_t displayId = windowHandle->getInfo()->displayId;
+    const InputWindowInfo* windowInfo = windowHandle->getInfo();
+    int32_t displayId = windowInfo->displayId;
     const std::vector<sp<InputWindowHandle>>& windowHandles = getWindowHandlesLocked(displayId);
     TouchOcclusionInfo info;
     info.hasBlockingOcclusion = false;
@@ -2228,8 +2232,11 @@
         }
         const InputWindowInfo* otherInfo = otherHandle->getInfo();
         if (canBeObscuredBy(windowHandle, otherHandle) &&
-            windowHandle->getInfo()->ownerUid != otherInfo->ownerUid &&
-            otherInfo->frameContainsPoint(x, y)) {
+            windowInfo->ownerUid != otherInfo->ownerUid && otherInfo->frameContainsPoint(x, y)) {
+            if (DEBUG_TOUCH_OCCLUSION) {
+                info.debugInfo.push_back(
+                        dumpWindowForTouchOcclusion(otherInfo, /* isTouchedWindow */ false));
+            }
             // canBeObscuredBy() has returned true above, which means this window is untrusted, so
             // we perform the checks below to see if the touch can be propagated or not based on the
             // window's touch occlusion mode
@@ -2255,9 +2262,26 @@
             }
         }
     }
+    if (DEBUG_TOUCH_OCCLUSION) {
+        info.debugInfo.push_back(
+                dumpWindowForTouchOcclusion(windowInfo, /* isTouchedWindow */ true));
+    }
     return info;
 }
 
+std::string InputDispatcher::dumpWindowForTouchOcclusion(const InputWindowInfo* info,
+                                                         bool isTouchedWindow) const {
+    return StringPrintf(INDENT2 "* %stype=%s, package=%s/%" PRId32 ", mode=%s, alpha=%.2f, "
+                                "frame=[%" PRId32 ",%" PRId32 "][%" PRId32 ",%" PRId32
+                                "], window=%s, applicationInfo=%s, flags=%s\n",
+                        (isTouchedWindow) ? "[TOUCHED] " : "",
+                        NamedEnum::string(info->type).c_str(), info->packageName.c_str(),
+                        info->ownerUid, toString(info->touchOcclusionMode).c_str(), info->alpha,
+                        info->frameLeft, info->frameTop, info->frameRight, info->frameBottom,
+                        info->name.c_str(), info->applicationInfo.name.c_str(),
+                        info->flags.string().c_str());
+}
+
 bool InputDispatcher::isTouchTrustedLocked(const TouchOcclusionInfo& occlusionInfo) const {
     if (occlusionInfo.hasBlockingOcclusion) {
         ALOGW("Untrusted touch due to occlusion by %s/%d", occlusionInfo.obscuringPackage.c_str(),
@@ -2380,7 +2404,7 @@
 
 void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
                                                  const sp<Connection>& connection,
-                                                 EventEntry* eventEntry,
+                                                 std::shared_ptr<EventEntry> eventEntry,
                                                  const InputTarget& inputTarget) {
     if (ATRACE_ENABLED()) {
         std::string message =
@@ -2414,7 +2438,7 @@
 
         const MotionEntry& originalMotionEntry = static_cast<const MotionEntry&>(*eventEntry);
         if (inputTarget.pointerIds.count() != originalMotionEntry.pointerCount) {
-            MotionEntry* splitMotionEntry =
+            std::unique_ptr<MotionEntry> splitMotionEntry =
                     splitMotionEvent(originalMotionEntry, inputTarget.pointerIds);
             if (!splitMotionEntry) {
                 return; // split event was dropped
@@ -2424,8 +2448,8 @@
                       connection->getInputChannelName().c_str());
                 logOutboundMotionDetails("  ", *splitMotionEntry);
             }
-            enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget);
-            splitMotionEntry->release();
+            enqueueDispatchEntriesLocked(currentTime, connection, std::move(splitMotionEntry),
+                                         inputTarget);
             return;
         }
     }
@@ -2436,7 +2460,7 @@
 
 void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime,
                                                    const sp<Connection>& connection,
-                                                   EventEntry* eventEntry,
+                                                   std::shared_ptr<EventEntry> eventEntry,
                                                    const InputTarget& inputTarget) {
     if (ATRACE_ENABLED()) {
         std::string message =
@@ -2468,7 +2492,7 @@
 }
 
 void InputDispatcher::enqueueDispatchEntryLocked(const sp<Connection>& connection,
-                                                 EventEntry* eventEntry,
+                                                 std::shared_ptr<EventEntry> eventEntry,
                                                  const InputTarget& inputTarget,
                                                  int32_t dispatchMode) {
     if (ATRACE_ENABLED()) {
@@ -2490,11 +2514,11 @@
 
     // Use the eventEntry from dispatchEntry since the entry may have changed and can now be a
     // different EventEntry than what was passed in.
-    EventEntry* newEntry = dispatchEntry->eventEntry;
+    EventEntry& newEntry = *(dispatchEntry->eventEntry);
     // Apply target flags and update the connection's input state.
-    switch (newEntry->type) {
+    switch (newEntry.type) {
         case EventEntry::Type::KEY: {
-            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*newEntry);
+            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(newEntry);
             dispatchEntry->resolvedEventId = keyEntry.id;
             dispatchEntry->resolvedAction = keyEntry.action;
             dispatchEntry->resolvedFlags = keyEntry.flags;
@@ -2511,7 +2535,7 @@
         }
 
         case EventEntry::Type::MOTION: {
-            const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*newEntry);
+            const MotionEntry& motionEntry = static_cast<const MotionEntry&>(newEntry);
             // Assign a default value to dispatchEntry that will never be generated by InputReader,
             // and assign a InputDispatcher value if it doesn't change in the if-else chain below.
             constexpr int32_t DEFAULT_RESOLVED_EVENT_ID =
@@ -2582,7 +2606,7 @@
         case EventEntry::Type::CONFIGURATION_CHANGED:
         case EventEntry::Type::DEVICE_RESET: {
             LOG_ALWAYS_FATAL("%s events should not go to apps",
-                             EventEntry::typeToString(newEntry->type));
+                             EventEntry::typeToString(newEntry.type));
             break;
         }
     }
@@ -2706,39 +2730,38 @@
 
         // Publish the event.
         status_t status;
-        EventEntry* eventEntry = dispatchEntry->eventEntry;
-        switch (eventEntry->type) {
+        const EventEntry& eventEntry = *(dispatchEntry->eventEntry);
+        switch (eventEntry.type) {
             case EventEntry::Type::KEY: {
-                const KeyEntry* keyEntry = static_cast<KeyEntry*>(eventEntry);
-                std::array<uint8_t, 32> hmac = getSignature(*keyEntry, *dispatchEntry);
+                const KeyEntry& keyEntry = static_cast<const KeyEntry&>(eventEntry);
+                std::array<uint8_t, 32> hmac = getSignature(keyEntry, *dispatchEntry);
 
                 // Publish the key event.
-                status =
-                        connection->inputPublisher
-                                .publishKeyEvent(dispatchEntry->seq, dispatchEntry->resolvedEventId,
-                                                 keyEntry->deviceId, keyEntry->source,
-                                                 keyEntry->displayId, std::move(hmac),
-                                                 dispatchEntry->resolvedAction,
-                                                 dispatchEntry->resolvedFlags, keyEntry->keyCode,
-                                                 keyEntry->scanCode, keyEntry->metaState,
-                                                 keyEntry->repeatCount, keyEntry->downTime,
-                                                 keyEntry->eventTime);
+                status = connection->inputPublisher
+                                 .publishKeyEvent(dispatchEntry->seq,
+                                                  dispatchEntry->resolvedEventId, keyEntry.deviceId,
+                                                  keyEntry.source, keyEntry.displayId,
+                                                  std::move(hmac), dispatchEntry->resolvedAction,
+                                                  dispatchEntry->resolvedFlags, keyEntry.keyCode,
+                                                  keyEntry.scanCode, keyEntry.metaState,
+                                                  keyEntry.repeatCount, keyEntry.downTime,
+                                                  keyEntry.eventTime);
                 break;
             }
 
             case EventEntry::Type::MOTION: {
-                MotionEntry* motionEntry = static_cast<MotionEntry*>(eventEntry);
+                const MotionEntry& motionEntry = static_cast<const MotionEntry&>(eventEntry);
 
                 PointerCoords scaledCoords[MAX_POINTERS];
-                const PointerCoords* usingCoords = motionEntry->pointerCoords;
+                const PointerCoords* usingCoords = motionEntry.pointerCoords;
 
                 // Set the X and Y offset and X and Y scale depending on the input source.
-                if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) &&
+                if ((motionEntry.source & AINPUT_SOURCE_CLASS_POINTER) &&
                     !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) {
                     float globalScaleFactor = dispatchEntry->globalScaleFactor;
                     if (globalScaleFactor != 1.0f) {
-                        for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
-                            scaledCoords[i] = motionEntry->pointerCoords[i];
+                        for (uint32_t i = 0; i < motionEntry.pointerCount; i++) {
+                            scaledCoords[i] = motionEntry.pointerCoords[i];
                             // Don't apply window scale here since we don't want scale to affect raw
                             // coordinates. The scale will be sent back to the client and applied
                             // later when requesting relative coordinates.
@@ -2750,43 +2773,42 @@
                 } else {
                     // We don't want the dispatch target to know.
                     if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) {
-                        for (uint32_t i = 0; i < motionEntry->pointerCount; i++) {
+                        for (uint32_t i = 0; i < motionEntry.pointerCount; i++) {
                             scaledCoords[i].clear();
                         }
                         usingCoords = scaledCoords;
                     }
                 }
 
-                std::array<uint8_t, 32> hmac = getSignature(*motionEntry, *dispatchEntry);
+                std::array<uint8_t, 32> hmac = getSignature(motionEntry, *dispatchEntry);
 
                 // Publish the motion event.
                 status = connection->inputPublisher
                                  .publishMotionEvent(dispatchEntry->seq,
                                                      dispatchEntry->resolvedEventId,
-                                                     motionEntry->deviceId, motionEntry->source,
-                                                     motionEntry->displayId, std::move(hmac),
+                                                     motionEntry.deviceId, motionEntry.source,
+                                                     motionEntry.displayId, std::move(hmac),
                                                      dispatchEntry->resolvedAction,
-                                                     motionEntry->actionButton,
+                                                     motionEntry.actionButton,
                                                      dispatchEntry->resolvedFlags,
-                                                     motionEntry->edgeFlags, motionEntry->metaState,
-                                                     motionEntry->buttonState,
-                                                     motionEntry->classification,
+                                                     motionEntry.edgeFlags, motionEntry.metaState,
+                                                     motionEntry.buttonState,
+                                                     motionEntry.classification,
                                                      dispatchEntry->transform,
-                                                     motionEntry->xPrecision,
-                                                     motionEntry->yPrecision,
-                                                     motionEntry->xCursorPosition,
-                                                     motionEntry->yCursorPosition,
-                                                     motionEntry->downTime, motionEntry->eventTime,
-                                                     motionEntry->pointerCount,
-                                                     motionEntry->pointerProperties, usingCoords);
-                reportTouchEventForStatistics(*motionEntry);
+                                                     motionEntry.xPrecision, motionEntry.yPrecision,
+                                                     motionEntry.xCursorPosition,
+                                                     motionEntry.yCursorPosition,
+                                                     motionEntry.downTime, motionEntry.eventTime,
+                                                     motionEntry.pointerCount,
+                                                     motionEntry.pointerProperties, usingCoords);
+                reportTouchEventForStatistics(motionEntry);
                 break;
             }
             case EventEntry::Type::FOCUS: {
-                FocusEntry* focusEntry = static_cast<FocusEntry*>(eventEntry);
+                const FocusEntry& focusEntry = static_cast<const FocusEntry&>(eventEntry);
                 status = connection->inputPublisher.publishFocusEvent(dispatchEntry->seq,
-                                                                      focusEntry->id,
-                                                                      focusEntry->hasFocus,
+                                                                      focusEntry.id,
+                                                                      focusEntry.hasFocus,
                                                                       mInTouchMode);
                 break;
             }
@@ -2794,7 +2816,7 @@
             case EventEntry::Type::CONFIGURATION_CHANGED:
             case EventEntry::Type::DEVICE_RESET: {
                 LOG_ALWAYS_FATAL("Should never start dispatch cycles for %s events",
-                                 EventEntry::typeToString(eventEntry->type));
+                                 EventEntry::typeToString(eventEntry.type));
                 return;
             }
         }
@@ -2932,7 +2954,7 @@
 
 void InputDispatcher::releaseDispatchEntry(DispatchEntry* dispatchEntry) {
     if (dispatchEntry->hasForegroundTarget()) {
-        decrementPendingForegroundDispatches(dispatchEntry->eventEntry);
+        decrementPendingForegroundDispatches(*(dispatchEntry->eventEntry));
     }
     delete dispatchEntry;
 }
@@ -3048,7 +3070,7 @@
 
     nsecs_t currentTime = now();
 
-    std::vector<EventEntry*> cancelationEvents =
+    std::vector<std::unique_ptr<EventEntry>> cancelationEvents =
             connection->inputState.synthesizeCancelationEvents(currentTime, options);
 
     if (cancelationEvents.empty()) {
@@ -3073,7 +3095,7 @@
     target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
 
     for (size_t i = 0; i < cancelationEvents.size(); i++) {
-        EventEntry* cancelationEventEntry = cancelationEvents[i];
+        std::unique_ptr<EventEntry> cancelationEventEntry = std::move(cancelationEvents[i]);
         switch (cancelationEventEntry->type) {
             case EventEntry::Type::KEY: {
                 logOutboundKeyDetails("cancel - ",
@@ -3097,10 +3119,8 @@
             }
         }
 
-        enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
-                                   target, InputTarget::FLAG_DISPATCH_AS_IS);
-
-        cancelationEventEntry->release();
+        enqueueDispatchEntryLocked(connection, std::move(cancelationEventEntry), target,
+                                   InputTarget::FLAG_DISPATCH_AS_IS);
     }
 
     startDispatchCycleLocked(currentTime, connection);
@@ -3114,7 +3134,7 @@
 
     nsecs_t currentTime = now();
 
-    std::vector<EventEntry*> downEvents =
+    std::vector<std::unique_ptr<EventEntry>> downEvents =
             connection->inputState.synthesizePointerDownEvents(currentTime);
 
     if (downEvents.empty()) {
@@ -3137,7 +3157,7 @@
     target.inputChannel = connection->inputChannel;
     target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
 
-    for (EventEntry* downEventEntry : downEvents) {
+    for (std::unique_ptr<EventEntry>& downEventEntry : downEvents) {
         switch (downEventEntry->type) {
             case EventEntry::Type::MOTION: {
                 logOutboundMotionDetails("down - ",
@@ -3155,17 +3175,15 @@
             }
         }
 
-        enqueueDispatchEntryLocked(connection, downEventEntry, // increments ref
-                                   target, InputTarget::FLAG_DISPATCH_AS_IS);
-
-        downEventEntry->release();
+        enqueueDispatchEntryLocked(connection, std::move(downEventEntry), target,
+                                   InputTarget::FLAG_DISPATCH_AS_IS);
     }
 
     startDispatchCycleLocked(currentTime, connection);
 }
 
-MotionEntry* InputDispatcher::splitMotionEvent(const MotionEntry& originalMotionEntry,
-                                               BitSet32 pointerIds) {
+std::unique_ptr<MotionEntry> InputDispatcher::splitMotionEvent(
+        const MotionEntry& originalMotionEntry, BitSet32 pointerIds) {
     ALOG_ASSERT(pointerIds.value != 0);
 
     uint32_t splitPointerIndexMap[MAX_POINTERS];
@@ -3238,17 +3256,22 @@
                                            originalMotionEntry.id, newId);
         ATRACE_NAME(message.c_str());
     }
-    MotionEntry* splitMotionEntry =
-            new MotionEntry(newId, originalMotionEntry.eventTime, originalMotionEntry.deviceId,
-                            originalMotionEntry.source, originalMotionEntry.displayId,
-                            originalMotionEntry.policyFlags, action,
-                            originalMotionEntry.actionButton, originalMotionEntry.flags,
-                            originalMotionEntry.metaState, originalMotionEntry.buttonState,
-                            originalMotionEntry.classification, originalMotionEntry.edgeFlags,
-                            originalMotionEntry.xPrecision, originalMotionEntry.yPrecision,
-                            originalMotionEntry.xCursorPosition,
-                            originalMotionEntry.yCursorPosition, originalMotionEntry.downTime,
-                            splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0);
+    std::unique_ptr<MotionEntry> splitMotionEntry =
+            std::make_unique<MotionEntry>(newId, originalMotionEntry.eventTime,
+                                          originalMotionEntry.deviceId, originalMotionEntry.source,
+                                          originalMotionEntry.displayId,
+                                          originalMotionEntry.policyFlags, action,
+                                          originalMotionEntry.actionButton,
+                                          originalMotionEntry.flags, originalMotionEntry.metaState,
+                                          originalMotionEntry.buttonState,
+                                          originalMotionEntry.classification,
+                                          originalMotionEntry.edgeFlags,
+                                          originalMotionEntry.xPrecision,
+                                          originalMotionEntry.yPrecision,
+                                          originalMotionEntry.xCursorPosition,
+                                          originalMotionEntry.yCursorPosition,
+                                          originalMotionEntry.downTime, splitPointerCount,
+                                          splitPointerProperties, splitPointerCoords, 0, 0);
 
     if (originalMotionEntry.injectionState) {
         splitMotionEntry->injectionState = originalMotionEntry.injectionState;
@@ -3267,9 +3290,9 @@
     { // acquire lock
         std::scoped_lock _l(mLock);
 
-        ConfigurationChangedEntry* newEntry =
-                new ConfigurationChangedEntry(args->id, args->eventTime);
-        needWake = enqueueInboundEventLocked(newEntry);
+        std::unique_ptr<ConfigurationChangedEntry> newEntry =
+                std::make_unique<ConfigurationChangedEntry>(args->id, args->eventTime);
+        needWake = enqueueInboundEventLocked(std::move(newEntry));
     } // release lock
 
     if (needWake) {
@@ -3373,12 +3396,13 @@
             mLock.lock();
         }
 
-        KeyEntry* newEntry =
-                new KeyEntry(args->id, args->eventTime, args->deviceId, args->source,
-                             args->displayId, policyFlags, args->action, flags, keyCode,
-                             args->scanCode, metaState, repeatCount, args->downTime);
+        std::unique_ptr<KeyEntry> newEntry =
+                std::make_unique<KeyEntry>(args->id, args->eventTime, args->deviceId, args->source,
+                                           args->displayId, policyFlags, args->action, flags,
+                                           keyCode, args->scanCode, metaState, repeatCount,
+                                           args->downTime);
 
-        needWake = enqueueInboundEventLocked(newEntry);
+        needWake = enqueueInboundEventLocked(std::move(newEntry));
         mLock.unlock();
     } // release lock
 
@@ -3459,16 +3483,18 @@
         }
 
         // Just enqueue a new motion event.
-        MotionEntry* newEntry =
-                new MotionEntry(args->id, args->eventTime, args->deviceId, args->source,
-                                args->displayId, policyFlags, args->action, args->actionButton,
-                                args->flags, args->metaState, args->buttonState,
-                                args->classification, args->edgeFlags, args->xPrecision,
-                                args->yPrecision, args->xCursorPosition, args->yCursorPosition,
-                                args->downTime, args->pointerCount, args->pointerProperties,
-                                args->pointerCoords, 0, 0);
+        std::unique_ptr<MotionEntry> newEntry =
+                std::make_unique<MotionEntry>(args->id, args->eventTime, args->deviceId,
+                                              args->source, args->displayId, policyFlags,
+                                              args->action, args->actionButton, args->flags,
+                                              args->metaState, args->buttonState,
+                                              args->classification, args->edgeFlags,
+                                              args->xPrecision, args->yPrecision,
+                                              args->xCursorPosition, args->yCursorPosition,
+                                              args->downTime, args->pointerCount,
+                                              args->pointerProperties, args->pointerCoords, 0, 0);
 
-        needWake = enqueueInboundEventLocked(newEntry);
+        needWake = enqueueInboundEventLocked(std::move(newEntry));
         mLock.unlock();
     } // release lock
 
@@ -3503,9 +3529,9 @@
     { // acquire lock
         std::scoped_lock _l(mLock);
 
-        DeviceResetEntry* newEntry =
-                new DeviceResetEntry(args->id, args->eventTime, args->deviceId);
-        needWake = enqueueInboundEventLocked(newEntry);
+        std::unique_ptr<DeviceResetEntry> newEntry =
+                std::make_unique<DeviceResetEntry>(args->id, args->eventTime, args->deviceId);
+        needWake = enqueueInboundEventLocked(std::move(newEntry));
     } // release lock
 
     if (needWake) {
@@ -3528,7 +3554,7 @@
         policyFlags |= POLICY_FLAG_TRUSTED;
     }
 
-    std::queue<EventEntry*> injectedEntries;
+    std::queue<std::unique_ptr<EventEntry>> injectedEntries;
     switch (event->getType()) {
         case AINPUT_EVENT_TYPE_KEY: {
             const KeyEvent& incomingKey = static_cast<const KeyEvent&>(*event);
@@ -3562,13 +3588,14 @@
             }
 
             mLock.lock();
-            KeyEntry* injectedEntry =
-                    new KeyEntry(incomingKey.getId(), incomingKey.getEventTime(),
-                                 VIRTUAL_KEYBOARD_ID, incomingKey.getSource(),
-                                 incomingKey.getDisplayId(), policyFlags, action, flags, keyCode,
-                                 incomingKey.getScanCode(), metaState, incomingKey.getRepeatCount(),
-                                 incomingKey.getDownTime());
-            injectedEntries.push(injectedEntry);
+            std::unique_ptr<KeyEntry> injectedEntry =
+                    std::make_unique<KeyEntry>(incomingKey.getId(), incomingKey.getEventTime(),
+                                               VIRTUAL_KEYBOARD_ID, incomingKey.getSource(),
+                                               incomingKey.getDisplayId(), policyFlags, action,
+                                               flags, keyCode, incomingKey.getScanCode(), metaState,
+                                               incomingKey.getRepeatCount(),
+                                               incomingKey.getDownTime());
+            injectedEntries.push(std::move(injectedEntry));
             break;
         }
 
@@ -3596,37 +3623,46 @@
             mLock.lock();
             const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
             const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
-            MotionEntry* injectedEntry =
-                    new MotionEntry(motionEvent->getId(), *sampleEventTimes, VIRTUAL_KEYBOARD_ID,
-                                    motionEvent->getSource(), motionEvent->getDisplayId(),
-                                    policyFlags, action, actionButton, motionEvent->getFlags(),
-                                    motionEvent->getMetaState(), motionEvent->getButtonState(),
-                                    motionEvent->getClassification(), motionEvent->getEdgeFlags(),
-                                    motionEvent->getXPrecision(), motionEvent->getYPrecision(),
-                                    motionEvent->getRawXCursorPosition(),
-                                    motionEvent->getRawYCursorPosition(),
-                                    motionEvent->getDownTime(), uint32_t(pointerCount),
-                                    pointerProperties, samplePointerCoords,
-                                    motionEvent->getXOffset(), motionEvent->getYOffset());
-            injectedEntries.push(injectedEntry);
+            std::unique_ptr<MotionEntry> injectedEntry =
+                    std::make_unique<MotionEntry>(motionEvent->getId(), *sampleEventTimes,
+                                                  VIRTUAL_KEYBOARD_ID, motionEvent->getSource(),
+                                                  motionEvent->getDisplayId(), policyFlags, action,
+                                                  actionButton, motionEvent->getFlags(),
+                                                  motionEvent->getMetaState(),
+                                                  motionEvent->getButtonState(),
+                                                  motionEvent->getClassification(),
+                                                  motionEvent->getEdgeFlags(),
+                                                  motionEvent->getXPrecision(),
+                                                  motionEvent->getYPrecision(),
+                                                  motionEvent->getRawXCursorPosition(),
+                                                  motionEvent->getRawYCursorPosition(),
+                                                  motionEvent->getDownTime(),
+                                                  uint32_t(pointerCount), pointerProperties,
+                                                  samplePointerCoords, motionEvent->getXOffset(),
+                                                  motionEvent->getYOffset());
+            injectedEntries.push(std::move(injectedEntry));
             for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
                 sampleEventTimes += 1;
                 samplePointerCoords += pointerCount;
-                MotionEntry* nextInjectedEntry =
-                        new MotionEntry(motionEvent->getId(), *sampleEventTimes,
-                                        VIRTUAL_KEYBOARD_ID, motionEvent->getSource(),
-                                        motionEvent->getDisplayId(), policyFlags, action,
-                                        actionButton, motionEvent->getFlags(),
-                                        motionEvent->getMetaState(), motionEvent->getButtonState(),
-                                        motionEvent->getClassification(),
-                                        motionEvent->getEdgeFlags(), motionEvent->getXPrecision(),
-                                        motionEvent->getYPrecision(),
-                                        motionEvent->getRawXCursorPosition(),
-                                        motionEvent->getRawYCursorPosition(),
-                                        motionEvent->getDownTime(), uint32_t(pointerCount),
-                                        pointerProperties, samplePointerCoords,
-                                        motionEvent->getXOffset(), motionEvent->getYOffset());
-                injectedEntries.push(nextInjectedEntry);
+                std::unique_ptr<MotionEntry> nextInjectedEntry =
+                        std::make_unique<MotionEntry>(motionEvent->getId(), *sampleEventTimes,
+                                                      VIRTUAL_KEYBOARD_ID, motionEvent->getSource(),
+                                                      motionEvent->getDisplayId(), policyFlags,
+                                                      action, actionButton, motionEvent->getFlags(),
+                                                      motionEvent->getMetaState(),
+                                                      motionEvent->getButtonState(),
+                                                      motionEvent->getClassification(),
+                                                      motionEvent->getEdgeFlags(),
+                                                      motionEvent->getXPrecision(),
+                                                      motionEvent->getYPrecision(),
+                                                      motionEvent->getRawXCursorPosition(),
+                                                      motionEvent->getRawYCursorPosition(),
+                                                      motionEvent->getDownTime(),
+                                                      uint32_t(pointerCount), pointerProperties,
+                                                      samplePointerCoords,
+                                                      motionEvent->getXOffset(),
+                                                      motionEvent->getYOffset());
+                injectedEntries.push(std::move(nextInjectedEntry));
             }
             break;
         }
@@ -3646,7 +3682,7 @@
 
     bool needWake = false;
     while (!injectedEntries.empty()) {
-        needWake |= enqueueInboundEventLocked(injectedEntries.front());
+        needWake |= enqueueInboundEventLocked(std::move(injectedEntries.front()));
         injectedEntries.pop();
     }
 
@@ -3753,9 +3789,9 @@
             mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid);
 }
 
-void InputDispatcher::setInjectionResult(EventEntry* entry,
+void InputDispatcher::setInjectionResult(EventEntry& entry,
                                          InputEventInjectionResult injectionResult) {
-    InjectionState* injectionState = entry->injectionState;
+    InjectionState* injectionState = entry.injectionState;
     if (injectionState) {
 #if DEBUG_INJECTION
         ALOGD("Setting input event injection result to %d.  "
@@ -3763,7 +3799,7 @@
               injectionResult, injectionState->injectorPid, injectionState->injectorUid);
 #endif
 
-        if (injectionState->injectionIsAsync && !(entry->policyFlags & POLICY_FLAG_FILTERED)) {
+        if (injectionState->injectionIsAsync && !(entry.policyFlags & POLICY_FLAG_FILTERED)) {
             // Log the outcome since the injector did not wait for the injection result.
             switch (injectionResult) {
                 case InputEventInjectionResult::SUCCEEDED:
@@ -3789,15 +3825,15 @@
     }
 }
 
-void InputDispatcher::incrementPendingForegroundDispatches(EventEntry* entry) {
-    InjectionState* injectionState = entry->injectionState;
+void InputDispatcher::incrementPendingForegroundDispatches(EventEntry& entry) {
+    InjectionState* injectionState = entry.injectionState;
     if (injectionState) {
         injectionState->pendingForegroundDispatches += 1;
     }
 }
 
-void InputDispatcher::decrementPendingForegroundDispatches(EventEntry* entry) {
-    InjectionState* injectionState = entry->injectionState;
+void InputDispatcher::decrementPendingForegroundDispatches(EventEntry& entry) {
+    InjectionState* injectionState = entry.injectionState;
     if (injectionState) {
         injectionState->pendingForegroundDispatches -= 1;
 
@@ -4485,7 +4521,7 @@
     // Dump recently dispatched or dropped events from oldest to newest.
     if (!mRecentQueue.empty()) {
         dump += StringPrintf(INDENT "RecentQueue: length=%zu\n", mRecentQueue.size());
-        for (EventEntry* entry : mRecentQueue) {
+        for (std::shared_ptr<EventEntry>& entry : mRecentQueue) {
             dump += INDENT2;
             dump += entry->getDescription();
             dump += StringPrintf(", age=%" PRId64 "ms\n", ns2ms(currentTime - entry->eventTime));
@@ -4508,7 +4544,7 @@
     // Dump inbound events from oldest to newest.
     if (!mInboundQueue.empty()) {
         dump += StringPrintf(INDENT "InboundQueue: length=%zu\n", mInboundQueue.size());
-        for (EventEntry* entry : mInboundQueue) {
+        for (std::shared_ptr<EventEntry>& entry : mInboundQueue) {
             dump += INDENT2;
             dump += entry->getDescription();
             dump += StringPrintf(", age=%" PRId64 "ms\n", ns2ms(currentTime - entry->eventTime));
@@ -5001,8 +5037,8 @@
 
 void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
         CommandEntry* commandEntry) {
-    KeyEntry* entry = commandEntry->keyEntry;
-    KeyEvent event = createKeyEvent(*entry);
+    KeyEntry& entry = *(commandEntry->keyEntry);
+    KeyEvent event = createKeyEvent(entry);
 
     mLock.unlock();
 
@@ -5010,7 +5046,7 @@
     sp<IBinder> token = commandEntry->inputChannel != nullptr
             ? commandEntry->inputChannel->getConnectionToken()
             : nullptr;
-    nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, &event, entry->policyFlags);
+    nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(token, &event, entry.policyFlags);
     if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
         ALOGW("Excessive delay in interceptKeyBeforeDispatching; took %s ms",
               std::to_string(t.duration().count()).c_str());
@@ -5019,14 +5055,13 @@
     mLock.lock();
 
     if (delay < 0) {
-        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
+        entry.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP;
     } else if (!delay) {
-        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
+        entry.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE;
     } else {
-        entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
-        entry->interceptKeyWakeupTime = now() + delay;
+        entry.interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER;
+        entry.interceptKeyWakeupTime = now() + delay;
     }
-    entry->release();
 }
 
 void InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) {
@@ -5070,11 +5105,11 @@
 
     bool restartEvent;
     if (dispatchEntry->eventEntry->type == EventEntry::Type::KEY) {
-        KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
+        KeyEntry& keyEntry = static_cast<KeyEntry&>(*(dispatchEntry->eventEntry));
         restartEvent =
                 afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled);
     } else if (dispatchEntry->eventEntry->type == EventEntry::Type::MOTION) {
-        MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
+        MotionEntry& motionEntry = static_cast<MotionEntry&>(*(dispatchEntry->eventEntry));
         restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry,
                                                            handled);
     } else {
@@ -5109,20 +5144,20 @@
 
 bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection,
                                                        DispatchEntry* dispatchEntry,
-                                                       KeyEntry* keyEntry, bool handled) {
-    if (keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK) {
+                                                       KeyEntry& keyEntry, bool handled) {
+    if (keyEntry.flags & AKEY_EVENT_FLAG_FALLBACK) {
         if (!handled) {
             // Report the key as unhandled, since the fallback was not handled.
-            mReporter->reportUnhandledKey(keyEntry->id);
+            mReporter->reportUnhandledKey(keyEntry.id);
         }
         return false;
     }
 
     // Get the fallback key state.
     // Clear it out after dispatching the UP.
-    int32_t originalKeyCode = keyEntry->keyCode;
+    int32_t originalKeyCode = keyEntry.keyCode;
     int32_t fallbackKeyCode = connection->inputState.getFallbackKey(originalKeyCode);
-    if (keyEntry->action == AKEY_EVENT_ACTION_UP) {
+    if (keyEntry.action == AKEY_EVENT_ACTION_UP) {
         connection->inputState.removeFallbackKey(originalKeyCode);
     }
 
@@ -5135,16 +5170,15 @@
 #if DEBUG_OUTBOUND_EVENT_DETAILS
             ALOGD("Unhandled key event: Asking policy to cancel fallback action.  "
                   "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
-                  keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount,
-                  keyEntry->policyFlags);
+                  keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
 #endif
-            KeyEvent event = createKeyEvent(*keyEntry);
+            KeyEvent event = createKeyEvent(keyEntry);
             event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED);
 
             mLock.unlock();
 
             mPolicy->dispatchUnhandledKey(connection->inputChannel->getConnectionToken(), &event,
-                                          keyEntry->policyFlags, &event);
+                                          keyEntry.policyFlags, &event);
 
             mLock.lock();
 
@@ -5163,13 +5197,13 @@
         // If the application did not handle a non-fallback key, first check
         // that we are in a good state to perform unhandled key event processing
         // Then ask the policy what to do with it.
-        bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN && keyEntry->repeatCount == 0;
+        bool initialDown = keyEntry.action == AKEY_EVENT_ACTION_DOWN && keyEntry.repeatCount == 0;
         if (fallbackKeyCode == -1 && !initialDown) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
             ALOGD("Unhandled key event: Skipping unhandled key event processing "
                   "since this is not an initial down.  "
                   "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
-                  originalKeyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags);
+                  originalKeyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
 #endif
             return false;
         }
@@ -5178,15 +5212,15 @@
 #if DEBUG_OUTBOUND_EVENT_DETAILS
         ALOGD("Unhandled key event: Asking policy to perform fallback action.  "
               "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x",
-              keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, keyEntry->policyFlags);
+              keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags);
 #endif
-        KeyEvent event = createKeyEvent(*keyEntry);
+        KeyEvent event = createKeyEvent(keyEntry);
 
         mLock.unlock();
 
         bool fallback =
                 mPolicy->dispatchUnhandledKey(connection->inputChannel->getConnectionToken(),
-                                              &event, keyEntry->policyFlags, &event);
+                                              &event, keyEntry.policyFlags, &event);
 
         mLock.lock();
 
@@ -5234,7 +5268,7 @@
 
             fallback = false;
             fallbackKeyCode = AKEYCODE_UNKNOWN;
-            if (keyEntry->action != AKEY_EVENT_ACTION_UP) {
+            if (keyEntry.action != AKEY_EVENT_ACTION_UP) {
                 connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode);
             }
         }
@@ -5254,22 +5288,22 @@
 
         if (fallback) {
             // Restart the dispatch cycle using the fallback key.
-            keyEntry->eventTime = event.getEventTime();
-            keyEntry->deviceId = event.getDeviceId();
-            keyEntry->source = event.getSource();
-            keyEntry->displayId = event.getDisplayId();
-            keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK;
-            keyEntry->keyCode = fallbackKeyCode;
-            keyEntry->scanCode = event.getScanCode();
-            keyEntry->metaState = event.getMetaState();
-            keyEntry->repeatCount = event.getRepeatCount();
-            keyEntry->downTime = event.getDownTime();
-            keyEntry->syntheticRepeat = false;
+            keyEntry.eventTime = event.getEventTime();
+            keyEntry.deviceId = event.getDeviceId();
+            keyEntry.source = event.getSource();
+            keyEntry.displayId = event.getDisplayId();
+            keyEntry.flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK;
+            keyEntry.keyCode = fallbackKeyCode;
+            keyEntry.scanCode = event.getScanCode();
+            keyEntry.metaState = event.getMetaState();
+            keyEntry.repeatCount = event.getRepeatCount();
+            keyEntry.downTime = event.getDownTime();
+            keyEntry.syntheticRepeat = false;
 
 #if DEBUG_OUTBOUND_EVENT_DETAILS
             ALOGD("Unhandled key event: Dispatching fallback key.  "
                   "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x",
-                  originalKeyCode, fallbackKeyCode, keyEntry->metaState);
+                  originalKeyCode, fallbackKeyCode, keyEntry.metaState);
 #endif
             return true; // restart the event
         } else {
@@ -5278,7 +5312,7 @@
 #endif
 
             // Report the key as unhandled, since there is no fallback key.
-            mReporter->reportUnhandledKey(keyEntry->id);
+            mReporter->reportUnhandledKey(keyEntry.id);
         }
     }
     return false;
@@ -5286,7 +5320,7 @@
 
 bool InputDispatcher::afterMotionEventLockedInterruptible(const sp<Connection>& connection,
                                                           DispatchEntry* dispatchEntry,
-                                                          MotionEntry* motionEntry, bool handled) {
+                                                          MotionEntry& motionEntry, bool handled) {
     return false;
 }
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 235a8d3..4565151 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -158,9 +158,9 @@
 
     sp<Looper> mLooper;
 
-    EventEntry* mPendingEvent GUARDED_BY(mLock);
-    std::deque<EventEntry*> mInboundQueue GUARDED_BY(mLock);
-    std::deque<EventEntry*> mRecentQueue GUARDED_BY(mLock);
+    std::shared_ptr<EventEntry> mPendingEvent GUARDED_BY(mLock);
+    std::deque<std::shared_ptr<EventEntry>> mInboundQueue GUARDED_BY(mLock);
+    std::deque<std::shared_ptr<EventEntry>> mRecentQueue GUARDED_BY(mLock);
     std::deque<std::unique_ptr<CommandEntry>> mCommandQueue GUARDED_BY(mLock);
 
     DropReason mLastDropReason GUARDED_BY(mLock);
@@ -175,7 +175,7 @@
     void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) REQUIRES(mLock);
 
     // Enqueues an inbound event.  Returns true if mLooper->wake() should be called.
-    bool enqueueInboundEventLocked(EventEntry* entry) REQUIRES(mLock);
+    bool enqueueInboundEventLocked(std::unique_ptr<EventEntry> entry) REQUIRES(mLock);
 
     // Cleans up input state when dropping an inbound event.
     void dropInboundEventLocked(const EventEntry& entry, DropReason dropReason) REQUIRES(mLock);
@@ -185,7 +185,7 @@
                                  std::string_view reason) REQUIRES(mLock);
 
     // Adds an event to a queue of recent events for debugging purposes.
-    void addRecentEventLocked(EventEntry* entry) REQUIRES(mLock);
+    void addRecentEventLocked(std::shared_ptr<EventEntry> entry) REQUIRES(mLock);
 
     // App switch latency optimization.
     bool mAppSwitchSawKeyDown GUARDED_BY(mLock);
@@ -197,7 +197,7 @@
 
     // Blocked event latency optimization.  Drops old events when the user intends
     // to transfer focus to a new application.
-    EventEntry* mNextUnblockedEvent GUARDED_BY(mLock);
+    std::shared_ptr<EventEntry> mNextUnblockedEvent GUARDED_BY(mLock);
 
     sp<InputWindowHandle> findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y,
                                                     TouchState* touchState,
@@ -242,21 +242,21 @@
     // Event injection and synchronization.
     std::condition_variable mInjectionResultAvailable;
     bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid);
-    void setInjectionResult(EventEntry* entry,
+    void setInjectionResult(EventEntry& entry,
                             android::os::InputEventInjectionResult injectionResult);
 
     std::condition_variable mInjectionSyncFinished;
-    void incrementPendingForegroundDispatches(EventEntry* entry);
-    void decrementPendingForegroundDispatches(EventEntry* entry);
+    void incrementPendingForegroundDispatches(EventEntry& entry);
+    void decrementPendingForegroundDispatches(EventEntry& entry);
 
     // Key repeat tracking.
     struct KeyRepeatState {
-        KeyEntry* lastKeyEntry; // or null if no repeat
+        std::shared_ptr<KeyEntry> lastKeyEntry; // or null if no repeat
         nsecs_t nextRepeatTime;
     } mKeyRepeatState GUARDED_BY(mLock);
 
     void resetKeyRepeatLocked() REQUIRES(mLock);
-    KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime) REQUIRES(mLock);
+    std::shared_ptr<KeyEntry> synthesizeKeyRepeatLocked(nsecs_t currentTime) REQUIRES(mLock);
 
     // Key replacement tracking
     struct KeyReplacement {
@@ -292,7 +292,7 @@
     // Inbound event processing.
     void drainInboundQueueLocked() REQUIRES(mLock);
     void releasePendingEventLocked() REQUIRES(mLock);
-    void releaseInboundEventLocked(EventEntry* entry) REQUIRES(mLock);
+    void releaseInboundEventLocked(std::shared_ptr<EventEntry> entry) REQUIRES(mLock);
 
     // Dispatch state.
     bool mDispatchEnabled GUARDED_BY(mLock);
@@ -356,15 +356,17 @@
                                        const std::vector<InputTarget>& targets) REQUIRES(mLock);
 
     // Dispatch inbound events.
-    bool dispatchConfigurationChangedLocked(nsecs_t currentTime, ConfigurationChangedEntry* entry)
+    bool dispatchConfigurationChangedLocked(nsecs_t currentTime,
+                                            const ConfigurationChangedEntry& entry) REQUIRES(mLock);
+    bool dispatchDeviceResetLocked(nsecs_t currentTime, const DeviceResetEntry& entry)
             REQUIRES(mLock);
-    bool dispatchDeviceResetLocked(nsecs_t currentTime, DeviceResetEntry* entry) REQUIRES(mLock);
-    bool dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, DropReason* dropReason,
-                           nsecs_t* nextWakeupTime) REQUIRES(mLock);
-    bool dispatchMotionLocked(nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason,
-                              nsecs_t* nextWakeupTime) REQUIRES(mLock);
-    void dispatchFocusLocked(nsecs_t currentTime, FocusEntry* entry) REQUIRES(mLock);
-    void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry,
+    bool dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry,
+                           DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock);
+    bool dispatchMotionLocked(nsecs_t currentTime, std::shared_ptr<MotionEntry> entry,
+                              DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock);
+    void dispatchFocusLocked(nsecs_t currentTime, std::shared_ptr<FocusEntry> entry)
+            REQUIRES(mLock);
+    void dispatchEventLocked(nsecs_t currentTime, std::shared_ptr<EventEntry> entry,
                              const std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
 
     void logOutboundKeyDetails(const char* prefix, const KeyEntry& entry);
@@ -461,6 +463,7 @@
         float obscuringOpacity;
         std::string obscuringPackage;
         int32_t obscuringUid;
+        std::vector<std::string> debugInfo;
     };
 
     TouchOcclusionInfo computeTouchOcclusionInfoLocked(const sp<InputWindowHandle>& windowHandle,
@@ -469,6 +472,7 @@
     bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle, int32_t x,
                                        int32_t y) const REQUIRES(mLock);
     bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
+    std::string dumpWindowForTouchOcclusion(const InputWindowInfo* info, bool isTouchWindow) const;
     std::string getApplicationWindowLabel(
             const std::shared_ptr<InputApplicationHandle>& applicationHandle,
             const sp<InputWindowHandle>& windowHandle);
@@ -478,12 +482,12 @@
     // with the mutex held makes it easier to ensure that connection invariants are maintained.
     // If needed, the methods post commands to run later once the critical bits are done.
     void prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
-                                    EventEntry* eventEntry, const InputTarget& inputTarget)
+                                    std::shared_ptr<EventEntry>, const InputTarget& inputTarget)
             REQUIRES(mLock);
     void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection,
-                                      EventEntry* eventEntry, const InputTarget& inputTarget)
+                                      std::shared_ptr<EventEntry>, const InputTarget& inputTarget)
             REQUIRES(mLock);
-    void enqueueDispatchEntryLocked(const sp<Connection>& connection, EventEntry* eventEntry,
+    void enqueueDispatchEntryLocked(const sp<Connection>& connection, std::shared_ptr<EventEntry>,
                                     const InputTarget& inputTarget, int32_t dispatchMode)
             REQUIRES(mLock);
     void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection)
@@ -517,7 +521,8 @@
             REQUIRES(mLock);
 
     // Splitting motion events across windows.
-    MotionEntry* splitMotionEvent(const MotionEntry& originalMotionEntry, BitSet32 pointerIds);
+    std::unique_ptr<MotionEntry> splitMotionEvent(const MotionEntry& originalMotionEntry,
+                                                  BitSet32 pointerIds);
 
     // Reset and drop everything the dispatcher is doing.
     void resetAndDropEverythingLocked(const char* reason) REQUIRES(mLock);
@@ -566,10 +571,10 @@
             REQUIRES(mLock);
     void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
     bool afterKeyEventLockedInterruptible(const sp<Connection>& connection,
-                                          DispatchEntry* dispatchEntry, KeyEntry* keyEntry,
+                                          DispatchEntry* dispatchEntry, KeyEntry& keyEntry,
                                           bool handled) REQUIRES(mLock);
     bool afterMotionEventLockedInterruptible(const sp<Connection>& connection,
-                                             DispatchEntry* dispatchEntry, MotionEntry* motionEntry,
+                                             DispatchEntry* dispatchEntry, MotionEntry& motionEntry,
                                              bool handled) REQUIRES(mLock);
     void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
     KeyEvent createKeyEvent(const KeyEntry& entry);
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index 386056d..1656a21 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -265,17 +265,18 @@
     }
 }
 
-std::vector<EventEntry*> InputState::synthesizeCancelationEvents(
+std::vector<std::unique_ptr<EventEntry>> InputState::synthesizeCancelationEvents(
         nsecs_t currentTime, const CancelationOptions& options) {
-    std::vector<EventEntry*> events;
+    std::vector<std::unique_ptr<EventEntry>> events;
     for (KeyMemento& memento : mKeyMementos) {
         if (shouldCancelKey(memento, options)) {
-            events.push_back(new KeyEntry(mIdGenerator.nextId(), currentTime, memento.deviceId,
-                                          memento.source, memento.displayId, memento.policyFlags,
-                                          AKEY_EVENT_ACTION_UP,
-                                          memento.flags | AKEY_EVENT_FLAG_CANCELED, memento.keyCode,
-                                          memento.scanCode, memento.metaState, 0 /*repeatCount*/,
-                                          memento.downTime));
+            events.push_back(
+                    std::make_unique<KeyEntry>(mIdGenerator.nextId(), currentTime, memento.deviceId,
+                                               memento.source, memento.displayId,
+                                               memento.policyFlags, AKEY_EVENT_ACTION_UP,
+                                               memento.flags | AKEY_EVENT_FLAG_CANCELED,
+                                               memento.keyCode, memento.scanCode, memento.metaState,
+                                               0 /*repeatCount*/, memento.downTime));
         }
     }
 
@@ -283,22 +284,26 @@
         if (shouldCancelMotion(memento, options)) {
             const int32_t action = memento.hovering ? AMOTION_EVENT_ACTION_HOVER_EXIT
                                                     : AMOTION_EVENT_ACTION_CANCEL;
-            events.push_back(new MotionEntry(mIdGenerator.nextId(), currentTime, memento.deviceId,
-                                             memento.source, memento.displayId, memento.policyFlags,
-                                             action, 0 /*actionButton*/, memento.flags, AMETA_NONE,
-                                             0 /*buttonState*/, MotionClassification::NONE,
-                                             AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
-                                             memento.yPrecision, memento.xCursorPosition,
-                                             memento.yCursorPosition, memento.downTime,
-                                             memento.pointerCount, memento.pointerProperties,
-                                             memento.pointerCoords, 0 /*xOffset*/, 0 /*yOffset*/));
+            events.push_back(
+                    std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
+                                                  memento.deviceId, memento.source,
+                                                  memento.displayId, memento.policyFlags, action,
+                                                  0 /*actionButton*/, memento.flags, AMETA_NONE,
+                                                  0 /*buttonState*/, MotionClassification::NONE,
+                                                  AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
+                                                  memento.yPrecision, memento.xCursorPosition,
+                                                  memento.yCursorPosition, memento.downTime,
+                                                  memento.pointerCount, memento.pointerProperties,
+                                                  memento.pointerCoords, 0 /*xOffset*/,
+                                                  0 /*yOffset*/));
         }
     }
     return events;
 }
 
-std::vector<EventEntry*> InputState::synthesizePointerDownEvents(nsecs_t currentTime) {
-    std::vector<EventEntry*> events;
+std::vector<std::unique_ptr<EventEntry>> InputState::synthesizePointerDownEvents(
+        nsecs_t currentTime) {
+    std::vector<std::unique_ptr<EventEntry>> events;
     for (MotionMemento& memento : mMotionMementos) {
         if (!(memento.source & AINPUT_SOURCE_CLASS_POINTER)) {
             continue;
@@ -333,15 +338,17 @@
                     : AMOTION_EVENT_ACTION_POINTER_DOWN
                             | (i << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
 
-            events.push_back(new MotionEntry(mIdGenerator.nextId(), currentTime, memento.deviceId,
-                                             memento.source, memento.displayId, memento.policyFlags,
-                                             action, 0 /*actionButton*/, memento.flags, AMETA_NONE,
-                                             0 /*buttonState*/, MotionClassification::NONE,
-                                             AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
-                                             memento.yPrecision, memento.xCursorPosition,
-                                             memento.yCursorPosition, memento.downTime,
-                                             pointerCount, pointerProperties, pointerCoords,
-                                             0 /*xOffset*/, 0 /*yOffset*/));
+            events.push_back(
+                    std::make_unique<MotionEntry>(mIdGenerator.nextId(), currentTime,
+                                                  memento.deviceId, memento.source,
+                                                  memento.displayId, memento.policyFlags, action,
+                                                  0 /*actionButton*/, memento.flags, AMETA_NONE,
+                                                  0 /*buttonState*/, MotionClassification::NONE,
+                                                  AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
+                                                  memento.yPrecision, memento.xCursorPosition,
+                                                  memento.yCursorPosition, memento.downTime,
+                                                  pointerCount, pointerProperties, pointerCoords,
+                                                  0 /*xOffset*/, 0 /*yOffset*/));
         }
 
         memento.firstNewPointerIdx = INVALID_POINTER_INDEX;
diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h
index d97a664..74ae21f 100644
--- a/services/inputflinger/dispatcher/InputState.h
+++ b/services/inputflinger/dispatcher/InputState.h
@@ -51,11 +51,11 @@
     bool trackMotion(const MotionEntry& entry, int32_t action, int32_t flags);
 
     // Synthesizes cancelation events for the current state and resets the tracked state.
-    std::vector<EventEntry*> synthesizeCancelationEvents(nsecs_t currentTime,
-                                                         const CancelationOptions& options);
+    std::vector<std::unique_ptr<EventEntry>> synthesizeCancelationEvents(
+            nsecs_t currentTime, const CancelationOptions& options);
 
     // Synthesizes down events for the current state.
-    std::vector<EventEntry*> synthesizePointerDownEvents(nsecs_t currentTime);
+    std::vector<std::unique_ptr<EventEntry>> synthesizePointerDownEvents(nsecs_t currentTime);
 
     // Clears the current state.
     void clear();
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index 6465cc9..8cb7194 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -48,4 +48,5 @@
         "libc++fs"
     ],
     require_root: true,
+    test_suites: ["device-tests"],
 }
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index c77298e..d302f98 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -204,8 +204,8 @@
     layer.frameNumber = mCurrentFrameNumber;
     layer.bufferId = mBufferInfo.mBuffer ? mBufferInfo.mBuffer->getId() : 0;
 
-    // TODO: we could be more subtle with isFixedSize()
-    const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
+    const bool useFiltering =
+            targetSettings.needsFiltering || mNeedsFiltering || bufferNeedsFiltering();
 
     // Query the texture matrix given our current filtering mode.
     float textureMatrix[16];
@@ -527,10 +527,6 @@
 }
 
 uint32_t BufferLayer::getEffectiveScalingMode() const {
-    if (mOverrideScalingMode >= 0) {
-        return mOverrideScalingMode;
-    }
-
     return mBufferInfo.mScaleMode;
 }
 
@@ -826,6 +822,10 @@
     }
 }
 
+bool BufferLayer::bufferNeedsFiltering() const {
+    return isFixedSize();
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 1cd753b..deaf846 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -94,8 +94,7 @@
 
     bool hasReadyFrame() const override;
 
-    // Returns the current scaling mode, unless mOverrideScalingMode
-    // is set, in which case, it returns mOverrideScalingMode
+    // Returns the current scaling mode
     uint32_t getEffectiveScalingMode() const override;
 
     // Calls latchBuffer if the buffer has a frame queued and then releases the buffer.
@@ -116,6 +115,10 @@
 
     ui::Transform::RotationFlags getTransformHint() const override { return mTransformHint; }
 
+    // Returns true if the transformed buffer size does not match the layer size and we need
+    // to apply filtering.
+    virtual bool bufferNeedsFiltering() const;
+
 protected:
     struct BufferInfo {
         nsecs_t mDesiredPresentTime;
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 7c73df2..69d2d11 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -503,6 +503,9 @@
 BufferLayerConsumer::Image::Image(const sp<GraphicBuffer>& graphicBuffer,
                                   renderengine::RenderEngine& engine)
       : mGraphicBuffer(graphicBuffer), mRE(engine) {
+    if (graphicBuffer != nullptr && (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED)) {
+        return;
+    }
     mRE.cacheExternalTextureBuffer(mGraphicBuffer);
 }
 
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 51c7ed5..9ab2974 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -239,7 +239,7 @@
     bool queuedBuffer = false;
     const int32_t layerId = getSequence();
     LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
-                    getProducerStickyTransform() != 0, mName, mOverrideScalingMode,
+                    getProducerStickyTransform() != 0, mName,
                     getTransformToDisplayInverse());
 
     if (isRemovedFromCurrentState()) {
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 66b4e19..a64b243 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -48,7 +48,6 @@
 
 BufferStateLayer::BufferStateLayer(const LayerCreationArgs& args)
       : BufferLayer(args), mHwcSlotGenerator(new HwcSlotGenerator()) {
-    mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
     mCurrentState.dataspace = ui::Dataspace::V0_SRGB;
 }
 
@@ -263,6 +262,8 @@
 bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence,
                                  nsecs_t postTime, nsecs_t desiredPresentTime,
                                  const client_cache_t& clientCacheId, uint64_t frameNumber) {
+    ATRACE_CALL();
+
     if (mCurrentState.buffer) {
         mReleasePreviousBuffer = true;
     }
@@ -681,6 +682,10 @@
     mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId);
 }
 
+uint32_t BufferStateLayer::getEffectiveScalingMode() const {
+   return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
+}
+
 Rect BufferStateLayer::computeCrop(const State& s) {
     if (s.crop.isEmpty() && s.buffer) {
         return s.buffer->getBounds();
@@ -739,6 +744,31 @@
                                         static_cast<float>(s.active.transform.ty() + s.active.h)),
                               radius);
 }
+
+bool BufferStateLayer::bufferNeedsFiltering() const {
+    const State& s(getDrawingState());
+    if (!s.buffer) {
+        return false;
+    }
+
+    uint32_t bufferWidth = s.buffer->width;
+    uint32_t bufferHeight = s.buffer->height;
+
+    // Undo any transformations on the buffer and return the result.
+    if (s.transform & ui::Transform::ROT_90) {
+        std::swap(bufferWidth, bufferHeight);
+    }
+
+    if (s.transformToDisplayInverse) {
+        uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
+        if (invTransform & ui::Transform::ROT_90) {
+            std::swap(bufferWidth, bufferHeight);
+        }
+    }
+
+    const Rect layerSize{getBounds()};
+    return layerSize.width() != bufferWidth || layerSize.height() != bufferHeight;
+}
 } // namespace android
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index c13f5e8..104a13b 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -92,7 +92,6 @@
         return false;
     }
     bool setCrop_legacy(const Rect& /*crop*/) override { return false; }
-    bool setOverrideScalingMode(int32_t /*overrideScalingMode*/) override { return false; }
     void deferTransactionUntil_legacy(const sp<IBinder>& /*barrierHandle*/,
                                       uint64_t /*frameNumber*/) override {}
     void deferTransactionUntil_legacy(const sp<Layer>& /*barrierLayer*/,
@@ -110,6 +109,7 @@
     bool fenceHasSignaled() const override;
     bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
     bool onPreComposition(nsecs_t refreshStartTime) override;
+    uint32_t getEffectiveScalingMode() const override;
 
 protected:
     void gatherBufferInfo() override;
@@ -143,6 +143,8 @@
 
     bool willPresentCurrentTransaction() const;
 
+    bool bufferNeedsFiltering() const override;
+
     static const std::array<float, 16> IDENTITY_MATRIX;
 
     std::unique_ptr<renderengine::Image> mTextureImage;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index 77400eb..5a3b9ac 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -20,6 +20,7 @@
 
 #include <gui/HdrMetadata.h>
 #include <math/mat4.h>
+#include <ui/BlurRegion.h>
 #include <ui/FloatRect.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
@@ -118,6 +119,9 @@
     // length of the shadow in screen space
     float shadowRadius{0.f};
 
+    // List of regions that require blur
+    std::vector<BlurRegion> blurRegions;
+
     /*
      * Geometry state
      */
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index d590f23..3be1cc4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -167,6 +167,11 @@
                                const Rect& orientedDisplaySpaceRect) = 0;
     // Sets the bounds to use
     virtual void setDisplaySize(const ui::Size&) = 0;
+    // Gets the transform hint used in layers that belong to this output. Used to guide
+    // composition orientation so that HW overlay can be used when display isn't in its natural
+    // orientation on some devices. Therefore usually we only use transform hint from display
+    // output.
+    virtual ui::Transform::RotationFlags getTransformHint() const = 0;
 
     // Sets the layer stack filtering settings for this output. See
     // belongsInOutput for full details.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 5b832a5..651230c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -42,6 +42,7 @@
                        const Rect& orientedDisplaySpaceRect) override;
     void setDisplaySize(const ui::Size&) override;
     void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
+    ui::Transform::RotationFlags getTransformHint() const override;
 
     void setColorTransform(const compositionengine::CompositionRefreshArgs&) override;
     void setColorProfile(const ColorProfile&) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index d6fbd7f..95db4da 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -39,6 +39,7 @@
     MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
     MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
     MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
+    MOCK_CONST_METHOD0(getTransformHint, ui::Transform::RotationFlags());
 
     MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
     MOCK_METHOD1(setColorProfile, void(const ColorProfile&));
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 04dceae..3852f45 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -192,6 +192,10 @@
     dirtyEntireOutput();
 }
 
+ui::Transform::RotationFlags Output::getTransformHint() const {
+    return static_cast<ui::Transform::RotationFlags>(getState().transform.getOrientation());
+}
+
 void Output::setLayerStackFilter(uint32_t layerStackId, bool isInternal) {
     auto& outputState = editState();
     outputState.layerStackId = layerStackId;
@@ -665,7 +669,8 @@
 compositionengine::OutputLayer* Output::findLayerRequestingBackgroundComposition() const {
     compositionengine::OutputLayer* layerRequestingBgComposition = nullptr;
     for (auto* layer : getOutputLayersOrderedByZ()) {
-        if (layer->getLayerFE().getCompositionState()->backgroundBlurRadius > 0) {
+        if (layer->getLayerFE().getCompositionState()->backgroundBlurRadius > 0 ||
+            layer->getLayerFE().getCompositionState()->blurRegions.size() > 0) {
             layerRequestingBgComposition = layer;
         }
     }
@@ -897,6 +902,8 @@
             needsProtected == renderEngine.isProtected()) {
             mRenderSurface->setProtected(needsProtected);
         }
+    } else if (!outputState.isSecure && renderEngine.isProtected()) {
+        renderEngine.useProtectedContext(false);
     }
 
     base::unique_fd fd;
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 6d01bf1..1befbf8 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -160,6 +160,7 @@
         EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
         EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
         EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+        EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     }
 
     DisplayCreationArgs getDisplayCreationArgsForPhysicalHWCDisplay() {
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index b5cda68..84c027b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -81,6 +81,7 @@
 
     MOCK_METHOD2(onHotplug,
                  std::optional<DisplayIdentificationInfo>(hal::HWDisplayId, hal::Connection));
+    MOCK_CONST_METHOD0(updatesDeviceProductInfoOnHotplugReconnect, bool());
     MOCK_METHOD2(onVsync, bool(hal::HWDisplayId, int64_t));
     MOCK_METHOD2(setVsyncEnabled, void(PhysicalDisplayId, hal::Vsync));
     MOCK_CONST_METHOD1(getRefreshTimestamp, nsecs_t(PhysicalDisplayId));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 1e10365..9badb99 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -268,6 +268,8 @@
     EXPECT_EQ(orientation, state.framebufferSpace.orientation);
 
     EXPECT_EQ(state.displaySpace.content, state.transform.transform(state.layerStackSpace.content));
+
+    EXPECT_EQ(ui::Transform::ROT_90, mOutput->getTransformHint());
 }
 
 TEST_F(OutputTest, setProjectionWithSmallFramebufferWorks) {
@@ -2950,6 +2952,7 @@
     mOutput.mState.usesClientComposition = false;
 
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
 
     EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
 
@@ -2962,6 +2965,7 @@
     mOutput.mState.flipClientTarget = true;
 
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(mOutputBuffer));
     EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
@@ -2971,6 +2975,7 @@
 
 TEST_F(OutputComposeSurfacesTest, doesMinimalWorkIfDequeueBufferFailsForClientComposition) {
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(nullptr));
 
@@ -2983,6 +2988,7 @@
     mOutput.mState.flipClientTarget = true;
 
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(nullptr));
 
@@ -2993,6 +2999,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3015,6 +3022,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3042,6 +3050,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3070,6 +3079,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3098,6 +3108,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
     EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3129,6 +3140,7 @@
     EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
     EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+    EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
     EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
             .WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r2}))
             .WillOnce(Return(std::vector<LayerFE::LayerSettings>{r1, r3}));
@@ -3151,6 +3163,7 @@
 struct OutputComposeSurfacesTest_UsesExpectedDisplaySettings : public OutputComposeSurfacesTest {
     OutputComposeSurfacesTest_UsesExpectedDisplaySettings() {
         EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+        EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
         EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
                 .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{}));
         EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
@@ -3298,6 +3311,8 @@
     mOutput.mState.isSecure = false;
     mLayer2.mLayerFEState.hasProtectedContent = true;
     EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(true));
+    EXPECT_CALL(mRenderEngine, isProtected).WillOnce(Return(true));
+    EXPECT_CALL(mRenderEngine, useProtectedContext(false)).WillOnce(Return(true));
 
     mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
 }
@@ -3390,6 +3405,7 @@
         EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
         EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
         EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+        EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
         EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
                 .WillRepeatedly(Return());
         EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
@@ -3998,6 +4014,34 @@
     mOutput->updateAndWriteCompositionState(args);
 }
 
+TEST_F(OutputUpdateAndWriteCompositionStateTest, handlesBlurRegionRequests) {
+    InjectedLayer layer1;
+    InjectedLayer layer2;
+    InjectedLayer layer3;
+
+    // Layer requesting blur, or below, should request client composition.
+    EXPECT_CALL(*layer1.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
+    EXPECT_CALL(*layer1.outputLayer, writeStateToHWC(false));
+    EXPECT_CALL(*layer2.outputLayer, updateCompositionState(false, true, ui::Transform::ROT_0));
+    EXPECT_CALL(*layer2.outputLayer, writeStateToHWC(false));
+    EXPECT_CALL(*layer3.outputLayer, updateCompositionState(false, false, ui::Transform::ROT_0));
+    EXPECT_CALL(*layer3.outputLayer, writeStateToHWC(false));
+
+    BlurRegion region;
+    layer2.layerFEState.blurRegions.push_back(region);
+
+    injectOutputLayer(layer1);
+    injectOutputLayer(layer2);
+    injectOutputLayer(layer3);
+
+    mOutput->editState().isEnabled = true;
+
+    CompositionRefreshArgs args;
+    args.updatingGeometryThisFrame = false;
+    args.devOptForceClientComposition = false;
+    mOutput->updateAndWriteCompositionState(args);
+}
+
 TEST_F(GenerateClientCompositionRequestsTest, handlesLandscapeModeSplitScreenRequests) {
     // In split-screen landscape mode, the screen is rotated 90 degrees, with
     // one layer on the left covering the left side of the output, and one layer
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 5bd7a1f..cbc201f 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -248,6 +248,10 @@
     return mCompositionDisplay->getState().layerStackId;
 }
 
+ui::Transform::RotationFlags DisplayDevice::getTransformHint() const {
+    return mCompositionDisplay->getTransformHint();
+}
+
 const ui::Transform& DisplayDevice::getTransform() const {
     return mCompositionDisplay->getState().transform;
 }
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index fa684c0..cc38ab0 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -95,10 +95,7 @@
 
     static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags();
 
-    ui::Transform::RotationFlags getTransformHint() const {
-        return static_cast<ui::Transform::RotationFlags>(getTransform().getOrientation());
-    }
-
+    ui::Transform::RotationFlags getTransformHint() const;
     const ui::Transform& getTransform() const;
     const Rect& getLayerStackSpaceRect() const;
     const Rect& getOrientedDisplaySpaceRect() const;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 2fdbd3a..1548d18 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -26,6 +26,7 @@
 
 #include "HWComposer.h"
 
+#include <android-base/properties.h>
 #include <compositionengine/Output.h>
 #include <compositionengine/OutputLayer.h>
 #include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -38,6 +39,7 @@
 #include "../Layer.h" // needed only for debugging
 #include "../Promise.h"
 #include "../SurfaceFlinger.h"
+#include "../SurfaceFlingerProperties.h"
 #include "ComposerHal.h"
 #include "HWC2.h"
 
@@ -143,12 +145,13 @@
 
 namespace impl {
 
-HWComposer::HWComposer(std::unique_ptr<Hwc2::Composer> composer) : mComposer(std::move(composer)) {
-}
+HWComposer::HWComposer(std::unique_ptr<Hwc2::Composer> composer)
+      : mComposer(std::move(composer)),
+        mUpdateDeviceProductInfoOnHotplugReconnect(
+                android::sysprop::update_device_product_info_on_hotplug_reconnect(false)) {}
 
 HWComposer::HWComposer(const std::string& composerServiceName)
-      : mComposer(std::make_unique<Hwc2::impl::Composer>(composerServiceName)) {
-}
+      : HWComposer(std::make_unique<Hwc2::impl::Composer>(composerServiceName)) {}
 
 HWComposer::~HWComposer() {
     mDisplayData.clear();
@@ -204,6 +207,10 @@
     }
 }
 
+bool HWComposer::updatesDeviceProductInfoOnHotplugReconnect() const {
+    return mUpdateDeviceProductInfoOnHotplugReconnect;
+}
+
 bool HWComposer::onVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp) {
     const auto displayId = toPhysicalDisplayId(hwcDisplayId);
     if (!displayId) {
@@ -888,6 +895,16 @@
         info = DisplayIdentificationInfo{.id = *displayId,
                                          .name = std::string(),
                                          .deviceProductInfo = std::nullopt};
+        if (mUpdateDeviceProductInfoOnHotplugReconnect) {
+            uint8_t port;
+            DisplayIdentificationData data;
+            getDisplayIdentificationData(hwcDisplayId, &port, &data);
+            if (auto newInfo = parseDisplayIdentificationData(port, data)) {
+                info->deviceProductInfo = std::move(newInfo->deviceProductInfo);
+            } else {
+                ALOGE("Failed to parse identification data for display %" PRIu64, hwcDisplayId);
+            }
+        }
     } else {
         uint8_t port;
         DisplayIdentificationData data;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 028a9a4..d8af5bf 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -173,6 +173,10 @@
     virtual std::optional<DisplayIdentificationInfo> onHotplug(hal::HWDisplayId,
                                                                hal::Connection) = 0;
 
+    // If true we'll update the DeviceProductInfo on subsequent hotplug connected events.
+    // TODO(b/157555476): Remove when the framework has proper support for headless mode
+    virtual bool updatesDeviceProductInfoOnHotplugReconnect() const = 0;
+
     virtual bool onVsync(hal::HWDisplayId, int64_t timestamp) = 0;
     virtual void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) = 0;
 
@@ -303,10 +307,12 @@
 
     // Events handling ---------------------------------------------------------
 
-    // Returns stable display ID (and display name on connection of new or previously disconnected
+    // Returns PhysicalDisplayId (and display name on connection of new or previously disconnected
     // display), or std::nullopt if hotplug event was ignored.
     std::optional<DisplayIdentificationInfo> onHotplug(hal::HWDisplayId, hal::Connection) override;
 
+    bool updatesDeviceProductInfoOnHotplugReconnect() const override;
+
     bool onVsync(hal::HWDisplayId, int64_t timestamp) override;
     void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) override;
 
@@ -400,6 +406,8 @@
     bool mHasMultiDisplaySupport = false;
 
     RandomDisplayIdGenerator<HalVirtualDisplayId> mVirtualIdGenerator{getMaxVirtualDisplayCount()};
+
+    const bool mUpdateDeviceProductInfoOnHotplugReconnect;
 };
 
 } // namespace impl
diff --git a/services/surfaceflinger/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp
index 9a6b328..20486e0 100644
--- a/services/surfaceflinger/DisplayRenderArea.cpp
+++ b/services/surfaceflinger/DisplayRenderArea.cpp
@@ -26,8 +26,7 @@
         return RenderArea::RotationFlags::ROT_0;
     }
 
-    const ui::Rotation orientation = display.getPhysicalOrientation() + display.getOrientation();
-    return ui::Transform::toRotationFlags(orientation);
+    return ui::Transform::toRotationFlags(display.getOrientation());
 }
 
 } // namespace
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index bef52b7..ffae56f 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -482,6 +482,7 @@
     compositionState->blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
     compositionState->alpha = alpha;
     compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
+    compositionState->blurRegions = drawingState.blurRegions;
 }
 
 void Layer::prepareGeometryCompositionState() {
@@ -550,7 +551,8 @@
             isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
 
     // Force client composition for special cases known only to the front-end.
-    if (isHdrY410() || usesRoundedCorners || drawShadows()) {
+    if (isHdrY410() || usesRoundedCorners || drawShadows() ||
+        getDrawingState().blurRegions.size() > 0) {
         compositionState->forceClientComposition = true;
     }
 }
@@ -646,6 +648,7 @@
     layerSettings.alpha = alpha;
     layerSettings.sourceDataspace = getDataSpace();
     layerSettings.backgroundBlurRadius = getBackgroundBlurRadius();
+    layerSettings.blurRegions = getBlurRegions();
     return layerSettings;
 }
 
@@ -1035,6 +1038,12 @@
         mCurrentState.inputInfoChanged = false;
     }
 
+    // Add the callbacks from the drawing state into the current state. This is so when the current
+    // state gets copied to drawing, we don't lose the callback handles that are still in drawing.
+    for (auto& handle : s.callbackHandles) {
+        c.callbackHandles.push_back(handle);
+    }
+
     // Commit the transaction
     commitTransaction(c);
     mPendingStatesSnapshot = mPendingStates;
@@ -1280,6 +1289,14 @@
     return true;
 }
 
+bool Layer::setBlurRegions(const std::vector<BlurRegion>& blurRegions) {
+    mCurrentState.sequence++;
+    mCurrentState.blurRegions = blurRegions;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
 bool Layer::setFlags(uint8_t flags, uint8_t mask) {
     const uint32_t newFlags = (mCurrentState.flags & ~mask) | (flags & mask);
     if (mCurrentState.flags == newFlags) return false;
@@ -1301,13 +1318,6 @@
     return true;
 }
 
-bool Layer::setOverrideScalingMode(int32_t scalingMode) {
-    if (scalingMode == mOverrideScalingMode) return false;
-    mOverrideScalingMode = scalingMode;
-    setTransactionFlags(eTransactionNeeded);
-    return true;
-}
-
 bool Layer::setMetadata(const LayerMetadata& data) {
     if (!mCurrentState.metadata.merge(data, true /* eraseEmpty */)) return false;
     mCurrentState.sequence++;
@@ -1463,7 +1473,6 @@
 }
 
 void Layer::setFrameTimelineVsyncForTransaction(int64_t frameTimelineVsyncId, nsecs_t postTime) {
-    mCurrentState.sequence++;
     mCurrentState.frameTimelineVsyncId = frameTimelineVsyncId;
     mCurrentState.postTime = postTime;
     mCurrentState.modified = true;
@@ -2175,6 +2184,10 @@
     return getDrawingState().backgroundBlurRadius;
 }
 
+const std::vector<BlurRegion>& Layer::getBlurRegions() const {
+    return getDrawingState().blurRegions;
+}
+
 Layer::RoundedCornerState Layer::getRoundedCornerState() const {
     const auto& p = mDrawingParent.promote();
     if (p != nullptr) {
@@ -2454,6 +2467,7 @@
         ySurfaceInset = std::round(ySurfaceInset * yScale);
     }
 
+    // Transform the layer bounds from layer coordinate space to display coordinate space.
     Rect transformedLayerBounds = t.transform(layerBounds);
 
     // clamp inset to layer bounds
@@ -2478,7 +2492,7 @@
         transformedLayerBounds.bottom = tmp;
     }
 
-    // Input coordinate should match the layer bounds.
+    // Input coordinates should be in display coordinate space.
     info.frameLeft = transformedLayerBounds.left;
     info.frameTop = transformedLayerBounds.top;
     info.frameRight = transformedLayerBounds.right;
@@ -2491,7 +2505,7 @@
     // the final frame calculated.
     // 1. Take the original transform set on the window and get the inverse transform. This is
     //    used to get the final bounds in display space (ignorning the transform). Apply the
-    //    inverse transform on the layerBounds to get the untransformed frame (in display space)
+    //    inverse transform on the layerBounds to get the untransformed frame (in layer space)
     // 2. Take the top and left of the untransformed frame to get the real position on screen.
     //    Apply the layer transform on top/left so it includes any scale or rotation. These will
     //    be the new translation values for the transform.
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2321247..5cb56a5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -26,6 +26,7 @@
 #include <renderengine/Mesh.h>
 #include <renderengine/Texture.h>
 #include <sys/types.h>
+#include <ui/BlurRegion.h>
 #include <ui/FloatRect.h>
 #include <ui/FrameStats.h>
 #include <ui/GraphicBuffer.h>
@@ -255,6 +256,9 @@
         // be rendered around the layer.
         float shadowRadius;
 
+        // Layer regions that are made of custom materials, like frosted glass
+        std::vector<BlurRegion> blurRegions;
+
         // Priority of the layer assigned by Window Manager.
         int32_t frameRateSelectionPriority;
 
@@ -341,7 +345,6 @@
     //
     // The first set of geometry functions are controlled by the scaling mode, described
     // in window.h. The scaling mode may be set by the client, as it submits buffers.
-    // This value may be overriden through SurfaceControl, with setOverrideScalingMode.
     //
     // Put simply, if our scaling mode is SCALING_MODE_FREEZE, then
     // matrix updates will not be applied while a resize is pending
@@ -392,6 +395,7 @@
     // When non-zero, everything below this layer will be blurred by backgroundBlurRadius, which
     // is specified in pixels.
     virtual bool setBackgroundBlurRadius(int backgroundBlurRadius);
+    virtual bool setBlurRegions(const std::vector<BlurRegion>& effectRegions);
     virtual bool setTransparentRegionHint(const Region& transparent);
     virtual bool setFlags(uint8_t flags, uint8_t mask);
     virtual bool setLayerStack(uint32_t layerStack);
@@ -399,7 +403,6 @@
     virtual void deferTransactionUntil_legacy(const sp<IBinder>& barrierHandle,
                                               uint64_t frameNumber);
     virtual void deferTransactionUntil_legacy(const sp<Layer>& barrierLayer, uint64_t frameNumber);
-    virtual bool setOverrideScalingMode(int32_t overrideScalingMode);
     virtual bool setMetadata(const LayerMetadata& data);
     virtual void setChildrenDrawingParent(const sp<Layer>&);
     virtual bool reparent(const sp<IBinder>& newParentHandle);
@@ -467,7 +470,7 @@
     virtual bool canReceiveInput() const;
 
     /*
-     * isProtected - true if the layer may contain protected content in the
+     * isProtected - true if the layer may contain protected contents in the
      * GRALLOC_USAGE_PROTECTED sense.
      */
     virtual bool isProtected() const { return false; }
@@ -679,7 +682,8 @@
 
     /*
      * isSecure - true if this surface is secure, that is if it prevents
-     * screenshots or VNC servers.
+     * screenshots or VNC servers. A surface can be set to be secure by the
+     * application, being secure doesn't mean the surface has DRM contents.
      */
     bool isSecure() const;
 
@@ -1003,7 +1007,6 @@
     bool mIsActiveBufferUpdatedForGpu = true;
 
     // We encode unset as -1.
-    int32_t mOverrideScalingMode{-1};
     std::atomic<uint64_t> mCurrentFrameNumber{0};
     // Whether filtering is needed b/c of the drawingstate
     bool mNeedsFiltering{false};
@@ -1080,7 +1083,8 @@
     sp<Layer> getRootLayer();
 
     // Cached properties computed from drawing state
-    // Effective transform taking into account parent transforms and any parent scaling.
+    // Effective transform taking into account parent transforms and any parent scaling, which is
+    // a transform from the current layer coordinate space to display(screen) coordinate space.
     ui::Transform mEffectiveTransform;
 
     // Bounds of the layer before any transformation is applied and before it has been cropped
@@ -1111,6 +1115,9 @@
     // final shadow radius for this layer. If a shadow is specified for a layer, then effective
     // shadow radius is the set shadow radius, otherwise its the parent's shadow radius.
     float mEffectiveShadowRadius = 0.f;
+
+    // A list of regions on this layer that should have blurs.
+    const std::vector<BlurRegion>& getBlurRegions() const;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index e6c8654..053b7f7 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -29,13 +29,12 @@
 
 LayerRejecter::LayerRejecter(Layer::State& front, Layer::State& current,
                              bool& recomputeVisibleRegions, bool stickySet, const std::string& name,
-                             int32_t overrideScalingMode, bool transformToDisplayInverse)
+                             bool transformToDisplayInverse)
       : mFront(front),
         mCurrent(current),
         mRecomputeVisibleRegions(recomputeVisibleRegions),
         mStickyTransformSet(stickySet),
         mName(name),
-        mOverrideScalingMode(overrideScalingMode),
         mTransformToDisplayInverse(transformToDisplayInverse) {}
 
 bool LayerRejecter::reject(const sp<GraphicBuffer>& buf, const BufferItem& item) {
@@ -59,7 +58,7 @@
         }
     }
 
-    int actualScalingMode = mOverrideScalingMode >= 0 ? mOverrideScalingMode : item.mScalingMode;
+    int actualScalingMode = item.mScalingMode;
     bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
     if (mFront.active_legacy != mFront.requested_legacy) {
         if (isFixedSize ||
diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h
index fb5c750..4981f45 100644
--- a/services/surfaceflinger/LayerRejecter.h
+++ b/services/surfaceflinger/LayerRejecter.h
@@ -24,7 +24,7 @@
 class LayerRejecter : public BufferLayerConsumer::BufferRejecter {
 public:
     LayerRejecter(Layer::State& front, Layer::State& current, bool& recomputeVisibleRegions,
-                  bool stickySet, const std::string& name, int32_t overrideScalingMode,
+                  bool stickySet, const std::string& name,
                   bool transformToDisplayInverse);
 
     virtual bool reject(const sp<GraphicBuffer>&, const BufferItem&);
@@ -35,7 +35,6 @@
     bool& mRecomputeVisibleRegions;
     const bool mStickyTransformSet;
     const std::string& mName;
-    const int32_t mOverrideScalingMode;
     const bool mTransformToDisplayInverse;
 };
 
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
index a90d05e..2783800 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.cpp
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
@@ -20,6 +20,21 @@
 #include <sstream>
 #include <thread>
 
+namespace {
+using namespace std::chrono_literals;
+
+constexpr int64_t kNsToSeconds = std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count();
+
+// The syscall interface uses a pair of integers for the timestamp. The first
+// (tv_sec) is the whole count of seconds. The second (tv_nsec) is the
+// nanosecond part of the count. This function takes care of translation.
+void calculateTimeoutTime(std::chrono::nanoseconds timestamp, timespec* spec) {
+    clock_gettime(CLOCK_MONOTONIC, spec);
+    spec->tv_sec += static_cast<__kernel_time_t>(timestamp.count() / kNsToSeconds);
+    spec->tv_nsec += timestamp.count() % kNsToSeconds;
+}
+} // namespace
+
 namespace android {
 namespace scheduler {
 
@@ -32,81 +47,95 @@
 }
 
 void OneShotTimer::start() {
-    {
-        std::lock_guard<std::mutex> lock(mMutex);
-        mState = TimerState::RESET;
+    sem_init(&mSemaphore, 0, 0);
+
+    if (!mThread.joinable()) {
+        // Only create thread if it has not been created.
+        mThread = std::thread(&OneShotTimer::loop, this);
     }
-    mThread = std::thread(&OneShotTimer::loop, this);
 }
 
 void OneShotTimer::stop() {
-    {
-        std::lock_guard<std::mutex> lock(mMutex);
-        mState = TimerState::STOPPED;
-    }
-    mCondition.notify_all();
+    mStopTriggered = true;
+    sem_post(&mSemaphore);
+
     if (mThread.joinable()) {
         mThread.join();
+        sem_destroy(&mSemaphore);
     }
 }
 
 void OneShotTimer::loop() {
+    TimerState state = TimerState::RESET;
     while (true) {
         bool triggerReset = false;
         bool triggerTimeout = false;
-        {
-            std::lock_guard<std::mutex> lock(mMutex);
-            if (mState == TimerState::STOPPED) {
-                break;
-            }
 
-            if (mState == TimerState::IDLE) {
-                mCondition.wait(mMutex);
-                continue;
-            }
-
-            if (mState == TimerState::RESET) {
-                triggerReset = true;
-            }
+        state = checkForResetAndStop(state);
+        if (state == TimerState::STOPPED) {
+            break;
         }
+
+        if (state == TimerState::IDLE) {
+            sem_wait(&mSemaphore);
+            continue;
+        }
+
+        if (state == TimerState::RESET) {
+            triggerReset = true;
+        }
+
         if (triggerReset && mResetCallback) {
             mResetCallback();
         }
 
-        { // lock the mutex again. someone might have called stop meanwhile
-            std::lock_guard<std::mutex> lock(mMutex);
-            if (mState == TimerState::STOPPED) {
-                break;
-            }
+        state = checkForResetAndStop(state);
+        if (state == TimerState::STOPPED) {
+            break;
+        }
 
-            auto triggerTime = std::chrono::steady_clock::now() + mInterval;
-            mState = TimerState::WAITING;
-            while (mState == TimerState::WAITING) {
-                constexpr auto zero = std::chrono::steady_clock::duration::zero();
-                auto waitTime = triggerTime - std::chrono::steady_clock::now();
-                if (waitTime > zero) mCondition.wait_for(mMutex, waitTime);
-                if (mState == TimerState::RESET) {
-                    triggerTime = std::chrono::steady_clock::now() + mInterval;
-                    mState = TimerState::WAITING;
-                } else if (mState == TimerState::WAITING &&
-                           (triggerTime - std::chrono::steady_clock::now()) <= zero) {
-                    triggerTimeout = true;
-                    mState = TimerState::IDLE;
-                }
+        auto triggerTime = std::chrono::steady_clock::now() + mInterval;
+        state = TimerState::WAITING;
+        while (state == TimerState::WAITING) {
+            constexpr auto zero = std::chrono::steady_clock::duration::zero();
+            // Wait for mInterval time for semaphore signal.
+            struct timespec ts;
+            calculateTimeoutTime(std::chrono::nanoseconds(mInterval), &ts);
+            sem_clockwait(&mSemaphore, CLOCK_MONOTONIC, &ts);
+
+            state = checkForResetAndStop(state);
+            if (state == TimerState::RESET) {
+                triggerTime = std::chrono::steady_clock::now() + mInterval;
+                state = TimerState::WAITING;
+            } else if (state == TimerState::WAITING &&
+                       (triggerTime - std::chrono::steady_clock::now()) <= zero) {
+                triggerTimeout = true;
+                state = TimerState::IDLE;
             }
         }
+
         if (triggerTimeout && mTimeoutCallback) {
             mTimeoutCallback();
         }
     }
 }
 
-void OneShotTimer::reset() {
-    {
-        std::lock_guard<std::mutex> lock(mMutex);
-        mState = TimerState::RESET;
+OneShotTimer::TimerState OneShotTimer::checkForResetAndStop(TimerState state) {
+    // Stop takes precedence of the reset.
+    if (mStopTriggered.exchange(false)) {
+        return TimerState::STOPPED;
     }
-    mCondition.notify_all();
+    // If the state was stopped, the thread was joined, and we cannot reset
+    // the timer anymore.
+    if (state != TimerState::STOPPED && mResetTriggered.exchange(false)) {
+        return TimerState::RESET;
+    }
+    return state;
+}
+
+void OneShotTimer::reset() {
+    mResetTriggered = true;
+    sem_post(&mSemaphore);
 }
 
 std::string OneShotTimer::dump() const {
diff --git a/services/surfaceflinger/Scheduler/OneShotTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h
index b005754..8bbd4f5 100644
--- a/services/surfaceflinger/Scheduler/OneShotTimer.h
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <semaphore.h>
 #include <chrono>
 #include <condition_variable>
 #include <thread>
@@ -70,17 +71,15 @@
     // Function that loops until the condition for stopping is met.
     void loop();
 
+    // Checks whether mResetTriggered and mStopTriggered were set and updates
+    // mState if so.
+    TimerState checkForResetAndStop(TimerState state);
+
     // Thread waiting for timer to expire.
     std::thread mThread;
 
-    // Condition used to notify mThread.
-    std::condition_variable_any mCondition;
-
-    // Lock used for synchronizing the waiting thread with the application thread.
-    std::mutex mMutex;
-
-    // Current timer state
-    TimerState mState GUARDED_BY(mMutex) = TimerState::RESET;
+    // Semaphore to keep mThread synchronized.
+    sem_t mSemaphore;
 
     // Interval after which timer expires.
     const Interval mInterval;
@@ -90,6 +89,12 @@
 
     // Callback that happens when timer expires.
     const TimeoutCallback mTimeoutCallback;
+
+    // After removing lock guarding mState, the state can be now accessed at
+    // any time. Keep a bool if the reset or stop were requested, and occasionally
+    // check in the main loop if they were.
+    std::atomic<bool> mResetTriggered = false;
+    std::atomic<bool> mStopTriggered = false;
 };
 
 } // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 8661b6e..7ab49a9 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -48,6 +48,13 @@
     }
 }
 
+std::string RefreshRateConfigs::Policy::toString() {
+    return base::StringPrintf("default config ID: %d, allowGroupSwitching = %d"
+                              ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]",
+                              defaultConfig.value(), allowGroupSwitching, primaryRange.min,
+                              primaryRange.max, appRequestRange.min, appRequestRange.max);
+}
+
 const RefreshRate& RefreshRateConfigs::getRefreshRateForContent(
         const std::vector<LayerRequirement>& layers) const {
     std::lock_guard lock(mLock);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index eed8486..280ed62 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -108,6 +108,10 @@
             std::unordered_map<HwcConfigIndexType, std::unique_ptr<const RefreshRate>>;
 
     struct Policy {
+    private:
+        static constexpr int kAllowGroupSwitchingDefault = false;
+
+    public:
         struct Range {
             float min = 0;
             float max = std::numeric_limits<float>::max();
@@ -122,6 +126,8 @@
         // The default config, used to ensure we only initiate display config switches within the
         // same config group as defaultConfigId's group.
         HwcConfigIndexType defaultConfig;
+        // Whether or not we switch config groups to get the best frame rate.
+        bool allowGroupSwitching = kAllowGroupSwitchingDefault;
         // The primary refresh rate range represents display manager's general guidance on the
         // display configs we'll consider when switching refresh rates. Unless we get an explicit
         // signal from an app, we should stay within this range.
@@ -133,15 +139,23 @@
         // app request range. The app request range will be greater than or equal to the primary
         // refresh rate range, never smaller.
         Range appRequestRange;
-        // Whether or not we switch config groups to get the best frame rate. Only used by tests.
-        bool allowGroupSwitching = false;
 
         Policy() = default;
+
         Policy(HwcConfigIndexType defaultConfig, const Range& range)
-              : Policy(defaultConfig, range, range) {}
+              : Policy(defaultConfig, kAllowGroupSwitchingDefault, range, range) {}
+
+        Policy(HwcConfigIndexType defaultConfig, bool allowGroupSwitching, const Range& range)
+              : Policy(defaultConfig, allowGroupSwitching, range, range) {}
+
         Policy(HwcConfigIndexType defaultConfig, const Range& primaryRange,
                const Range& appRequestRange)
+              : Policy(defaultConfig, kAllowGroupSwitchingDefault, primaryRange, appRequestRange) {}
+
+        Policy(HwcConfigIndexType defaultConfig, bool allowGroupSwitching,
+               const Range& primaryRange, const Range& appRequestRange)
               : defaultConfig(defaultConfig),
+                allowGroupSwitching(allowGroupSwitching),
                 primaryRange(primaryRange),
                 appRequestRange(appRequestRange) {}
 
@@ -152,6 +166,7 @@
         }
 
         bool operator!=(const Policy& other) const { return !(*this == other); }
+        std::string toString();
     };
 
     // Return code set*Policy() to indicate the current policy is unchanged.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 31c380e..fde38c9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -357,7 +357,9 @@
 
     hasWideColorDisplay = has_wide_color_display(false);
 
-    useColorManagement = use_color_management(false);
+    // Android 12 and beyond, color management in display pipeline is turned on
+    // by default.
+    useColorManagement = use_color_management(true);
 
     mDefaultCompositionDataspace =
             static_cast<ui::Dataspace>(default_composition_dataspace(Dataspace::V0_SRGB));
@@ -1041,7 +1043,12 @@
         } else {
             const HwcConfigIndexType config(mode);
             const float fps = mRefreshRateConfigs->getRefreshRateFromConfigId(config).getFps();
-            const scheduler::RefreshRateConfigs::Policy policy{config, {fps, fps}};
+            // Keep the old switching type.
+            const auto allowGroupSwitching =
+                    mRefreshRateConfigs->getCurrentPolicy().allowGroupSwitching;
+            const scheduler::RefreshRateConfigs::Policy policy{config,
+                                                               allowGroupSwitching,
+                                                               {fps, fps}};
             constexpr bool kOverridePolicy = false;
 
             return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
@@ -1848,16 +1855,18 @@
 
     bool refreshNeeded;
     {
-        ConditionalLockGuard<std::mutex> lock(mTracingLock, mTracingEnabled);
+        mTracePostComposition = mTracing.flagIsSet(SurfaceTracing::TRACE_COMPOSITION) ||
+                mTracing.flagIsSet(SurfaceTracing::TRACE_SYNC) ||
+                mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS);
+        const bool tracePreComposition = mTracingEnabled && !mTracePostComposition;
+        ConditionalLockGuard<std::mutex> lock(mTracingLock, tracePreComposition);
 
         mFrameTimeline->setSfWakeUp(vsyncId, frameStart);
 
         refreshNeeded = handleMessageTransaction();
         refreshNeeded |= handleMessageInvalidate();
-        if (mTracingEnabled) {
-            mAddCompositionStateToTrace =
-                    mTracing.flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION);
-            if (mVisibleRegionsDirty && !mAddCompositionStateToTrace) {
+        if (tracePreComposition) {
+            if (mVisibleRegionsDirty) {
                 mTracing.notifyLocked("visibleRegionsDirty");
             }
         }
@@ -2007,12 +2016,15 @@
     modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition);
 
     mLayersWithQueuedFrames.clear();
-    if (mVisibleRegionsDirty) {
-        mVisibleRegionsDirty = false;
-        if (mTracingEnabled && mAddCompositionStateToTrace) {
+    if (mTracingEnabled && mTracePostComposition) {
+        // This may block if SurfaceTracing is running in sync mode.
+        if (mVisibleRegionsDirty) {
             mTracing.notify("visibleRegionsDirty");
+        } else if (mTracing.flagIsSet(SurfaceTracing::TRACE_BUFFERS)) {
+            mTracing.notify("bufferLatched");
         }
     }
+    mVisibleRegionsDirty = false;
 
     if (mCompositionEngine->needsAnotherUpdate()) {
         signalLayerUpdate();
@@ -2313,7 +2325,7 @@
 
 void SurfaceFlinger::processDisplayHotplugEventsLocked() {
     for (const auto& event : mPendingHotplugEvents) {
-        const std::optional<DisplayIdentificationInfo> info =
+        std::optional<DisplayIdentificationInfo> info =
                 getHwComposer().onHotplug(event.hwcDisplayId, event.connection);
 
         if (!info) {
@@ -2335,9 +2347,9 @@
                 state.physical = {.id = displayId,
                                   .type = getHwComposer().getDisplayConnectionType(displayId),
                                   .hwcDisplayId = event.hwcDisplayId,
-                                  .deviceProductInfo = info->deviceProductInfo};
+                                  .deviceProductInfo = std::move(info->deviceProductInfo)};
                 state.isSecure = true; // All physical displays are currently considered secure.
-                state.displayName = info->name;
+                state.displayName = std::move(info->name);
 
                 sp<IBinder> token = new BBinder();
                 mCurrentState.displays.add(token, state);
@@ -2349,7 +2361,10 @@
 
                 const auto token = it->second;
                 auto& state = mCurrentState.displays.editValueFor(token);
-                state.sequenceId = DisplayDeviceState{}.sequenceId;
+                state.sequenceId = DisplayDeviceState{}.sequenceId; // Generate new sequenceId
+                if (getHwComposer().updatesDeviceProductInfoOnHotplugReconnect()) {
+                    state.physical->deviceProductInfo = std::move(info->deviceProductInfo);
+                }
             }
         } else {
             ALOGV("Removing display %s", to_string(displayId).c_str());
@@ -3669,6 +3684,9 @@
     if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs && mSupportsBlur) {
         if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded;
     }
+    if (what & layer_state_t::eBlurRegionsChanged) {
+        if (layer->setBlurRegions(s.blurRegions)) flags |= eTraversalNeeded;
+    }
     if (what & layer_state_t::eLayerStackChanged) {
         ssize_t idx = mCurrentState.layersSortedByZ.indexOf(layer);
         // We only allow setting layer stacks for top level layers,
@@ -3703,11 +3721,6 @@
     if (what & layer_state_t::eDetachChildren) {
         layer->detachChildren();
     }
-    if (what & layer_state_t::eOverrideScalingModeChanged) {
-        layer->setOverrideScalingMode(s.overrideScalingMode);
-        // We don't trigger a traversal here because if no other state is
-        // changed, we don't want this to cause any more work
-    }
     if (what & layer_state_t::eTransformChanged) {
         if (layer->setTransform(s.transform)) flags |= eTraversalNeeded;
     }
@@ -3772,6 +3785,13 @@
             flags |= eTraversalNeeded;
         }
     }
+    if (what & layer_state_t::eFrameTimelineVsyncChanged) {
+        layer->setFrameTimelineVsyncForTransaction(s.frameTimelineVsyncId, postTime);
+    } else {
+        // TODO (b/171252403) We are calling this too much, potentially triggering
+        // unnecessary work
+        layer->setFrameTimelineVsyncForTransaction(frameTimelineVsyncId, postTime);
+    }
     if (what & layer_state_t::eFixedTransformHintChanged) {
         if (layer->setFixedTransformHint(s.fixedTransformHint)) {
             flags |= eTraversalNeeded | eTransformHintUpdateNeeded;
@@ -3831,8 +3851,6 @@
         }
     }
 
-    layer->setFrameTimelineVsyncForTransaction(frameTimelineVsyncId, postTime);
-
     if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
     // Do not put anything that updates layer state or modifies flags after
     // setTransactionCompletedListener
@@ -4274,7 +4292,7 @@
 
 status_t SurfaceFlinger::dumpCritical(int fd, const DumpArgs&, bool asProto) {
     if (asProto && mTracing.isEnabled()) {
-        mTracing.writeToFileAsync();
+        mTracing.writeToFile();
     }
 
     return doDump(fd, DumpArgs(), asProto);
@@ -4358,21 +4376,14 @@
                   dispSyncPresentTimeOffset, getVsyncPeriodFromHWC());
 
     scheduler::RefreshRateConfigs::Policy policy = mRefreshRateConfigs->getDisplayManagerPolicy();
-    StringAppendF(&result,
-                  "DesiredDisplayConfigSpecs (DisplayManager): default config ID: %d"
-                  ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
-                  policy.defaultConfig.value(), policy.primaryRange.min, policy.primaryRange.max,
-                  policy.appRequestRange.min, policy.appRequestRange.max);
+    StringAppendF(&result, "DesiredDisplayConfigSpecs (DisplayManager): %s\n\n",
+                  policy.toString().c_str());
     StringAppendF(&result, "(config override by backdoor: %s)\n\n",
                   mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
     scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
     if (currentPolicy != policy) {
-        StringAppendF(&result,
-                      "DesiredDisplayConfigSpecs (Override): default config ID: %d"
-                      ", primary range: [%.2f %.2f], app request range: [%.2f %.2f]\n\n",
-                      currentPolicy.defaultConfig.value(), currentPolicy.primaryRange.min,
-                      currentPolicy.primaryRange.max, currentPolicy.appRequestRange.min,
-                      currentPolicy.appRequestRange.max);
+        StringAppendF(&result, "DesiredDisplayConfigSpecs (Override): %s\n\n",
+                      currentPolicy.toString().c_str());
     }
 
     mScheduler->dump(mAppConnectionHandle, result);
@@ -5098,19 +5109,19 @@
             }
             case 1025: { // Set layer tracing
                 n = data.readInt32();
+                bool tracingEnabledChanged;
                 if (n) {
                     ALOGD("LayerTracing enabled");
-                    mTracingEnabledChanged = mTracing.enable();
-                    reply->writeInt32(NO_ERROR);
+                    tracingEnabledChanged = mTracing.enable();
+                    if (tracingEnabledChanged) {
+                        schedule([&]() MAIN_THREAD { mTracing.notify("start"); }).wait();
+                    }
                 } else {
                     ALOGD("LayerTracing disabled");
-                    mTracingEnabledChanged = mTracing.disable();
-                    if (mTracingEnabledChanged) {
-                        reply->writeInt32(mTracing.writeToFile());
-                    } else {
-                        reply->writeInt32(NO_ERROR);
-                    }
+                    tracingEnabledChanged = mTracing.disable();
                 }
+                mTracingEnabledChanged = tracingEnabledChanged;
+                reply->writeInt32(NO_ERROR);
                 return NO_ERROR;
             }
             case 1026: { // Get layer tracing status
@@ -5383,6 +5394,45 @@
     return PERMISSION_DENIED;
 }
 
+status_t SurfaceFlinger::setSchedFifo(bool enabled) {
+    static constexpr int kFifoPriority = 2;
+    static constexpr int kOtherPriority = 0;
+
+    struct sched_param param = {0};
+    int sched_policy;
+    if (enabled) {
+        sched_policy = SCHED_FIFO;
+        param.sched_priority = kFifoPriority;
+    } else {
+        sched_policy = SCHED_OTHER;
+        param.sched_priority = kOtherPriority;
+    }
+
+    if (sched_setscheduler(0, sched_policy, &param) != 0) {
+        return -errno;
+    }
+    return NO_ERROR;
+}
+
+sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) {
+    if (const sp<IBinder> displayToken =
+                getPhysicalDisplayTokenLocked(PhysicalDisplayId{displayOrLayerStack})) {
+        return getDisplayDeviceLocked(displayToken);
+    }
+    // Couldn't find display by displayId. Try to get display by layerStack since virtual displays
+    // may not have a displayId.
+    return getDisplayByLayerStack(displayOrLayerStack);
+}
+
+sp<DisplayDevice> SurfaceFlinger::getDisplayByLayerStack(uint64_t layerStack) {
+    for (const auto& [token, display] : mDisplays) {
+        if (display->getLayerStack() == layerStack) {
+            return display;
+        }
+    }
+    return nullptr;
+}
+
 status_t SurfaceFlinger::captureDisplay(const DisplayCaptureArgs& args,
                                         const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
@@ -5431,46 +5481,7 @@
     };
 
     return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
-                               args.pixelFormat, captureListener);
-}
-
-status_t SurfaceFlinger::setSchedFifo(bool enabled) {
-    static constexpr int kFifoPriority = 2;
-    static constexpr int kOtherPriority = 0;
-
-    struct sched_param param = {0};
-    int sched_policy;
-    if (enabled) {
-        sched_policy = SCHED_FIFO;
-        param.sched_priority = kFifoPriority;
-    } else {
-        sched_policy = SCHED_OTHER;
-        param.sched_priority = kOtherPriority;
-    }
-
-    if (sched_setscheduler(0, sched_policy, &param) != 0) {
-        return -errno;
-    }
-    return NO_ERROR;
-}
-
-sp<DisplayDevice> SurfaceFlinger::getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) {
-    if (const sp<IBinder> displayToken =
-                getPhysicalDisplayTokenLocked(PhysicalDisplayId{displayOrLayerStack})) {
-        return getDisplayDeviceLocked(displayToken);
-    }
-    // Couldn't find display by displayId. Try to get display by layerStack since virtual displays
-    // may not have a displayId.
-    return getDisplayByLayerStack(displayOrLayerStack);
-}
-
-sp<DisplayDevice> SurfaceFlinger::getDisplayByLayerStack(uint64_t layerStack) {
-    for (const auto& [token, display] : mDisplays) {
-        if (display->getLayerStack() == layerStack) {
-            return display;
-        }
-    }
-    return nullptr;
+                               args.pixelFormat, args.allowProtected, captureListener);
 }
 
 status_t SurfaceFlinger::captureDisplay(uint64_t displayOrLayerStack,
@@ -5505,7 +5516,8 @@
     };
 
     return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, size,
-                               ui::PixelFormat::RGBA_8888, captureListener);
+                               ui::PixelFormat::RGBA_8888, false /* allowProtected */,
+                               captureListener);
 }
 
 status_t SurfaceFlinger::captureLayers(const LayerCaptureArgs& args,
@@ -5626,18 +5638,32 @@
     };
 
     return captureScreenCommon(std::move(renderAreaFuture), traverseLayers, reqSize,
-                               args.pixelFormat, captureListener);
+                               args.pixelFormat, args.allowProtected, captureListener);
 }
 
 status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
                                              TraverseLayersFunction traverseLayers,
                                              ui::Size bufferSize, ui::PixelFormat reqPixelFormat,
+                                             const bool allowProtected,
                                              const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
 
-    // TODO(b/116112787) Make buffer usage a parameter.
-    const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
-            GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+    // Loop over all visible layers to see whether there's any protected layer. A protected layer is
+    // typically a layer with DRM contents, or have the GRALLOC_USAGE_PROTECTED set on the buffer.
+    // A protected layer has no implication on whether it's secure, which is explicitly set by
+    // application to avoid being screenshot or drawn via unsecure display.
+    const bool supportsProtected = getRenderEngine().supportsProtectedContent();
+    bool hasProtectedLayer = false;
+    if (allowProtected && supportsProtected) {
+        traverseLayers([&](Layer* layer) {
+            hasProtectedLayer = hasProtectedLayer || (layer->isVisible() && layer->isProtected());
+        });
+    }
+
+    const uint32_t usage = GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE |
+            (hasProtectedLayer && allowProtected && supportsProtected
+                     ? GRALLOC_USAGE_PROTECTED
+                     : GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
     sp<GraphicBuffer> buffer =
             getFactory().createGraphicBuffer(bufferSize.getWidth(), bufferSize.getHeight(),
                                              static_cast<android_pixel_format>(reqPixelFormat),
@@ -5648,7 +5674,7 @@
 
 status_t SurfaceFlinger::captureScreenCommon(RenderAreaFuture renderAreaFuture,
                                              TraverseLayersFunction traverseLayers,
-                                             sp<GraphicBuffer>& buffer, bool regionSampling,
+                                             sp<GraphicBuffer>& buffer, const bool regionSampling,
                                              const sp<IScreenCaptureListener>& captureListener) {
     ATRACE_CALL();
 
@@ -5706,6 +5732,8 @@
                 captureResults.capturedSecureLayers || (layer->isVisible() && layer->isSecure());
     });
 
+    const bool useProtected = buffer->getUsage() & GRALLOC_USAGE_PROTECTED;
+
     // We allow the system server to take screenshots of secure layers for
     // use in situations like the Screen-rotation animation and place
     // the impetus on WindowManager to not persist them.
@@ -5750,14 +5778,13 @@
     std::vector<Layer*> renderedLayers;
     Region clearRegion = Region::INVALID_REGION;
     traverseLayers([&](Layer* layer) {
-        const bool supportProtectedContent = false;
         Region clip(renderArea.getBounds());
         compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
                 clip,
                 layer->needsFilteringForScreenshots(display.get(), transform) ||
                         renderArea.needsFiltering(),
                 renderArea.isSecure(),
-                supportProtectedContent,
+                useProtected,
                 clearRegion,
                 layerStackSpaceRect,
                 clientCompositionDisplay.outputDataspace,
@@ -5795,7 +5822,7 @@
     // there is no need for synchronization with the GPU.
     base::unique_fd bufferFence;
     base::unique_fd drawFence;
-    getRenderEngine().useProtectedContext(false);
+    getRenderEngine().useProtectedContext(useProtected);
     getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buffer,
                                  /*useFramebufferCache=*/false, std::move(bufferFence), &drawFence);
 
@@ -5807,6 +5834,8 @@
             layer->onLayerDisplayed(releaseFence);
         }
     }
+    // Always switch back to unprotected context.
+    getRenderEngine().useProtectedContext(false);
 
     return NO_ERROR;
 }
@@ -5948,12 +5977,10 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                      int32_t defaultConfig,
-                                                      float primaryRefreshRateMin,
-                                                      float primaryRefreshRateMax,
-                                                      float appRequestRefreshRateMin,
-                                                      float appRequestRefreshRateMax) {
+status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(
+        const sp<IBinder>& displayToken, int32_t defaultConfig, bool allowGroupSwitching,
+        float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin,
+        float appRequestRefreshRateMax) {
     ATRACE_CALL();
 
     if (!displayToken) {
@@ -5972,6 +5999,7 @@
         } else {
             using Policy = scheduler::RefreshRateConfigs::Policy;
             const Policy policy{HwcConfigIndexType(defaultConfig),
+                                allowGroupSwitching,
                                 {primaryRefreshRateMin, primaryRefreshRateMax},
                                 {appRequestRefreshRateMin, appRequestRefreshRateMax}};
             constexpr bool kOverridePolicy = false;
@@ -5983,12 +6011,10 @@
     return future.get();
 }
 
-status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                      int32_t* outDefaultConfig,
-                                                      float* outPrimaryRefreshRateMin,
-                                                      float* outPrimaryRefreshRateMax,
-                                                      float* outAppRequestRefreshRateMin,
-                                                      float* outAppRequestRefreshRateMax) {
+status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(
+        const sp<IBinder>& displayToken, int32_t* outDefaultConfig, bool* outAllowGroupSwitching,
+        float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax,
+        float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) {
     ATRACE_CALL();
 
     if (!displayToken || !outDefaultConfig || !outPrimaryRefreshRateMin ||
@@ -6006,6 +6032,7 @@
         scheduler::RefreshRateConfigs::Policy policy =
                 mRefreshRateConfigs->getDisplayManagerPolicy();
         *outDefaultConfig = policy.defaultConfig.value();
+        *outAllowGroupSwitching = policy.allowGroupSwitching;
         *outPrimaryRefreshRateMin = policy.primaryRange.min;
         *outPrimaryRefreshRateMax = policy.primaryRange.max;
         *outAppRequestRefreshRateMin = policy.appRequestRange.min;
@@ -6016,6 +6043,7 @@
     } else {
         const auto displayId = display->getPhysicalId();
         *outDefaultConfig = getHwComposer().getActiveConfigIndex(displayId);
+        *outAllowGroupSwitching = false;
         auto vsyncPeriod = getHwComposer().getActiveConfig(displayId)->getVsyncPeriod();
         *outPrimaryRefreshRateMin = 1e9f / vsyncPeriod;
         *outPrimaryRefreshRateMax = 1e9f / vsyncPeriod;
@@ -6146,8 +6174,8 @@
             // This is a little racy, but not in a way that hurts anything. As we grab the
             // defaultConfig from the display manager policy, we could be setting a new display
             // manager policy, leaving us using a stale defaultConfig. The defaultConfig doesn't
-            // matter for the override policy though, since we set allowGroupSwitching to true, so
-            // it's not a problem.
+            // matter for the override policy though, since we set allowGroupSwitching to
+            // true, so it's not a problem.
             scheduler::RefreshRateConfigs::Policy overridePolicy;
             overridePolicy.defaultConfig =
                     mRefreshRateConfigs->getDisplayManagerPolicy().defaultConfig;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f55dd90..a821d44 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -583,11 +583,12 @@
                                        const sp<IRegionSamplingListener>& listener) override;
     status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
     status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, int32_t displayModeId,
-                                          float primaryRefreshRateMin, float primaryRefreshRateMax,
+                                          bool allowGroupSwitching, float primaryRefreshRateMin,
+                                          float primaryRefreshRateMax,
                                           float appRequestRefreshRateMin,
                                           float appRequestRefreshRateMax) override;
     status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                          int32_t* outDefaultConfig,
+                                          int32_t* outDefaultConfig, bool* outAllowGroupSwitching,
                                           float* outPrimaryRefreshRateMin,
                                           float* outPrimaryRefreshRateMax,
                                           float* outAppRequestRefreshRateMin,
@@ -797,13 +798,14 @@
     // Boot animation, on/off animations and screen capture
     void startBootAnim();
 
+    status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize,
+                                 ui::PixelFormat, const bool allowProtected,
+                                 const sp<IScreenCaptureListener>&);
+    status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp<GraphicBuffer>&,
+                                 bool regionSampling, const sp<IScreenCaptureListener>&);
     status_t renderScreenImplLocked(const RenderArea&, TraverseLayersFunction,
                                     const sp<GraphicBuffer>&, bool forSystem, int* outSyncFd,
                                     bool regionSampling, ScreenCaptureResults&);
-    status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, ui::Size bufferSize,
-                                 ui::PixelFormat, const sp<IScreenCaptureListener>&);
-    status_t captureScreenCommon(RenderAreaFuture, TraverseLayersFunction, sp<GraphicBuffer>&,
-                                 bool regionSampling, const sp<IScreenCaptureListener>&);
 
     sp<DisplayDevice> getDisplayByIdOrLayerStack(uint64_t displayOrLayerStack) REQUIRES(mStateLock);
     sp<DisplayDevice> getDisplayByLayerStack(uint64_t layerStack) REQUIRES(mStateLock);
@@ -1133,7 +1135,7 @@
     SurfaceTracing mTracing{*this};
     std::mutex mTracingLock;
     bool mTracingEnabled = false;
-    bool mAddCompositionStateToTrace = false;
+    bool mTracePostComposition = false;
     std::atomic<bool> mTracingEnabledChanged = false;
 
     const std::shared_ptr<TimeStats> mTimeStats;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index 9d78702..97725ec 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -371,5 +371,10 @@
     return primaries;
 }
 
+bool update_device_product_info_on_hotplug_reconnect(bool defaultValue) {
+    return SurfaceFlingerProperties::update_device_product_info_on_hotplug_reconnect().value_or(
+            defaultValue);
+}
+
 } // namespace sysprop
 } // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index c63adfe..37a6b40 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -95,6 +95,9 @@
 int32_t display_update_imminent_timeout_ms(int32_t defaultValue);
 
 android::ui::DisplayPrimaries getDisplayNativePrimaries();
+
+bool update_device_product_info_on_hotplug_reconnect(bool defaultValue);
+
 } // namespace sysprop
 } // namespace android
 #endif // SURFACEFLINGERPROPERTIES_H_
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index da58d4e..3548923 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -140,12 +140,12 @@
     addCropLocked(transaction, layerId, layer->mCurrentState.crop_legacy);
     addCornerRadiusLocked(transaction, layerId, layer->mCurrentState.cornerRadius);
     addBackgroundBlurRadiusLocked(transaction, layerId, layer->mCurrentState.backgroundBlurRadius);
+    addBlurRegionsLocked(transaction, layerId, layer->mCurrentState.blurRegions);
     if (layer->mCurrentState.barrierLayer_legacy != nullptr) {
         addDeferTransactionLocked(transaction, layerId,
                                   layer->mCurrentState.barrierLayer_legacy.promote(),
                                   layer->mCurrentState.barrierFrameNumber);
     }
-    addOverrideScalingModeLocked(transaction, layerId, layer->getEffectiveScalingMode());
     addFlagsLocked(transaction, layerId, layer->mCurrentState.flags,
                    layer_state_t::eLayerHidden | layer_state_t::eLayerOpaque |
                            layer_state_t::eLayerSecure);
@@ -362,6 +362,25 @@
     blurRadiusChange->set_background_blur_radius(backgroundBlurRadius);
 }
 
+void SurfaceInterceptor::addBlurRegionsLocked(Transaction* transaction, int32_t layerId,
+                                              const std::vector<BlurRegion>& blurRegions) {
+    SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
+    BlurRegionsChange* blurRegionsChange(change->mutable_blur_regions());
+    for (const auto blurRegion : blurRegions) {
+        const auto blurRegionChange = blurRegionsChange->add_blur_regions();
+        blurRegionChange->set_blur_radius(blurRegion.blurRadius);
+        blurRegionChange->set_corner_radius_tl(blurRegion.cornerRadiusTL);
+        blurRegionChange->set_corner_radius_tr(blurRegion.cornerRadiusTR);
+        blurRegionChange->set_corner_radius_bl(blurRegion.cornerRadiusBL);
+        blurRegionChange->set_corner_radius_br(blurRegion.cornerRadiusBR);
+        blurRegionChange->set_alpha(blurRegion.alpha);
+        blurRegionChange->set_left(blurRegion.left);
+        blurRegionChange->set_top(blurRegion.top);
+        blurRegionChange->set_right(blurRegion.right);
+        blurRegionChange->set_bottom(blurRegion.bottom);
+    }
+}
+
 void SurfaceInterceptor::addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
         const sp<const Layer>& layer, uint64_t frameNumber)
 {
@@ -376,14 +395,6 @@
     deferTransaction->set_frame_number(frameNumber);
 }
 
-void SurfaceInterceptor::addOverrideScalingModeLocked(Transaction* transaction,
-        int32_t layerId, int32_t overrideScalingMode)
-{
-    SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
-    OverrideScalingModeChange* overrideChange(change->mutable_override_scaling_mode());
-    overrideChange->set_override_scaling_mode(overrideScalingMode);
-}
-
 void SurfaceInterceptor::addReparentLocked(Transaction* transaction, int32_t layerId,
                                            int32_t parentId) {
     SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
@@ -465,6 +476,9 @@
     if (state.what & layer_state_t::eBackgroundBlurRadiusChanged) {
         addBackgroundBlurRadiusLocked(transaction, layerId, state.backgroundBlurRadius);
     }
+    if (state.what & layer_state_t::eBlurRegionsChanged) {
+        addBlurRegionsLocked(transaction, layerId, state.blurRegions);
+    }
     if (state.what & layer_state_t::eDeferTransaction_legacy) {
         sp<Layer> otherLayer = nullptr;
         if (state.barrierSurfaceControl_legacy != nullptr) {
@@ -474,9 +488,6 @@
         }
         addDeferTransactionLocked(transaction, layerId, otherLayer, state.barrierFrameNumber);
     }
-    if (state.what & layer_state_t::eOverrideScalingModeChanged) {
-        addOverrideScalingModeLocked(transaction, layerId, state.overrideScalingMode);
-    }
     if (state.what & layer_state_t::eReparent) {
         auto parentHandle = (state.parentSurfaceControlForChild)
                 ? state.parentSurfaceControlForChild->getHandle()
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 9ac189a..3df79c6 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -165,10 +165,10 @@
     void addCornerRadiusLocked(Transaction* transaction, int32_t layerId, float cornerRadius);
     void addBackgroundBlurRadiusLocked(Transaction* transaction, int32_t layerId,
                                        int32_t backgroundBlurRadius);
+    void addBlurRegionsLocked(Transaction* transaction, int32_t layerId,
+                              const std::vector<BlurRegion>& effectRegions);
     void addDeferTransactionLocked(Transaction* transaction, int32_t layerId,
             const sp<const Layer>& layer, uint64_t frameNumber);
-    void addOverrideScalingModeLocked(Transaction* transaction, int32_t layerId,
-            int32_t overrideScalingMode);
     void addSurfaceChangesLocked(Transaction* transaction, const layer_state_t& state);
     void addTransactionLocked(Increment* increment, const Vector<ComposerState>& stateUpdates,
                               const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index d84ce69..1d1f0c5 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -14,9 +14,6 @@
  * limitations under the License.
  */
 
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
 #undef LOG_TAG
 #define LOG_TAG "SurfaceTracing"
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
@@ -32,65 +29,65 @@
 
 namespace android {
 
-SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger)
-      : mFlinger(flinger), mSfLock(flinger.mTracingLock) {}
+SurfaceTracing::SurfaceTracing(SurfaceFlinger& flinger) : mFlinger(flinger) {}
 
-void SurfaceTracing::mainLoop() {
-    bool enabled = addFirstEntry();
-    while (enabled) {
-        LayersTraceProto entry = traceWhenNotified();
-        enabled = addTraceToBuffer(entry);
-    }
-}
-
-bool SurfaceTracing::addFirstEntry() {
-    LayersTraceProto entry;
-    {
-        std::scoped_lock lock(mSfLock);
-        entry = traceLayersLocked("tracing.enable");
-    }
-    return addTraceToBuffer(entry);
-}
-
-LayersTraceProto SurfaceTracing::traceWhenNotified() {
-    std::unique_lock<std::mutex> lock(mSfLock);
-    mCanStartTrace.wait(lock);
-    android::base::ScopedLockAssertion assumeLock(mSfLock);
-    LayersTraceProto entry = traceLayersLocked(mWhere);
-    mTracingInProgress = false;
-    mMissedTraceEntries = 0;
-    lock.unlock();
-    return entry;
-}
-
-bool SurfaceTracing::addTraceToBuffer(LayersTraceProto& entry) {
+bool SurfaceTracing::enable() {
     std::scoped_lock lock(mTraceLock);
-    mBuffer.emplace(std::move(entry));
-    if (mWriteToFile) {
-        writeProtoFileLocked();
-        mWriteToFile = false;
+    if (mEnabled) {
+        return false;
     }
+
+    if (flagIsSet(TRACE_SYNC)) {
+        runner = std::make_unique<SurfaceTracing::Runner>(mFlinger, mConfig);
+    } else {
+        runner = std::make_unique<SurfaceTracing::AsyncRunner>(mFlinger, mConfig,
+                                                               mFlinger.mTracingLock);
+    }
+    mEnabled = true;
+    return true;
+}
+
+bool SurfaceTracing::disable() {
+    std::scoped_lock lock(mTraceLock);
+    if (!mEnabled) {
+        return false;
+    }
+    mEnabled = false;
+    runner->stop();
+    return true;
+}
+
+bool SurfaceTracing::isEnabled() const {
+    std::scoped_lock lock(mTraceLock);
     return mEnabled;
 }
 
+status_t SurfaceTracing::writeToFile() {
+    std::scoped_lock lock(mTraceLock);
+    if (!mEnabled) {
+        return STATUS_OK;
+    }
+    return runner->writeToFile();
+}
+
 void SurfaceTracing::notify(const char* where) {
-    std::scoped_lock lock(mSfLock);
-    notifyLocked(where);
+    if (mEnabled) {
+        runner->notify(where);
+    }
 }
 
 void SurfaceTracing::notifyLocked(const char* where) {
-    mWhere = where;
-    if (mTracingInProgress) {
-        mMissedTraceEntries++;
+    if (mEnabled) {
+        runner->notifyLocked(where);
     }
-    mTracingInProgress = true;
-    mCanStartTrace.notify_one();
 }
 
-void SurfaceTracing::writeToFileAsync() {
+void SurfaceTracing::dump(std::string& result) const {
     std::scoped_lock lock(mTraceLock);
-    mWriteToFile = true;
-    mCanStartTrace.notify_one();
+    base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
+    if (mEnabled) {
+        runner->dump(result);
+    }
 }
 
 void SurfaceTracing::LayersTraceBuffer::reset(size_t newSize) {
@@ -101,12 +98,12 @@
 }
 
 void SurfaceTracing::LayersTraceBuffer::emplace(LayersTraceProto&& proto) {
-    auto protoSize = proto.ByteSize();
+    size_t protoSize = static_cast<size_t>(proto.ByteSize());
     while (mUsedInBytes + protoSize > mSizeInBytes) {
         if (mStorage.empty()) {
             return;
         }
-        mUsedInBytes -= mStorage.front().ByteSize();
+        mUsedInBytes -= static_cast<size_t>(mStorage.front().ByteSize());
         mStorage.pop();
     }
     mUsedInBytes += protoSize;
@@ -115,7 +112,7 @@
 }
 
 void SurfaceTracing::LayersTraceBuffer::flush(LayersTraceFileProto* fileProto) {
-    fileProto->mutable_entry()->Reserve(mStorage.size());
+    fileProto->mutable_entry()->Reserve(static_cast<int>(mStorage.size()));
 
     while (!mStorage.empty()) {
         auto entry = fileProto->add_entry();
@@ -124,85 +121,21 @@
     }
 }
 
-bool SurfaceTracing::enable() {
-    std::scoped_lock lock(mTraceLock);
-
-    if (mEnabled) {
-        return false;
-    }
-
-    mBuffer.reset(mBufferSize);
-    mEnabled = true;
-    mThread = std::thread(&SurfaceTracing::mainLoop, this);
-    return true;
+SurfaceTracing::Runner::Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config)
+      : mFlinger(flinger), mConfig(config) {
+    mBuffer.setSize(mConfig.bufferSize);
 }
 
-status_t SurfaceTracing::writeToFile() {
-    std::thread thread;
-    {
-        std::scoped_lock lock(mTraceLock);
-        thread = std::move(mThread);
-    }
-    thread.join();
-    return mLastErr;
+void SurfaceTracing::Runner::notify(const char* where) {
+    LayersTraceProto entry = traceLayers(where);
+    mBuffer.emplace(std::move(entry));
 }
 
-bool SurfaceTracing::disable() {
-    std::scoped_lock lock(mTraceLock);
-
-    if (!mEnabled) {
-        return false;
-    }
-
-    mEnabled = false;
-    mWriteToFile = true;
-    mCanStartTrace.notify_all();
-    return true;
+status_t SurfaceTracing::Runner::stop() {
+    return writeToFile();
 }
 
-bool SurfaceTracing::isEnabled() const {
-    std::scoped_lock lock(mTraceLock);
-    return mEnabled;
-}
-
-void SurfaceTracing::setBufferSize(size_t bufferSizeInByte) {
-    std::scoped_lock lock(mTraceLock);
-    mBufferSize = bufferSizeInByte;
-    mBuffer.setSize(bufferSizeInByte);
-}
-
-void SurfaceTracing::setTraceFlags(uint32_t flags) {
-    std::scoped_lock lock(mSfLock);
-    mTraceFlags = flags;
-}
-
-LayersTraceProto SurfaceTracing::traceLayersLocked(const char* where) {
-    ATRACE_CALL();
-
-    LayersTraceProto entry;
-    entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
-    entry.set_where(where);
-    LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags));
-
-    if (flagIsSetLocked(SurfaceTracing::TRACE_EXTRA)) {
-        mFlinger.dumpOffscreenLayersProto(layers);
-    }
-    entry.mutable_layers()->Swap(&layers);
-
-    if (mTraceFlags & SurfaceTracing::TRACE_HWC) {
-        std::string hwcDump;
-        mFlinger.dumpHwc(hwcDump);
-        entry.set_hwc_blob(hwcDump);
-    }
-    if (!flagIsSetLocked(SurfaceTracing::TRACE_COMPOSITION)) {
-        entry.set_excludes_composition_state(true);
-    }
-    entry.set_missed_entries(mMissedTraceEntries);
-
-    return entry;
-}
-
-void SurfaceTracing::writeProtoFileLocked() {
+status_t SurfaceTracing::Runner::writeToFile() {
     ATRACE_CALL();
 
     LayersTraceFileProto fileProto;
@@ -211,33 +144,114 @@
     fileProto.set_magic_number(uint64_t(LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_H) << 32 |
                                LayersTraceFileProto_MagicNumber_MAGIC_NUMBER_L);
     mBuffer.flush(&fileProto);
-    mBuffer.reset(mBufferSize);
+    mBuffer.reset(mConfig.bufferSize);
 
     if (!fileProto.SerializeToString(&output)) {
         ALOGE("Could not save the proto file! Permission denied");
-        mLastErr = PERMISSION_DENIED;
+        return PERMISSION_DENIED;
     }
 
     // -rw-r--r--
     const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
-    if (!android::base::WriteStringToFile(output, kDefaultFileName, mode, getuid(), getgid(),
+    if (!android::base::WriteStringToFile(output, DEFAULT_FILE_NAME, mode, getuid(), getgid(),
                                           true)) {
         ALOGE("Could not save the proto file! There are missing fields");
-        mLastErr = PERMISSION_DENIED;
+        return PERMISSION_DENIED;
     }
 
-    mLastErr = NO_ERROR;
+    return NO_ERROR;
 }
 
-void SurfaceTracing::dump(std::string& result) const {
-    std::scoped_lock lock(mTraceLock);
-    base::StringAppendF(&result, "Tracing state: %s\n", mEnabled ? "enabled" : "disabled");
+LayersTraceProto SurfaceTracing::Runner::traceLayers(const char* where) {
+    ATRACE_CALL();
+
+    LayersTraceProto entry;
+    entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
+    entry.set_where(where);
+    LayersProto layers(mFlinger.dumpDrawingStateProto(mConfig.flags));
+
+    if (flagIsSet(SurfaceTracing::TRACE_EXTRA)) {
+        mFlinger.dumpOffscreenLayersProto(layers);
+    }
+    entry.mutable_layers()->Swap(&layers);
+
+    if (flagIsSet(SurfaceTracing::TRACE_HWC)) {
+        std::string hwcDump;
+        mFlinger.dumpHwc(hwcDump);
+        entry.set_hwc_blob(hwcDump);
+    }
+    if (!flagIsSet(SurfaceTracing::TRACE_COMPOSITION)) {
+        entry.set_excludes_composition_state(true);
+    }
+    entry.set_missed_entries(mMissedTraceEntries);
+
+    return entry;
+}
+
+void SurfaceTracing::Runner::dump(std::string& result) const {
     base::StringAppendF(&result, "  number of entries: %zu (%.2fMB / %.2fMB)\n",
                         mBuffer.frameCount(), float(mBuffer.used()) / float(1_MB),
                         float(mBuffer.size()) / float(1_MB));
 }
 
-} // namespace android
+SurfaceTracing::AsyncRunner::AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config,
+                                         std::mutex& sfLock)
+      : SurfaceTracing::Runner(flinger, config), mSfLock(sfLock) {
+    mEnabled = true;
+    mThread = std::thread(&AsyncRunner::loop, this);
+}
 
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion"
+void SurfaceTracing::AsyncRunner::loop() {
+    while (mEnabled) {
+        LayersTraceProto entry;
+        bool entryAdded = traceWhenNotified(&entry);
+        if (entryAdded) {
+            mBuffer.emplace(std::move(entry));
+        }
+        if (mWriteToFile) {
+            Runner::writeToFile();
+            mWriteToFile = false;
+        }
+    }
+}
+
+bool SurfaceTracing::AsyncRunner::traceWhenNotified(LayersTraceProto* outProto) {
+    std::unique_lock<std::mutex> lock(mSfLock);
+    mCanStartTrace.wait(lock);
+    if (!mAddEntry) {
+        return false;
+    }
+    *outProto = traceLayers(mWhere);
+    mAddEntry = false;
+    mMissedTraceEntries = 0;
+    return true;
+}
+
+void SurfaceTracing::AsyncRunner::notify(const char* where) {
+    std::scoped_lock lock(mSfLock);
+    notifyLocked(where);
+}
+
+void SurfaceTracing::AsyncRunner::notifyLocked(const char* where) {
+    mWhere = where;
+    if (mAddEntry) {
+        mMissedTraceEntries++;
+    }
+    mAddEntry = true;
+    mCanStartTrace.notify_one();
+}
+
+status_t SurfaceTracing::AsyncRunner::writeToFile() {
+    mWriteToFile = true;
+    mCanStartTrace.notify_one();
+    return STATUS_OK;
+}
+
+status_t SurfaceTracing::AsyncRunner::stop() {
+    mEnabled = false;
+    mCanStartTrace.notify_one();
+    mThread.join();
+    return Runner::writeToFile();
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index f208eb8..576bba7 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -32,25 +32,31 @@
 namespace android {
 
 class SurfaceFlinger;
-
 constexpr auto operator""_MB(unsigned long long const num) {
     return num * 1024 * 1024;
 }
 /*
- * SurfaceTracing records layer states during surface flinging.
+ * SurfaceTracing records layer states during surface flinging. Manages tracing state and
+ * configuration.
  */
 class SurfaceTracing {
 public:
-    explicit SurfaceTracing(SurfaceFlinger& flinger);
+    SurfaceTracing(SurfaceFlinger& flinger);
     bool enable();
     bool disable();
     status_t writeToFile();
     bool isEnabled() const;
+    /*
+     * Adds a trace entry, must be called from the drawing thread or while holding the
+     * SurfaceFlinger tracing lock.
+     */
     void notify(const char* where);
-    void notifyLocked(const char* where) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */;
+    /*
+     * Adds a trace entry, called while holding the SurfaceFlinger tracing lock.
+     */
+    void notifyLocked(const char* where) /* REQUIRES(mSfLock) */;
 
-    void setBufferSize(size_t bufferSizeInByte);
-    void writeToFileAsync();
+    void setBufferSize(size_t bufferSizeInBytes) { mConfig.bufferSize = bufferSizeInBytes; }
     void dump(std::string& result) const;
 
     enum : uint32_t {
@@ -59,18 +65,34 @@
         TRACE_COMPOSITION = 1 << 2,
         TRACE_EXTRA = 1 << 3,
         TRACE_HWC = 1 << 4,
-        TRACE_ALL = 0xffffffff
+        // Add non-geometry composition changes to the trace.
+        TRACE_BUFFERS = 1 << 5,
+        // Add entries from the drawing thread post composition.
+        TRACE_SYNC = 1 << 6,
+        TRACE_ALL = TRACE_CRITICAL | TRACE_INPUT | TRACE_COMPOSITION | TRACE_EXTRA,
     };
-    void setTraceFlags(uint32_t flags);
-    bool flagIsSetLocked(uint32_t flags) NO_THREAD_SAFETY_ANALYSIS /* REQUIRES(mSfLock) */ {
-        return (mTraceFlags & flags) == flags;
-    }
+    void setTraceFlags(uint32_t flags) { mConfig.flags = flags; }
+    bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; }
 
 private:
-    static constexpr auto kDefaultBufferCapInByte = 5_MB;
-    static constexpr auto kDefaultFileName = "/data/misc/wmtrace/layers_trace.pb";
+    class Runner;
+    static constexpr auto DEFAULT_BUFFER_SIZE = 5_MB;
+    static constexpr auto DEFAULT_FILE_NAME = "/data/misc/wmtrace/layers_trace.pb";
 
-    class LayersTraceBuffer { // ring buffer
+    SurfaceFlinger& mFlinger;
+    mutable std::mutex mTraceLock;
+    bool mEnabled = false;
+    std::unique_ptr<Runner> runner;
+
+    struct Config {
+        uint32_t flags = TRACE_CRITICAL | TRACE_INPUT;
+        size_t bufferSize = DEFAULT_BUFFER_SIZE;
+    } mConfig;
+
+    /*
+     * ring buffer.
+     */
+    class LayersTraceBuffer {
     public:
         size_t size() const { return mSizeInBytes; }
         size_t used() const { return mUsedInBytes; }
@@ -83,35 +105,59 @@
 
     private:
         size_t mUsedInBytes = 0U;
-        size_t mSizeInBytes = 0U;
+        size_t mSizeInBytes = DEFAULT_BUFFER_SIZE;
         std::queue<LayersTraceProto> mStorage;
     };
 
-    void mainLoop();
-    bool addFirstEntry();
-    LayersTraceProto traceWhenNotified();
-    LayersTraceProto traceLayersLocked(const char* where) REQUIRES(mSfLock);
+    /*
+     * Implements a synchronous way of adding trace entries. This must be called
+     * from the drawing thread.
+     */
+    class Runner {
+    public:
+        Runner(SurfaceFlinger& flinger, SurfaceTracing::Config& config);
+        virtual ~Runner() = default;
+        virtual status_t stop();
+        virtual status_t writeToFile();
+        virtual void notify(const char* where);
+        /* Cannot be called with a synchronous runner. */
+        virtual void notifyLocked(const char* /* where */) {}
+        void dump(std::string& result) const;
 
-    // Returns true if trace is enabled.
-    bool addTraceToBuffer(LayersTraceProto& entry);
-    void writeProtoFileLocked() REQUIRES(mTraceLock);
+    protected:
+        bool flagIsSet(uint32_t flags) { return (mConfig.flags & flags) == flags; }
+        SurfaceFlinger& mFlinger;
+        SurfaceTracing::Config mConfig;
+        SurfaceTracing::LayersTraceBuffer mBuffer;
+        uint32_t mMissedTraceEntries = 0;
+        LayersTraceProto traceLayers(const char* where);
+    };
 
-    SurfaceFlinger& mFlinger;
-    status_t mLastErr = NO_ERROR;
-    std::thread mThread;
-    std::condition_variable mCanStartTrace;
+    /*
+     * Implements asynchronous way to add trace entries called from a separate thread while holding
+     * the SurfaceFlinger tracing lock. Trace entries may be missed if the tracing thread is not
+     * scheduled in time.
+     */
+    class AsyncRunner : public Runner {
+    public:
+        AsyncRunner(SurfaceFlinger& flinger, SurfaceTracing::Config& config, std::mutex& sfLock);
+        virtual ~AsyncRunner() = default;
+        status_t stop() override;
+        status_t writeToFile() override;
+        void notify(const char* where) override;
+        void notifyLocked(const char* where);
 
-    std::mutex& mSfLock;
-    uint32_t mTraceFlags GUARDED_BY(mSfLock) = TRACE_CRITICAL | TRACE_INPUT;
-    const char* mWhere GUARDED_BY(mSfLock) = "";
-    uint32_t mMissedTraceEntries GUARDED_BY(mSfLock) = 0;
-    bool mTracingInProgress GUARDED_BY(mSfLock) = false;
-
-    mutable std::mutex mTraceLock;
-    LayersTraceBuffer mBuffer GUARDED_BY(mTraceLock);
-    size_t mBufferSize GUARDED_BY(mTraceLock) = kDefaultBufferCapInByte;
-    bool mEnabled GUARDED_BY(mTraceLock) = false;
-    bool mWriteToFile GUARDED_BY(mTraceLock) = false;
+    private:
+        std::mutex& mSfLock;
+        std::condition_variable mCanStartTrace;
+        std::thread mThread;
+        const char* mWhere = "";
+        bool mWriteToFile = false;
+        bool mEnabled = false;
+        bool mAddEntry = false;
+        void loop();
+        bool traceWhenNotified(LayersTraceProto* outProto);
+    };
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index f3f5626..9f25674 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -125,6 +125,9 @@
   int32 background_blur_radius = 52;
 
   uint32 owner_uid = 53;
+
+  // Regions of a layer, where blur should be applied.
+  repeated BlurRegion blur_regions = 54;
 }
 
 message PositionProto {
@@ -211,3 +214,16 @@
   // This will be a 4x4 matrix of float values
   repeated float val = 1;
 }
+
+message BlurRegion {
+    uint32 blur_radius = 1;
+    uint32 corner_radius_tl = 2;
+    uint32 corner_radius_tr = 3;
+    uint32 corner_radius_bl = 4;
+    float corner_radius_br = 5;
+    float alpha = 6;
+    int32 left = 7;
+    int32 top = 8;
+    int32 right = 9;
+    int32 bottom = 10;
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/layerproto/layerstrace.proto b/services/surfaceflinger/layerproto/layerstrace.proto
index acf621e..990f3cf 100644
--- a/services/surfaceflinger/layerproto/layerstrace.proto
+++ b/services/surfaceflinger/layerproto/layerstrace.proto
@@ -42,7 +42,7 @@
 /* one window manager trace entry. */
 message LayersTraceProto {
     /* required: elapsed realtime in nanos since boot of when this entry was logged */
-    optional fixed64 elapsed_realtime_nanos = 1;
+    optional sfixed64 elapsed_realtime_nanos = 1;
 
     /* where the trace originated */
     optional string where = 2;
@@ -56,5 +56,5 @@
     optional bool excludes_composition_state = 5;
 
     /* Number of missed entries since the last entry was recorded. */
-    optional int32 missed_entries = 6;
+    optional uint32 missed_entries = 6;
 }
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 7666f7f..421484f 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -435,3 +435,13 @@
     access: Readonly
     prop_name: "ro.surface_flinger.display_update_imminent_timeout_ms"
 }
+
+
+# Updates the DeviceProductInfo when a hoplug reconnect event is processed
+prop {
+    api_name: "update_device_product_info_on_hotplug_reconnect"
+    type: Boolean
+    scope: Public
+    access: Readonly
+    prop_name: "ro.surface_flinger.update_device_product_info_on_hotplug_reconnect"
+}
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index ba60a7d..da66ece 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -124,6 +124,10 @@
     prop_name: "ro.surface_flinger.supports_background_blur"
   }
   prop {
+    api_name: "update_device_product_info_on_hotplug_reconnect"
+    prop_name: "ro.surface_flinger.update_device_product_info_on_hotplug_reconnect"
+  }
+  prop {
     api_name: "use_color_management"
     prop_name: "ro.surface_flinger.use_color_management"
   }
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index db5d820..02b4308 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -50,7 +50,7 @@
         "android.hardware.graphics.composer@2.1",
     ],
     shared_libs: [
-        "android.hardware.graphics.common-ndk_platform",
+        "android.hardware.graphics.common-unstable-ndk_platform",
         "android.hardware.graphics.common@1.2",
         "libandroid",
         "libbase",
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index 7f541e2..9302463 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -218,18 +218,21 @@
 TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
     const auto display = SurfaceComposerClient::getInternalDisplayToken();
     int32_t defaultConfig;
+    bool allowGroupSwitching;
     float primaryFpsMin;
     float primaryFpsMax;
     float appRequestFpsMin;
     float appRequestFpsMax;
     status_t res =
             SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
+                                                                &allowGroupSwitching,
                                                                 &primaryFpsMin, &primaryFpsMax,
                                                                 &appRequestFpsMin,
                                                                 &appRequestFpsMax);
     ASSERT_EQ(res, NO_ERROR);
     std::function<status_t()> condition = [=]() {
         return SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, defaultConfig,
+                                                                   allowGroupSwitching,
                                                                    primaryFpsMin, primaryFpsMax,
                                                                    appRequestFpsMin,
                                                                    appRequestFpsMax);
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index debfe83..3a8b40f 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -14,16 +14,18 @@
  * 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/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <private/gui/ComposerService.h>
+#include <ui/DisplayConfig.h>
+#include <utils/Errors.h>
+#include <utils/Vector.h>
 
-#include <thread>
-#include "LayerTransactionTest.h"
+#include "utils/TransactionUtils.h"
+
 namespace android {
 
-using android::hardware::graphics::common::V1_1::BufferUsage;
-
 ::testing::Environment* const binderEnv =
         ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
 
@@ -31,32 +33,54 @@
  * Test class for setting display configs and passing around refresh rate ranges.
  */
 class RefreshRateRangeTest : public ::testing::Test {
+private:
+    int32_t initialDefaultConfig;
+    bool initialAllowGroupSwitching;
+    float initialPrimaryMin;
+    float initialPrimaryMax;
+    float initialAppRequestMin;
+    float initialAppRequestMax;
+
 protected:
-    void SetUp() override { mDisplayToken = SurfaceComposerClient::getInternalDisplayToken(); }
+    void SetUp() override {
+        mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
+        status_t res =
+                SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
+                                                                    &initialDefaultConfig,
+                                                                    &initialAllowGroupSwitching,
+                                                                    &initialPrimaryMin,
+                                                                    &initialPrimaryMax,
+                                                                    &initialAppRequestMin,
+                                                                    &initialAppRequestMax);
+        ASSERT_EQ(res, NO_ERROR);
+    }
+
+    void TearDown() override {
+        status_t res =
+                SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken,
+                                                                    initialDefaultConfig,
+                                                                    initialAllowGroupSwitching,
+                                                                    initialPrimaryMin,
+                                                                    initialPrimaryMax,
+                                                                    initialAppRequestMin,
+                                                                    initialAppRequestMax);
+        ASSERT_EQ(res, NO_ERROR);
+    }
+
+    void testSetAllowGroupSwitching(bool allowGroupSwitching);
 
     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);
+    status_t res = SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &configs);
     ASSERT_EQ(res, NO_ERROR);
+    ASSERT_GT(configs.size(), 0);
 
     for (size_t i = 0; i < configs.size(); i++) {
-        res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, i,
+        res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken,
+                                                                  static_cast<int32_t>(i), false,
                                                                   configs[i].refreshRate,
                                                                   configs[i].refreshRate,
                                                                   configs[i].refreshRate,
@@ -64,31 +88,58 @@
         ASSERT_EQ(res, NO_ERROR);
 
         int defaultConfig;
+        bool allowGroupSwitching;
         float primaryRefreshRateMin;
         float primaryRefreshRateMax;
         float appRequestRefreshRateMin;
         float appRequestRefreshRateMax;
         res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
+                                                                  &allowGroupSwitching,
                                                                   &primaryRefreshRateMin,
                                                                   &primaryRefreshRateMax,
                                                                   &appRequestRefreshRateMin,
                                                                   &appRequestRefreshRateMax);
         ASSERT_EQ(res, NO_ERROR);
         ASSERT_EQ(defaultConfig, i);
+        ASSERT_EQ(allowGroupSwitching, false);
         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);
+void RefreshRateRangeTest::testSetAllowGroupSwitching(bool allowGroupSwitching) {
+    status_t res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, 0,
+                                                                       allowGroupSwitching, 0.f,
+                                                                       90.f, 0.f, 90.f);
     ASSERT_EQ(res, NO_ERROR);
+    int defaultConfig;
+    bool newAllowGroupSwitching;
+    float primaryRefreshRateMin;
+    float primaryRefreshRateMax;
+    float appRequestRefreshRateMin;
+    float appRequestRefreshRateMax;
+
+    res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
+                                                              &newAllowGroupSwitching,
+                                                              &primaryRefreshRateMin,
+                                                              &primaryRefreshRateMax,
+                                                              &appRequestRefreshRateMin,
+                                                              &appRequestRefreshRateMax);
+    ASSERT_EQ(res, NO_ERROR);
+    ASSERT_EQ(defaultConfig, 0);
+    ASSERT_EQ(newAllowGroupSwitching, allowGroupSwitching);
+    ASSERT_EQ(primaryRefreshRateMin, 0.f);
+    ASSERT_EQ(primaryRefreshRateMax, 90.f);
+    ASSERT_EQ(appRequestRefreshRateMin, 0.f);
+    ASSERT_EQ(appRequestRefreshRateMax, 90.f);
+}
+
+TEST_F(RefreshRateRangeTest, setAllowGroupSwitching) {
+    testSetAllowGroupSwitching(true);
+    testSetAllowGroupSwitching(false);
+    testSetAllowGroupSwitching(true);
 }
 
 } // 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
index 3dca391..fafb49e 100644
--- a/services/surfaceflinger/tests/EffectLayer_test.cpp
+++ b/services/surfaceflinger/tests/EffectLayer_test.cpp
@@ -51,7 +51,7 @@
     sp<SurfaceControl> effectLayer =
             mClient->createSurface(String8("Effect Layer"), 0 /* width */, 0 /* height */,
                                    PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceEffect,
-                                   mParentLayer.get());
+                                   mParentLayer->getHandle());
 
     EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
     asTransaction([&](Transaction& t) {
@@ -72,7 +72,7 @@
                                    PIXEL_FORMAT_RGBA_8888,
                                    ISurfaceComposerClient::eFXSurfaceEffect |
                                            ISurfaceComposerClient::eNoColorFill,
-                                   mParentLayer.get());
+                                   mParentLayer->getHandle());
 
     EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
     asTransaction([&](Transaction& t) {
@@ -93,7 +93,7 @@
                                    PIXEL_FORMAT_RGBA_8888,
                                    ISurfaceComposerClient::eFXSurfaceEffect |
                                            ISurfaceComposerClient::eNoColorFill,
-                                   mParentLayer.get());
+                                   mParentLayer->getHandle());
 
     EXPECT_NE(nullptr, effectLayer.get()) << "failed to create SurfaceControl";
     asTransaction([&](Transaction& t) {
diff --git a/services/surfaceflinger/tests/InvalidHandles_test.cpp b/services/surfaceflinger/tests/InvalidHandles_test.cpp
index cfec0d2..152d2d2 100644
--- a/services/surfaceflinger/tests/InvalidHandles_test.cpp
+++ b/services/surfaceflinger/tests/InvalidHandles_test.cpp
@@ -56,7 +56,7 @@
     auto notSc = makeNotSurfaceControl();
     ASSERT_EQ(nullptr,
               mScc->createSurface(String8("lolcats"), 19, 47, PIXEL_FORMAT_RGBA_8888, 0,
-                                  notSc.get())
+                                  notSc->getHandle())
                       .get());
 }
 
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 4947289..52e1a4d 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -179,19 +179,6 @@
     }
 }
 
-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;
@@ -950,40 +937,6 @@
     }
 }
 
-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));
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index d4e952a..da71dad 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -16,6 +16,10 @@
 
 #pragma once
 
+// 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/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
@@ -75,8 +79,9 @@
                                              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);
+        sp<IBinder> parentHandle = (parent) ? parent->getHandle() : nullptr;
+        auto layer = client->createSurface(String8(name), width, height, format, flags,
+                                           parentHandle, LayerMetadata(), outTransformHint);
         EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
         return layer;
     }
@@ -299,3 +304,6 @@
 };
 
 } // 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/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index 38da0b1..29473f2 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -566,7 +566,10 @@
     }
 
     asTransaction([&](Transaction& t) {
-        t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        mFGSurfaceControl->getSurface()->setScalingMode(
+            NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        // Resubmit buffer with new scaling mode
+        TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
         // We cause scaling by 2.
         t.setSize(mFGSurfaceControl, 128, 128);
     });
@@ -673,7 +676,10 @@
     }
 
     asTransaction([&](Transaction& t) {
-        t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        mFGSurfaceControl->getSurface()->setScalingMode(
+            NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        // Resubmit buffer with new scaling mode
+        TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
         // Set a scaling by 2.
         t.setSize(mFGSurfaceControl, 128, 128);
     });
@@ -705,7 +711,10 @@
 
     // 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);
+        mFGSurfaceControl->getSurface()->setScalingMode(
+            NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+        // Resubmit buffer with new scaling mode
+        TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
         t.setSize(mFGSurfaceControl, 128, 64);
     });
     sp<Surface> s = mFGSurfaceControl->getSurface();
@@ -1019,12 +1028,13 @@
 TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) {
     sp<SurfaceControl> boundlessLayer =
             mClient->createSurface(String8("BoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
-                                   0 /* flags */, mFGSurfaceControl.get());
+                                   0 /* flags */, mFGSurfaceControl->getHandle());
     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());
+                                   ISurfaceComposerClient::eFXSurfaceEffect,
+                                   boundlessLayer->getHandle());
     ASSERT_TRUE(colorLayer != nullptr);
     ASSERT_TRUE(colorLayer->isValid());
     asTransaction([&](Transaction& t) {
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 104d919..81e648a 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -39,7 +39,6 @@
 using Trace = surfaceflinger::Trace;
 using Increment = surfaceflinger::Increment;
 
-constexpr int32_t SCALING_UPDATE = 1;
 constexpr uint32_t BUFFER_UPDATES = 18;
 constexpr uint32_t LAYER_UPDATE = INT_MAX - 2;
 constexpr uint32_t SIZE_UPDATE = 134;
@@ -52,6 +51,7 @@
 constexpr float POSITION_UPDATE = 121;
 const Rect CROP_UPDATE(16, 16, 32, 32);
 const float SHADOW_RADIUS_UPDATE = 35.0f;
+std::vector<BlurRegion> BLUR_REGIONS_UPDATE;
 
 const String8 DISPLAY_NAME("SurfaceInterceptor Display Test");
 constexpr auto TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface";
@@ -182,6 +182,7 @@
     bool cornerRadiusUpdateFound(const SurfaceChange& change, bool foundCornerRadius);
     bool backgroundBlurRadiusUpdateFound(const SurfaceChange& change,
                                          bool foundBackgroundBlurRadius);
+    bool blurRegionsUpdateFound(const SurfaceChange& change, bool foundBlurRegions);
     bool matrixUpdateFound(const SurfaceChange& change, bool foundMatrix);
     bool scalingModeUpdateFound(const SurfaceChange& change, bool foundScalingMode);
     bool transparentRegionHintUpdateFound(const SurfaceChange& change, bool foundTransparentRegion);
@@ -220,8 +221,8 @@
     void cropUpdate(Transaction&);
     void cornerRadiusUpdate(Transaction&);
     void backgroundBlurRadiusUpdate(Transaction&);
+    void blurRegionsUpdate(Transaction&);
     void matrixUpdate(Transaction&);
-    void overrideScalingModeUpdate(Transaction&);
     void transparentRegionHintUpdate(Transaction&);
     void layerStackUpdate(Transaction&);
     void hiddenFlagUpdate(Transaction&);
@@ -359,6 +360,12 @@
     t.setBackgroundBlurRadius(mBGSurfaceControl, BACKGROUND_BLUR_RADIUS_UPDATE);
 }
 
+void SurfaceInterceptorTest::blurRegionsUpdate(Transaction& t) {
+    BLUR_REGIONS_UPDATE.empty();
+    BLUR_REGIONS_UPDATE.push_back(BlurRegion());
+    t.setBlurRegions(mBGSurfaceControl, BLUR_REGIONS_UPDATE);
+}
+
 void SurfaceInterceptorTest::layerUpdate(Transaction& t) {
     t.setLayer(mBGSurfaceControl, LAYER_UPDATE);
 }
@@ -371,10 +378,6 @@
     t.setMatrix(mBGSurfaceControl, M_SQRT1_2, M_SQRT1_2, -M_SQRT1_2, M_SQRT1_2);
 }
 
-void SurfaceInterceptorTest::overrideScalingModeUpdate(Transaction& t) {
-    t.setOverrideScalingMode(mBGSurfaceControl, SCALING_UPDATE);
-}
-
 void SurfaceInterceptorTest::transparentRegionHintUpdate(Transaction& t) {
     Region region(CROP_UPDATE);
     t.setTransparentRegionHint(mBGSurfaceControl, region);
@@ -436,10 +439,10 @@
     runInTransaction(&SurfaceInterceptorTest::alphaUpdate);
     runInTransaction(&SurfaceInterceptorTest::cornerRadiusUpdate);
     runInTransaction(&SurfaceInterceptorTest::backgroundBlurRadiusUpdate);
+    runInTransaction(&SurfaceInterceptorTest::blurRegionsUpdate);
     runInTransaction(&SurfaceInterceptorTest::layerUpdate);
     runInTransaction(&SurfaceInterceptorTest::cropUpdate);
     runInTransaction(&SurfaceInterceptorTest::matrixUpdate);
-    runInTransaction(&SurfaceInterceptorTest::overrideScalingModeUpdate);
     runInTransaction(&SurfaceInterceptorTest::transparentRegionHintUpdate);
     runInTransaction(&SurfaceInterceptorTest::layerStackUpdate);
     runInTransaction(&SurfaceInterceptorTest::hiddenFlagUpdate);
@@ -525,6 +528,17 @@
     return foundBackgroundBlur;
 }
 
+bool SurfaceInterceptorTest::blurRegionsUpdateFound(const SurfaceChange& change,
+                                                    bool foundBlurRegions) {
+    bool hasBlurRegions(change.blur_regions().blur_regions_size() == BLUR_REGIONS_UPDATE.size());
+    if (hasBlurRegions && !foundBlurRegions) {
+        foundBlurRegions = true;
+    } else if (hasBlurRegions && foundBlurRegions) {
+        []() { FAIL(); }();
+    }
+    return foundBlurRegions;
+}
+
 bool SurfaceInterceptorTest::layerUpdateFound(const SurfaceChange& change, bool foundLayer) {
     bool hasLayer(change.layer().layer() == LAYER_UPDATE);
     if (hasLayer && !foundLayer) {
@@ -561,17 +575,6 @@
     return foundMatrix;
 }
 
-bool SurfaceInterceptorTest::scalingModeUpdateFound(const SurfaceChange& change,
-        bool foundScalingMode) {
-    bool hasScalingUpdate(change.override_scaling_mode().override_scaling_mode() == SCALING_UPDATE);
-    if (hasScalingUpdate && !foundScalingMode) {
-        foundScalingMode = true;
-    } else if (hasScalingUpdate && foundScalingMode) {
-        [] () { FAIL(); }();
-    }
-    return foundScalingMode;
-}
-
 bool SurfaceInterceptorTest::transparentRegionHintUpdateFound(const SurfaceChange& change,
         bool foundTransparentRegion) {
     auto traceRegion = change.transparent_region_hint().region(0);
@@ -724,12 +727,12 @@
                         case SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius:
                             foundUpdate = backgroundBlurRadiusUpdateFound(change, foundUpdate);
                             break;
+                        case SurfaceChange::SurfaceChangeCase::kBlurRegions:
+                            foundUpdate = blurRegionsUpdateFound(change, foundUpdate);
+                            break;
                         case SurfaceChange::SurfaceChangeCase::kMatrix:
                             foundUpdate = matrixUpdateFound(change, foundUpdate);
                             break;
-                        case SurfaceChange::SurfaceChangeCase::kOverrideScalingMode:
-                            foundUpdate = scalingModeUpdateFound(change, foundUpdate);
-                            break;
                         case SurfaceChange::SurfaceChangeCase::kTransparentRegionHint:
                             foundUpdate = transparentRegionHintUpdateFound(change, foundUpdate);
                             break;
@@ -780,7 +783,6 @@
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kLayer));
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kCrop));
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kMatrix));
-    ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kOverrideScalingMode));
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kTransparentRegionHint));
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kLayerStack));
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kHiddenFlag));
@@ -911,13 +913,13 @@
                 SurfaceChange::SurfaceChangeCase::kBackgroundBlurRadius);
 }
 
-TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) {
-    captureTest(&SurfaceInterceptorTest::matrixUpdate, SurfaceChange::SurfaceChangeCase::kMatrix);
+TEST_F(SurfaceInterceptorTest, InterceptBlurRegionsUpdateWorks) {
+    captureTest(&SurfaceInterceptorTest::blurRegionsUpdate,
+                SurfaceChange::SurfaceChangeCase::kBlurRegions);
 }
 
-TEST_F(SurfaceInterceptorTest, InterceptOverrideScalingModeUpdateWorks) {
-    captureTest(&SurfaceInterceptorTest::overrideScalingModeUpdate,
-            SurfaceChange::SurfaceChangeCase::kOverrideScalingMode);
+TEST_F(SurfaceInterceptorTest, InterceptMatrixUpdateWorks) {
+    captureTest(&SurfaceInterceptorTest::matrixUpdate, SurfaceChange::SurfaceChangeCase::kMatrix);
 }
 
 TEST_F(SurfaceInterceptorTest, InterceptTransparentRegionHintUpdateWorks) {
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 2861013..8d094e4 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -8,6 +8,7 @@
          "FakeComposerUtils.cpp",
          "SFFakeHwc_test.cpp"
     ],
+    require_root: true,
     shared_libs: [
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 07c558f..0a70f5c 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -447,7 +447,7 @@
             const auto& config = configs[i];
             if (config.resolution.getWidth() == 800) {
                 EXPECT_EQ(NO_ERROR,
-                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
                                                                               config.refreshRate,
                                                                               config.refreshRate,
                                                                               config.refreshRate,
@@ -553,7 +553,7 @@
             const auto& config = configs[i];
             if (config.refreshRate == 1e9f / 11'111'111) {
                 EXPECT_EQ(NO_ERROR,
-                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
                                                                               config.refreshRate,
                                                                               config.refreshRate,
                                                                               config.refreshRate,
@@ -670,7 +670,8 @@
             if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) {
                 EXPECT_EQ(NO_ERROR,
                           SurfaceComposerClient::
-                                  setDesiredDisplayConfigSpecs(display, i, configs[i].refreshRate,
+                                  setDesiredDisplayConfigSpecs(display, i, false,
+                                                               configs[i].refreshRate,
                                                                configs[i].refreshRate,
                                                                configs[i].refreshRate,
                                                                configs[i].refreshRate));
@@ -716,7 +717,7 @@
             const auto& config = configs[i];
             if (config.refreshRate == 1e9f / 8'333'333) {
                 EXPECT_EQ(NO_ERROR,
-                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
                                                                               config.refreshRate,
                                                                               config.refreshRate,
                                                                               config.refreshRate,
@@ -763,7 +764,7 @@
             const auto& config = configs[i];
             if (config.resolution.getWidth() == 1600 && config.refreshRate == 1e9f / 11'111'111) {
                 EXPECT_EQ(NO_ERROR,
-                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i,
+                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
                                                                               config.refreshRate,
                                                                               config.refreshRate,
                                                                               config.refreshRate,
@@ -1469,7 +1470,7 @@
         Base::SetUp();
         mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10,
                                                       PIXEL_FORMAT_RGBA_8888, 0,
-                                                      Base::mFGSurfaceControl.get());
+                                                      Base::mFGSurfaceControl->getHandle());
         fillSurfaceRGBA8(mChild, LIGHT_GRAY);
 
         Base::sFakeComposer->runVSyncAndWait();
@@ -1653,7 +1654,7 @@
         sp<SurfaceControl> childNewClient =
                 newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
                                                  PIXEL_FORMAT_RGBA_8888, 0,
-                                                 Base::mFGSurfaceControl.get());
+                                                 Base::mFGSurfaceControl->getHandle());
         ASSERT_TRUE(childNewClient != nullptr);
         ASSERT_TRUE(childNewClient->isValid());
         fillSurfaceRGBA8(childNewClient, LIGHT_GRAY);
@@ -1691,30 +1692,6 @@
         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() {
         {
@@ -1756,7 +1733,7 @@
         mChild = Base::mComposerClient->createSurface(String8("Child surface"), 10, 10,
                                                       PIXEL_FORMAT_RGBA_8888,
                                                       ISurfaceComposerClient::eHidden,
-                                                      Base::mFGSurfaceControl.get());
+                                                      Base::mFGSurfaceControl->getHandle());
 
         // Show the child layer in a deferred transaction
         {
@@ -1823,10 +1800,6 @@
     Test_DetachChildrenDifferentClient();
 }
 
-TEST_F(ChildLayerTest_2_1, DISABLED_InheritNonTransformScalingFromParent) {
-    Test_InheritNonTransformScalingFromParent();
-}
-
 // Regression test for b/37673612
 TEST_F(ChildLayerTest_2_1, DISABLED_ChildrenWithParentBufferTransform) {
     Test_ChildrenWithParentBufferTransform();
@@ -1847,7 +1820,7 @@
                 Base::mComposerClient->createSurface(String8("Child surface"), 0, 0,
                                                      PIXEL_FORMAT_RGBA_8888,
                                                      ISurfaceComposerClient::eFXSurfaceEffect,
-                                                     Base::mFGSurfaceControl.get());
+                                                     Base::mFGSurfaceControl->getHandle());
         {
             TransactionScope ts(*Base::sFakeComposer);
             ts.setColor(Base::mChild,
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 9655cf3..8097a88 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -41,6 +41,8 @@
         "DisplayIdentificationTest.cpp",
         "DisplayIdGeneratorTest.cpp",
         "DisplayTransactionTest.cpp",
+        "DisplayDevice_GetBestColorModeTest.cpp",
+        "DisplayDevice_SetProjectionTest.cpp",
         "EventThreadTest.cpp",
         "FrameTimelineTest.cpp",
         "HWComposerTest.cpp",
@@ -50,6 +52,16 @@
         "LayerMetadataTest.cpp",
         "MessageQueueTest.cpp",
         "PromiseTest.cpp",
+        "SurfaceFlinger_CreateDisplayTest.cpp",
+        "SurfaceFlinger_DestroyDisplayTest.cpp",
+        "SurfaceFlinger_GetDisplayNativePrimariesTest.cpp",
+        "SurfaceFlinger_HandleTransactionLockedTest.cpp",
+        "SurfaceFlinger_NotifyPowerBoostTest.cpp",
+        "SurfaceFlinger_OnHotplugReceivedTest.cpp",
+        "SurfaceFlinger_OnInitializeDisplaysTest.cpp",
+        "SurfaceFlinger_SetDisplayStateTest.cpp",
+        "SurfaceFlinger_SetPowerModeInternalTest.cpp",
+        "SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp",
         "SchedulerTest.cpp",
         "SchedulerUtilsTest.cpp",
         "SetFrameRateTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_GetBestColorModeTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_GetBestColorModeTest.cpp
new file mode 100644
index 0000000..2e53cd1
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_GetBestColorModeTest.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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 "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+using hal::RenderIntent;
+
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+class GetBestColorModeTest : public DisplayTransactionTest {
+public:
+    void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
+
+    void addHwcColorModesMapping(ui::ColorMode colorMode,
+                                 std::vector<ui::RenderIntent> renderIntents) {
+        mHwcColorModes[colorMode] = renderIntents;
+    }
+
+    void setInputDataspace(ui::Dataspace dataspace) { mInputDataspace = dataspace; }
+
+    void setInputRenderIntent(ui::RenderIntent renderIntent) { mInputRenderIntent = renderIntent; }
+
+    void getBestColorMode() {
+        auto displayDevice =
+                injectDefaultInternalDisplay([this](FakeDisplayDeviceInjector& injector) {
+                    injector.setHwcColorModes(mHwcColorModes);
+                    injector.setHasWideColorGamut(mHasWideColorGamut);
+                    injector.setNativeWindow(mNativeWindow);
+                });
+
+        displayDevice->getCompositionDisplay()
+                ->getDisplayColorProfile()
+                ->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
+                                   &mOutColorMode, &mOutRenderIntent);
+    }
+
+    ui::Dataspace mOutDataspace;
+    ui::ColorMode mOutColorMode;
+    ui::RenderIntent mOutRenderIntent;
+
+private:
+    ui::Dataspace mInputDataspace;
+    ui::RenderIntent mInputRenderIntent;
+    bool mHasWideColorGamut = false;
+    std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> mHwcColorModes;
+};
+
+TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeSRGB) {
+    addHwcColorModesMapping(ui::ColorMode::SRGB,
+                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+    setInputDataspace(ui::Dataspace::DISPLAY_P3);
+    setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
+    setHasWideColorGamut(true);
+
+    getBestColorMode();
+
+    ASSERT_EQ(ui::Dataspace::V0_SRGB, mOutDataspace);
+    ASSERT_EQ(ui::ColorMode::SRGB, mOutColorMode);
+    ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
+}
+
+TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDisplayP3) {
+    addHwcColorModesMapping(ui::ColorMode::DISPLAY_P3,
+                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+    addHwcColorModesMapping(ui::ColorMode::SRGB,
+                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+    addHwcColorModesMapping(ui::ColorMode::DISPLAY_BT2020,
+                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+    setInputDataspace(ui::Dataspace::DISPLAY_P3);
+    setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
+    setHasWideColorGamut(true);
+
+    getBestColorMode();
+
+    ASSERT_EQ(ui::Dataspace::DISPLAY_P3, mOutDataspace);
+    ASSERT_EQ(ui::ColorMode::DISPLAY_P3, mOutColorMode);
+    ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
+}
+
+TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDISPLAY_BT2020) {
+    addHwcColorModesMapping(ui::ColorMode::DISPLAY_BT2020,
+                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+    setInputDataspace(ui::Dataspace::DISPLAY_P3);
+    setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
+    setHasWideColorGamut(true);
+
+    getBestColorMode();
+
+    ASSERT_EQ(ui::Dataspace::DISPLAY_BT2020, mOutDataspace);
+    ASSERT_EQ(ui::ColorMode::DISPLAY_BT2020, mOutColorMode);
+    ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp
new file mode 100644
index 0000000..9fe30f8
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayDevice_SetProjectionTest.cpp
@@ -0,0 +1,250 @@
+/*
+ * 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 "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+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(ui::ROTATION_0, compositionState.displaySpace.orientation);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
+        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(ui::ROTATION_90, compositionState.displaySpace.orientation);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
+        // For 90, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
+        // size width and height swapped
+        EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)),
+                  compositionState.orientedDisplaySpace.content);
+        EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
+        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(ui::ROTATION_180, compositionState.displaySpace.orientation);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
+        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(ui::ROTATION_270, compositionState.displaySpace.orientation);
+        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
+        // For 270, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
+        // size width and height swapped
+        EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)),
+                  compositionState.orientedDisplaySpace.content);
+        EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
+        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();
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index e055e95..db05d5a 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -14,160 +14,22 @@
  * 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 <type_traits>
-
-#include <android/hardware/power/Boost.h>
-#include <binder/IPCThreadState.h>
-#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 <private/android_filesystem_config.h>
-#include <renderengine/mock/RenderEngine.h>
-#include <ui/DebugUtils.h>
-
-#include "DisplayIdentificationTest.h"
-#include "TestableScheduler.h"
-#include "TestableSurfaceFlinger.h"
-#include "mock/DisplayHardware/MockComposer.h"
-#include "mock/DisplayHardware/MockPowerAdvisor.h"
-#include "mock/MockEventThread.h"
-#include "mock/MockMessageQueue.h"
-#include "mock/MockNativeWindowSurface.h"
-#include "mock/MockSchedulerCallback.h"
-#include "mock/MockSurfaceInterceptor.h"
-#include "mock/MockVsyncController.h"
-#include "mock/system/window/MockNativeWindow.h"
+#include "DisplayTransactionTestHelpers.h"
 
 namespace android {
-namespace {
 
-namespace hal = android::hardware::graphics::composer::hal;
-
-using android::hardware::power::Boost;
-
-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 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 android::hardware::graphics::composer::hal::HWDisplayId;
 
 using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
-using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
-using HotplugEvent = TestableSurfaceFlinger::HotplugEvent;
-using HWC2Display = TestableSurfaceFlinger::HWC2Display;
-
-constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'667;
-constexpr int32_t DEFAULT_DPI = 320;
-constexpr int DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT = HAL_PIXEL_FORMAT_RGB_565;
-
-constexpr int POWER_MODE_LEET = 1337; // An out of range power mode value
-
-/* ------------------------------------------------------------------------
- * Boolean avoidance
- *
- * To make calls and template instantiations more readable, we define some
- * local enums along with an implicit bool conversion.
- */
-
-#define BOOL_SUBSTITUTE(TYPENAME) enum class TYPENAME : bool { FALSE = false, TRUE = true };
-
-BOOL_SUBSTITUTE(Async);
-BOOL_SUBSTITUTE(Critical);
-BOOL_SUBSTITUTE(Primary);
-BOOL_SUBSTITUTE(Secure);
-BOOL_SUBSTITUTE(Virtual);
-
-/* ------------------------------------------------------------------------
- *
- */
-
-class DisplayTransactionTest : public testing::Test {
-public:
-    DisplayTransactionTest();
-    ~DisplayTransactionTest() override;
-
-    // --------------------------------------------------------------------
-    // Mock/Fake injection
-
-    void injectMockScheduler();
-    void injectMockComposer(int virtualDisplayCount);
-    void injectFakeBufferQueueFactory();
-    void injectFakeNativeWindowSurfaceFactory();
-    sp<DisplayDevice> injectDefaultInternalDisplay(std::function<void(FakeDisplayDeviceInjector&)>);
-
-    // --------------------------------------------------------------------
-    // Postcondition helpers
-
-    bool hasPhysicalHwcDisplay(HWDisplayId hwcDisplayId);
-    bool hasTransactionFlagSet(int flag);
-    bool hasDisplayDevice(sp<IBinder> displayToken);
-    sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken);
-    bool hasCurrentDisplayState(sp<IBinder> displayToken);
-    const DisplayDeviceState& getCurrentDisplayState(sp<IBinder> displayToken);
-    bool hasDrawingDisplayState(sp<IBinder> displayToken);
-    const DisplayDeviceState& getDrawingDisplayState(sp<IBinder> displayToken);
-
-    // --------------------------------------------------------------------
-    // Test instances
-
-    TestableSurfaceFlinger mFlinger;
-    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
-    // to keep a reference to them for use in setting up call expectations.
-    renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
-    Hwc2::mock::Composer* mComposer = nullptr;
-    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
-    sp<mock::SurfaceInterceptor> mSurfaceInterceptor = new mock::SurfaceInterceptor;
-
-    mock::VsyncController* mVsyncController = new mock::VsyncController;
-    mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker;
-    mock::SchedulerCallback mSchedulerCallback;
-    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;
-    sp<mock::GraphicBufferProducer> mProducer;
-    surfaceflinger::mock::NativeWindowSurface* mNativeWindowSurface = nullptr;
-};
 
 DisplayTransactionTest::DisplayTransactionTest() {
     const ::testing::TestInfo* const test_info =
@@ -330,3298 +192,4 @@
     return mFlinger.mutableDrawingState().displays.valueFor(displayToken);
 }
 
-/* ------------------------------------------------------------------------
- *
- */
-
-template <typename PhysicalDisplay>
-struct PhysicalDisplayIdType {};
-
-template <uint64_t displayId>
-using HalVirtualDisplayIdType = std::integral_constant<uint64_t, displayId>;
-
-struct GpuVirtualDisplayIdType {};
-
-template <typename>
-struct IsPhysicalDisplayId : std::bool_constant<false> {};
-
-template <typename PhysicalDisplay>
-struct IsPhysicalDisplayId<PhysicalDisplayIdType<PhysicalDisplay>> : std::bool_constant<true> {};
-
-template <typename>
-struct DisplayIdGetter;
-
-template <typename PhysicalDisplay>
-struct DisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
-    static PhysicalDisplayId get() {
-        if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
-            return PhysicalDisplayId::fromPort(static_cast<bool>(PhysicalDisplay::PRIMARY)
-                                                       ? LEGACY_DISPLAY_TYPE_PRIMARY
-                                                       : LEGACY_DISPLAY_TYPE_EXTERNAL);
-        }
-
-        const auto info =
-                parseDisplayIdentificationData(PhysicalDisplay::PORT,
-                                               PhysicalDisplay::GET_IDENTIFICATION_DATA());
-        return info ? info->id : PhysicalDisplayId::fromPort(PhysicalDisplay::PORT);
-    }
-};
-
-template <uint64_t displayId>
-struct DisplayIdGetter<HalVirtualDisplayIdType<displayId>> {
-    static HalVirtualDisplayId get() { return HalVirtualDisplayId(displayId); }
-};
-
-template <>
-struct DisplayIdGetter<GpuVirtualDisplayIdType> {
-    static GpuVirtualDisplayId get() { return GpuVirtualDisplayId(0); }
-};
-
-template <typename>
-struct DisplayConnectionTypeGetter {
-    static constexpr std::optional<DisplayConnectionType> value;
-};
-
-template <typename PhysicalDisplay>
-struct DisplayConnectionTypeGetter<PhysicalDisplayIdType<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 <uint64_t displayId>
-struct HwcDisplayIdGetter<HalVirtualDisplayIdType<displayId>> {
-    static constexpr std::optional<HWDisplayId> value = HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID;
-};
-
-template <typename PhysicalDisplay>
-struct HwcDisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
-    static constexpr std::optional<HWDisplayId> value = PhysicalDisplay::HWC_DISPLAY_ID;
-};
-
-// DisplayIdType can be:
-//     1) PhysicalDisplayIdType<...> for generated ID of physical display backed by HWC.
-//     2) HalVirtualDisplayIdType<...> for hard-coded ID of virtual display backed by HWC.
-//     3) GpuVirtualDisplayIdType for virtual display without HWC backing.
-template <typename DisplayIdType, int width, int height, Critical critical, Async async,
-          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;
-    static constexpr int HEIGHT = height;
-
-    static constexpr int GRALLOC_USAGE = grallocUsage;
-
-    // Whether the display is virtual or physical
-    static constexpr Virtual VIRTUAL =
-            IsPhysicalDisplayId<DisplayIdType>{} ? Virtual::FALSE : Virtual::TRUE;
-
-    // When creating native window surfaces for the framebuffer, whether those should be critical
-    static constexpr Critical CRITICAL = critical;
-
-    // When creating native window surfaces for the framebuffer, whether those should be async
-    static constexpr Async ASYNC = async;
-
-    // Whether the display should be treated as secure
-    static constexpr Secure SECURE = secure;
-
-    // Whether the display is primary
-    static constexpr Primary PRIMARY = primary;
-
-    static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
-        auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder();
-        if (auto displayId = PhysicalDisplayId::tryCast(DISPLAY_ID::get())) {
-            ceDisplayArgs.setPhysical({*displayId, DisplayConnectionType::Internal});
-        } else {
-            // We turn off the use of HwcVirtualDisplays, to prevent Composition Engine
-            // from calling into HWComposer. This way all virtual displays will get
-            // a GpuVirtualDisplayId, even if we are in the HwcVirtualDisplayVariant.
-            // In this case we later override it by calling display.setDisplayIdForTesting().
-            ceDisplayArgs.setUseHwcVirtualDisplays(false);
-
-            GpuVirtualDisplayId desiredDisplayId = GpuVirtualDisplayId::tryCast(DISPLAY_ID::get())
-                                                           .value_or(GpuVirtualDisplayId(0));
-
-            ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
-                    .WillByDefault(Return(desiredDisplayId));
-
-            auto& generator = test->mFlinger.gpuVirtualDisplayIdGenerator();
-            ceDisplayArgs.setGpuVirtualDisplayIdGenerator(generator);
-        }
-        ceDisplayArgs.setPixels({WIDTH, HEIGHT}).setPowerAdvisor(&test->mPowerAdvisor);
-
-        auto compositionDisplay =
-                compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
-                                                       ceDisplayArgs.build());
-
-        if (HalVirtualDisplayId::tryCast(DISPLAY_ID::get())) {
-            // CompositionEngine has assigned a placeholder GpuVirtualDisplayId and we need to
-            // override it with the correct HalVirtualDisplayId.
-            compositionDisplay->setDisplayIdForTesting(DISPLAY_ID::get());
-        }
-
-        auto injector = 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);
-
-        // Creating a DisplayDevice requires getting default dimensions from the
-        // native window along with some other initial setup.
-        EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
-                .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
-        EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
-                .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
-        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT))
-                .WillRepeatedly(Return(0));
-        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT))
-                .WillRepeatedly(Return(0));
-        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64))
-                .WillRepeatedly(Return(0));
-        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT))
-                .WillRepeatedly(Return(0));
-
-        return injector;
-    }
-
-    // Called by tests to set up any native window creation call expectations.
-    static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mNativeWindowSurface, getNativeWindow())
-                .WillOnce(Return(test->mNativeWindow));
-
-        EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
-                .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
-        EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
-                .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
-        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT))
-                .WillRepeatedly(Return(0));
-        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT))
-                .WillRepeatedly(Return(0));
-        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64))
-                .WillRepeatedly(Return(0));
-        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT))
-                .WillRepeatedly(Return(0));
-    }
-
-    static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR));
-        EXPECT_CALL(*test->mConsumer, setConsumerName(_)).WillRepeatedly(Return(NO_ERROR));
-        EXPECT_CALL(*test->mConsumer, setConsumerUsageBits(GRALLOC_USAGE))
-                .WillRepeatedly(Return(NO_ERROR));
-        EXPECT_CALL(*test->mConsumer, setDefaultBufferSize(WIDTH, HEIGHT))
-                .WillRepeatedly(Return(NO_ERROR));
-        EXPECT_CALL(*test->mConsumer, setMaxAcquiredBufferCount(_))
-                .WillRepeatedly(Return(NO_ERROR));
-    }
-
-    static void setupFramebufferProducerBufferQueueCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mProducer, allocateBuffers(0, 0, 0, 0)).WillRepeatedly(Return());
-    }
-};
-
-template <HWDisplayId hwcDisplayId, DisplayType hwcDisplayType, typename DisplayVariant,
-          typename PhysicalDisplay = void>
-struct HwcDisplayVariant {
-    // The display id supplied by the HWC
-    static constexpr HWDisplayId HWC_DISPLAY_ID = hwcDisplayId;
-
-    // The HWC display type
-    static constexpr DisplayType HWC_DISPLAY_TYPE = hwcDisplayType;
-
-    // The HWC active configuration id
-    static constexpr int HWC_ACTIVE_CONFIG_ID = 2001;
-    static constexpr PowerMode INIT_POWER_MODE = PowerMode::ON;
-
-    static void injectPendingHotplugEvent(DisplayTransactionTest* test, Connection connection) {
-        test->mFlinger.mutablePendingHotplugEvents().emplace_back(
-                HotplugEvent{HWC_DISPLAY_ID, connection});
-    }
-
-    // Called by tests to inject a HWC display setup
-    static void injectHwcDisplayWithNoDefaultCapabilities(DisplayTransactionTest* test) {
-        const auto displayId = DisplayVariant::DISPLAY_ID::get();
-        ASSERT_FALSE(GpuVirtualDisplayId::tryCast(displayId));
-        FakeHwcDisplayInjector(displayId, HWC_DISPLAY_TYPE,
-                               static_cast<bool>(DisplayVariant::PRIMARY))
-                .setHwcDisplayId(HWC_DISPLAY_ID)
-                .setWidth(DisplayVariant::WIDTH)
-                .setHeight(DisplayVariant::HEIGHT)
-                .setActiveConfig(HWC_ACTIVE_CONFIG_ID)
-                .setPowerMode(INIT_POWER_MODE)
-                .inject(&test->mFlinger, test->mComposer);
-    }
-
-    // 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<DisplayCapability>({})),
-                                Return(Error::NONE)));
-        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) {
-        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)));
-        EXPECT_CALL(*test->mComposer,
-                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
-                                        IComposerClient::Attribute::WIDTH, _))
-                .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::WIDTH), Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
-                                        IComposerClient::Attribute::HEIGHT, _))
-                .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::HEIGHT), Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
-                                        IComposerClient::Attribute::VSYNC_PERIOD, _))
-                .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
-                                        IComposerClient::Attribute::DPI_X, _))
-                .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
-                                        IComposerClient::Attribute::DPI_Y, _))
-                .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
-                                        IComposerClient::Attribute::CONFIG_GROUP, _))
-                .WillOnce(DoAll(SetArgPointee<3>(-1), Return(Error::NONE)));
-
-        if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
-            EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
-                    .WillOnce(DoAll(SetArgPointee<1>(PhysicalDisplay::PORT),
-                                    SetArgPointee<2>(PhysicalDisplay::GET_IDENTIFICATION_DATA()),
-                                    Return(Error::NONE)));
-        } else {
-            EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
-                    .WillOnce(Return(Error::UNSUPPORTED));
-        }
-    }
-
-    // Called by tests to set up HWC call expectations
-    static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY_ID, _))
-                .WillRepeatedly(DoAll(SetArgPointee<1>(HWC_ACTIVE_CONFIG_ID), Return(Error::NONE)));
-    }
-};
-
-// Physical displays are expected to be synchronous, secure, and have a HWC display for output.
-constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY =
-        GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
-
-template <typename PhysicalDisplay, int width, int height, Critical critical>
-struct PhysicalDisplayVariant
-      : DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, critical,
-                       Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY,
-                       GRALLOC_USAGE_PHYSICAL_DISPLAY>,
-        HwcDisplayVariant<PhysicalDisplay::HWC_DISPLAY_ID, DisplayType::PHYSICAL,
-                          DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height,
-                                         critical, Async::FALSE, Secure::TRUE,
-                                         PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
-                          PhysicalDisplay> {};
-
-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;
-};
-
-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<PrimaryDisplay<false>, 3840, 2160, Critical::TRUE>;
-
-// An external display is physical display that is not critical.
-using ExternalDisplayVariant =
-        PhysicalDisplayVariant<ExternalDisplay<false>, 1920, 1280, 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;
-
-template <int width, int height, Secure secure>
-struct NonHwcVirtualDisplayVariant
-      : DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE, Async::TRUE, secure,
-                       Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY> {
-    using Base =
-            DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE, Async::TRUE,
-                           secure, Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>;
-
-    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();
-
-        ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
-                .WillByDefault(Return(Base::DISPLAY_ID::get()));
-
-        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())
-                                     .setGpuVirtualDisplayIdGenerator(
-                                             test->mFlinger.gpuVirtualDisplayIdGenerator())
-                                     .build();
-
-        return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
-                                                      ceDisplayArgs);
-    }
-
-    static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
-    }
-
-    static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
-        Base::setupNativeWindowSurfaceCreationCallExpectations(test);
-        EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1);
-    }
-};
-
-// A virtual display supported by the HWC.
-constexpr uint32_t GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY = GRALLOC_USAGE_HW_COMPOSER;
-
-template <int width, int height, Secure secure>
-struct HwcVirtualDisplayVariant
-      : DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Critical::FALSE, Async::TRUE,
-                       secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
-        HwcDisplayVariant<HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID, DisplayType::VIRTUAL,
-                          DisplayVariant<HalVirtualDisplayIdType<42>, width, height,
-                                         Critical::FALSE, Async::TRUE, secure, Primary::FALSE,
-                                         GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>> {
-    using Base = DisplayVariant<HalVirtualDisplayIdType<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();
-
-        // In order to prevent compostition engine calling into HWComposer, we
-        // 1. turn off the use of HWC virtual displays,
-        // 2. provide a GpuVirtualDisplayIdGenerator which always returns some fake ID
-        // 3. override the ID by calling setDisplayIdForTesting()
-
-        ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
-                .WillByDefault(Return(GpuVirtualDisplayId(0)));
-
-        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())
-                                     .setGpuVirtualDisplayIdGenerator(
-                                             test->mFlinger.gpuVirtualDisplayIdGenerator())
-                                     .build();
-
-        auto compositionDisplay =
-                compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
-                                                       ceDisplayArgs);
-        compositionDisplay->setDisplayIdForTesting(Base::DISPLAY_ID::get());
-
-        // Insert display data so that the HWC thinks it created the virtual display.
-        if (const auto displayId = Base::DISPLAY_ID::get();
-            HalVirtualDisplayId::tryCast(displayId)) {
-            test->mFlinger.mutableHwcDisplayData().try_emplace(displayId);
-        }
-
-        return compositionDisplay;
-    }
-
-    static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
-        Base::setupNativeWindowSurfaceCreationCallExpectations(test);
-        EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1);
-    }
-
-    static void setupHwcVirtualDisplayCreationCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _))
-                .WillOnce(DoAll(SetArgPointee<3>(Self::HWC_DISPLAY_ID), Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
-    }
-};
-
-// For this variant, SurfaceFlinger should not configure itself with wide
-// display support, so the display should not be configured for wide-color
-// support.
-struct WideColorSupportNotConfiguredVariant {
-    static constexpr bool WIDE_COLOR_SUPPORTED = false;
-
-    static void injectConfigChange(DisplayTransactionTest* test) {
-        test->mFlinger.mutableHasWideColorDisplay() = false;
-        test->mFlinger.mutableUseColorManagement() = false;
-        test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
-    }
-
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getColorModes(_, _)).Times(0);
-        EXPECT_CALL(*test->mComposer, getRenderIntents(_, _, _)).Times(0);
-        EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0);
-    }
-};
-
-// For this variant, SurfaceFlinger should configure itself with wide display
-// support, and the display should respond with an non-empty list of supported
-// color modes. Wide-color support should be configured.
-template <typename Display>
-struct WideColorP3ColorimetricSupportedVariant {
-    static constexpr bool WIDE_COLOR_SUPPORTED = true;
-
-    static void injectConfigChange(DisplayTransactionTest* test) {
-        test->mFlinger.mutableUseColorManagement() = true;
-        test->mFlinger.mutableHasWideColorDisplay() = true;
-        test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
-    }
-
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_DATASPACE)).Times(1);
-
-        EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>({ColorMode::DISPLAY_P3})),
-                                Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    getRenderIntents(Display::HWC_DISPLAY_ID, ColorMode::DISPLAY_P3, _))
-                .WillOnce(DoAll(SetArgPointee<2>(
-                                        std::vector<RenderIntent>({RenderIntent::COLORIMETRIC})),
-                                Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer,
-                    setColorMode(Display::HWC_DISPLAY_ID, ColorMode::SRGB,
-                                 RenderIntent::COLORIMETRIC))
-                .WillOnce(Return(Error::NONE));
-    }
-};
-
-// For this variant, SurfaceFlinger should configure itself with wide display
-// support, but the display should respond with an empty list of supported color
-// modes. Wide-color support for the display should not be configured.
-template <typename Display>
-struct WideColorNotSupportedVariant {
-    static constexpr bool WIDE_COLOR_SUPPORTED = false;
-
-    static void injectConfigChange(DisplayTransactionTest* test) {
-        test->mFlinger.mutableUseColorManagement() = true;
-        test->mFlinger.mutableHasWideColorDisplay() = true;
-    }
-
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>()), Return(Error::NONE)));
-        EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0);
-    }
-};
-
-// For this variant, the display is not a HWC display, so no HDR support should
-// be configured.
-struct NonHwcDisplayHdrSupportVariant {
-    static constexpr bool HDR10_PLUS_SUPPORTED = false;
-    static constexpr bool HDR10_SUPPORTED = false;
-    static constexpr bool HDR_HLG_SUPPORTED = false;
-    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getHdrCapabilities(_, _, _, _, _)).Times(0);
-    }
-};
-
-template <typename Display>
-struct Hdr10PlusSupportedVariant {
-    static constexpr bool HDR10_PLUS_SUPPORTED = true;
-    static constexpr bool HDR10_SUPPORTED = true;
-    static constexpr bool HDR_HLG_SUPPORTED = false;
-    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getHdrCapabilities(_, _, _, _, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>({
-                                        Hdr::HDR10_PLUS,
-                                        Hdr::HDR10,
-                                })),
-                                Return(Error::NONE)));
-    }
-};
-
-// For this variant, the composer should respond with a non-empty list of HDR
-// modes containing HDR10, so HDR10 support should be configured.
-template <typename Display>
-struct Hdr10SupportedVariant {
-    static constexpr bool HDR10_PLUS_SUPPORTED = false;
-    static constexpr bool HDR10_SUPPORTED = true;
-    static constexpr bool HDR_HLG_SUPPORTED = false;
-    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::HDR10})),
-                                Return(Error::NONE)));
-    }
-};
-
-// For this variant, the composer should respond with a non-empty list of HDR
-// modes containing HLG, so HLG support should be configured.
-template <typename Display>
-struct HdrHlgSupportedVariant {
-    static constexpr bool HDR10_PLUS_SUPPORTED = false;
-    static constexpr bool HDR10_SUPPORTED = false;
-    static constexpr bool HDR_HLG_SUPPORTED = true;
-    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
-                .WillOnce(
-                        DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::HLG})), Return(Error::NONE)));
-    }
-};
-
-// For this variant, the composer should respond with a non-empty list of HDR
-// modes containing DOLBY_VISION, so DOLBY_VISION support should be configured.
-template <typename Display>
-struct HdrDolbyVisionSupportedVariant {
-    static constexpr bool HDR10_PLUS_SUPPORTED = false;
-    static constexpr bool HDR10_SUPPORTED = false;
-    static constexpr bool HDR_HLG_SUPPORTED = false;
-    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = true;
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::DOLBY_VISION})),
-                                Return(Error::NONE)));
-    }
-};
-
-// For this variant, the composer should respond with am empty list of HDR
-// modes, so no HDR support should be configured.
-template <typename Display>
-struct HdrNotSupportedVariant {
-    static constexpr bool HDR10_PLUS_SUPPORTED = false;
-    static constexpr bool HDR10_SUPPORTED = false;
-    static constexpr bool HDR_HLG_SUPPORTED = false;
-    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>()), Return(Error::NONE)));
-    }
-};
-
-struct NonHwcPerFrameMetadataSupportVariant {
-    static constexpr int PER_FRAME_METADATA_KEYS = 0;
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(_)).Times(0);
-    }
-};
-
-template <typename Display>
-struct NoPerFrameMetadataSupportVariant {
-    static constexpr int PER_FRAME_METADATA_KEYS = 0;
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
-                .WillOnce(Return(std::vector<PerFrameMetadataKey>()));
-    }
-};
-
-template <typename Display>
-struct Smpte2086PerFrameMetadataSupportVariant {
-    static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::SMPTE2086;
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
-                .WillOnce(Return(std::vector<PerFrameMetadataKey>({
-                        PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X,
-                        PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y,
-                        PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X,
-                        PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y,
-                        PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X,
-                        PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y,
-                        PerFrameMetadataKey::WHITE_POINT_X,
-                        PerFrameMetadataKey::WHITE_POINT_Y,
-                        PerFrameMetadataKey::MAX_LUMINANCE,
-                        PerFrameMetadataKey::MIN_LUMINANCE,
-                })));
-    }
-};
-
-template <typename Display>
-struct Cta861_3_PerFrameMetadataSupportVariant {
-    static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::CTA861_3;
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
-                .WillOnce(Return(std::vector<PerFrameMetadataKey>({
-                        PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL,
-                        PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL,
-                })));
-    }
-};
-
-template <typename Display>
-struct Hdr10_Plus_PerFrameMetadataSupportVariant {
-    static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::HDR10PLUS;
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
-                .WillOnce(Return(std::vector<PerFrameMetadataKey>({
-                        PerFrameMetadataKey::HDR10_PLUS_SEI,
-                })));
-    }
-};
-/* ------------------------------------------------------------------------
- * Typical display configurations to test
- */
-
-template <typename DisplayPolicy, typename WideColorSupportPolicy, typename HdrSupportPolicy,
-          typename PerFrameMetadataSupportPolicy>
-struct Case {
-    using Display = DisplayPolicy;
-    using WideColorSupport = WideColorSupportPolicy;
-    using HdrSupport = HdrSupportPolicy;
-    using PerFrameMetadataSupport = PerFrameMetadataSupportPolicy;
-};
-
-using SimplePrimaryDisplayCase =
-        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
-             HdrNotSupportedVariant<PrimaryDisplayVariant>,
-             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using SimpleExternalDisplayCase =
-        Case<ExternalDisplayVariant, WideColorNotSupportedVariant<ExternalDisplayVariant>,
-             HdrNotSupportedVariant<ExternalDisplayVariant>,
-             NoPerFrameMetadataSupportVariant<ExternalDisplayVariant>>;
-using SimpleTertiaryDisplayCase =
-        Case<TertiaryDisplayVariant, WideColorNotSupportedVariant<TertiaryDisplayVariant>,
-             HdrNotSupportedVariant<TertiaryDisplayVariant>,
-             NoPerFrameMetadataSupportVariant<TertiaryDisplayVariant>>;
-using NonHwcVirtualDisplayCase =
-        Case<NonHwcVirtualDisplayVariant<1024, 768, Secure::FALSE>,
-             WideColorSupportNotConfiguredVariant, NonHwcDisplayHdrSupportVariant,
-             NonHwcPerFrameMetadataSupportVariant>;
-using SimpleHwcVirtualDisplayVariant = HwcVirtualDisplayVariant<1024, 768, Secure::TRUE>;
-using HwcVirtualDisplayCase =
-        Case<SimpleHwcVirtualDisplayVariant, WideColorSupportNotConfiguredVariant,
-             HdrNotSupportedVariant<SimpleHwcVirtualDisplayVariant>,
-             NoPerFrameMetadataSupportVariant<SimpleHwcVirtualDisplayVariant>>;
-using WideColorP3ColorimetricDisplayCase =
-        Case<PrimaryDisplayVariant, WideColorP3ColorimetricSupportedVariant<PrimaryDisplayVariant>,
-             HdrNotSupportedVariant<PrimaryDisplayVariant>,
-             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using Hdr10PlusDisplayCase =
-        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
-             Hdr10SupportedVariant<PrimaryDisplayVariant>,
-             Hdr10_Plus_PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using Hdr10DisplayCase =
-        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
-             Hdr10SupportedVariant<PrimaryDisplayVariant>,
-             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using HdrHlgDisplayCase =
-        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
-             HdrHlgSupportedVariant<PrimaryDisplayVariant>,
-             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using HdrDolbyVisionDisplayCase =
-        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
-             HdrDolbyVisionSupportedVariant<PrimaryDisplayVariant>,
-             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using HdrSmpte2086DisplayCase =
-        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
-             HdrNotSupportedVariant<PrimaryDisplayVariant>,
-             Smpte2086PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using HdrCta861_3_DisplayCase =
-        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
-             HdrNotSupportedVariant<PrimaryDisplayVariant>,
-             Cta861_3_PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-
-/* ------------------------------------------------------------------------
- *
- * SurfaceFlinger::onHotplugReceived
- */
-
-TEST_F(DisplayTransactionTest, hotplugEnqueuesEventsForDisplayTransaction) {
-    constexpr int currentSequenceId = 123;
-    constexpr HWDisplayId hwcDisplayId1 = 456;
-    constexpr HWDisplayId hwcDisplayId2 = 654;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // Set the current sequence id for accepted events
-    mFlinger.mutableComposerSequenceId() = currentSequenceId;
-
-    // Set the main thread id so that the current thread does not appear to be
-    // the main thread.
-    mFlinger.mutableMainThreadId() = std::thread::id();
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    // We expect invalidate() to be invoked once to trigger display transaction
-    // processing.
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    // Simulate two hotplug events (a connect and a disconnect)
-    mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId1, Connection::CONNECTED);
-    mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId2, Connection::DISCONNECTED);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The display transaction needed flag should be set.
-    EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
-
-    // All events should be in the pending event queue.
-    const auto& pendingEvents = mFlinger.mutablePendingHotplugEvents();
-    ASSERT_EQ(2u, pendingEvents.size());
-    EXPECT_EQ(hwcDisplayId1, pendingEvents[0].hwcDisplayId);
-    EXPECT_EQ(Connection::CONNECTED, pendingEvents[0].connection);
-    EXPECT_EQ(hwcDisplayId2, pendingEvents[1].hwcDisplayId);
-    EXPECT_EQ(Connection::DISCONNECTED, pendingEvents[1].connection);
-}
-
-TEST_F(DisplayTransactionTest, hotplugDiscardsUnexpectedEvents) {
-    constexpr int currentSequenceId = 123;
-    constexpr int otherSequenceId = 321;
-    constexpr HWDisplayId displayId = 456;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // Set the current sequence id for accepted events
-    mFlinger.mutableComposerSequenceId() = currentSequenceId;
-
-    // Set the main thread id so that the current thread does not appear to be
-    // the main thread.
-    mFlinger.mutableMainThreadId() = std::thread::id();
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    // We do not expect any calls to invalidate().
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(0);
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    // Call with an unexpected sequence id
-    mFlinger.onHotplugReceived(otherSequenceId, displayId, Connection::INVALID);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The display transaction needed flag should not be set
-    EXPECT_FALSE(hasTransactionFlagSet(eDisplayTransactionNeeded));
-
-    // There should be no pending events
-    EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty());
-}
-
-TEST_F(DisplayTransactionTest, hotplugProcessesEnqueuedEventsIfCalledOnMainThread) {
-    constexpr int currentSequenceId = 123;
-    constexpr HWDisplayId displayId1 = 456;
-
-    // --------------------------------------------------------------------
-    // Note:
-    // --------------------------------------------------------------------
-    // This test case is a bit tricky. We want to verify that
-    // onHotplugReceived() calls processDisplayHotplugEventsLocked(), but we
-    // don't really want to provide coverage for everything the later function
-    // does as there are specific tests for it.
-    // --------------------------------------------------------------------
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // Set the current sequence id for accepted events
-    mFlinger.mutableComposerSequenceId() = currentSequenceId;
-
-    // Set the main thread id so that the current thread does appear to be the
-    // main thread.
-    mFlinger.mutableMainThreadId() = std::this_thread::get_id();
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    // We expect invalidate() to be invoked once to trigger display transaction
-    // processing.
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    // 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, Connection::DISCONNECTED);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The display transaction needed flag should be set.
-    EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
-
-    // There should be no event queued on return, as it should have been
-    // processed.
-    EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty());
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::createDisplay
- */
-
-TEST_F(DisplayTransactionTest, createDisplaySetsCurrentStateForNonsecureDisplay) {
-    const String8 name("virtual.test");
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    // The call should notify the interceptor that a display was created.
-    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    sp<IBinder> displayToken = mFlinger.createDisplay(name, false);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The display should have been added to the current state
-    ASSERT_TRUE(hasCurrentDisplayState(displayToken));
-    const auto& display = getCurrentDisplayState(displayToken);
-    EXPECT_TRUE(display.isVirtual());
-    EXPECT_FALSE(display.isSecure);
-    EXPECT_EQ(name.string(), display.displayName);
-
-    // --------------------------------------------------------------------
-    // Cleanup conditions
-
-    // Destroying the display invalidates the display state.
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
-}
-
-TEST_F(DisplayTransactionTest, createDisplaySetsCurrentStateForSecureDisplay) {
-    const String8 name("virtual.test");
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    // The call should notify the interceptor that a display was created.
-    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
-
-    // --------------------------------------------------------------------
-    // Invocation
-    int64_t oldId = IPCThreadState::self()->clearCallingIdentity();
-    // Set the calling identity to graphics so captureDisplay with secure is allowed.
-    IPCThreadState::self()->restoreCallingIdentity(static_cast<int64_t>(AID_GRAPHICS) << 32 |
-                                                   AID_GRAPHICS);
-    sp<IBinder> displayToken = mFlinger.createDisplay(name, true);
-    IPCThreadState::self()->restoreCallingIdentity(oldId);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The display should have been added to the current state
-    ASSERT_TRUE(hasCurrentDisplayState(displayToken));
-    const auto& display = getCurrentDisplayState(displayToken);
-    EXPECT_TRUE(display.isVirtual());
-    EXPECT_TRUE(display.isSecure);
-    EXPECT_EQ(name.string(), display.displayName);
-
-    // --------------------------------------------------------------------
-    // Cleanup conditions
-
-    // Destroying the display invalidates the display state.
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::destroyDisplay
- */
-
-TEST_F(DisplayTransactionTest, destroyDisplayClearsCurrentStateForDisplay) {
-    using Case = NonHwcVirtualDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A virtual display exists
-    auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
-    existing.inject();
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    // The call should notify the interceptor that a display was created.
-    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
-
-    // Destroying the display invalidates the display state.
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.destroyDisplay(existing.token());
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The display should have been removed from the current state
-    EXPECT_FALSE(hasCurrentDisplayState(existing.token()));
-
-    // Ths display should still exist in the drawing state
-    EXPECT_TRUE(hasDrawingDisplayState(existing.token()));
-
-    // The display transaction needed flasg should be set
-    EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
-}
-
-TEST_F(DisplayTransactionTest, destroyDisplayHandlesUnknownDisplay) {
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    sp<BBinder> displayToken = new BBinder();
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.destroyDisplay(displayToken);
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::notifyPowerBoost
- */
-
-TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) {
-    mFlinger.scheduler()->replaceTouchTimer(100);
-    std::this_thread::sleep_for(10ms);                  // wait for callback to be triggered
-    EXPECT_TRUE(mFlinger.scheduler()->isTouchActive()); // Starting timer activates touch
-
-    std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
-    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
-
-    EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::CAMERA_SHOT)));
-    std::this_thread::sleep_for(10ms); // wait for callback to maybe be triggered
-    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
-
-    std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
-    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
-
-    EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::INTERACTION)));
-    std::this_thread::sleep_for(10ms); // wait for callback to be triggered.
-    EXPECT_TRUE(mFlinger.scheduler()->isTouchActive());
-}
-
-/* ------------------------------------------------------------------------
- * DisplayDevice::GetBestColorMode
- */
-class GetBestColorModeTest : public DisplayTransactionTest {
-public:
-    void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
-
-    void addHwcColorModesMapping(ui::ColorMode colorMode,
-                                 std::vector<ui::RenderIntent> renderIntents) {
-        mHwcColorModes[colorMode] = renderIntents;
-    }
-
-    void setInputDataspace(ui::Dataspace dataspace) { mInputDataspace = dataspace; }
-
-    void setInputRenderIntent(ui::RenderIntent renderIntent) { mInputRenderIntent = renderIntent; }
-
-    void getBestColorMode() {
-        auto displayDevice =
-                injectDefaultInternalDisplay([this](FakeDisplayDeviceInjector& injector) {
-                    injector.setHwcColorModes(mHwcColorModes);
-                    injector.setHasWideColorGamut(mHasWideColorGamut);
-                    injector.setNativeWindow(mNativeWindow);
-                });
-
-        displayDevice->getCompositionDisplay()
-                ->getDisplayColorProfile()
-                ->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
-                                   &mOutColorMode, &mOutRenderIntent);
-    }
-
-    ui::Dataspace mOutDataspace;
-    ui::ColorMode mOutColorMode;
-    ui::RenderIntent mOutRenderIntent;
-
-private:
-    ui::Dataspace mInputDataspace;
-    ui::RenderIntent mInputRenderIntent;
-    bool mHasWideColorGamut = false;
-    std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> mHwcColorModes;
-};
-
-TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeSRGB) {
-    addHwcColorModesMapping(ui::ColorMode::SRGB,
-                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
-    setInputDataspace(ui::Dataspace::DISPLAY_P3);
-    setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
-    setHasWideColorGamut(true);
-
-    getBestColorMode();
-
-    ASSERT_EQ(ui::Dataspace::V0_SRGB, mOutDataspace);
-    ASSERT_EQ(ui::ColorMode::SRGB, mOutColorMode);
-    ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
-}
-
-TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDisplayP3) {
-    addHwcColorModesMapping(ui::ColorMode::DISPLAY_P3,
-                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
-    addHwcColorModesMapping(ui::ColorMode::SRGB,
-                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
-    addHwcColorModesMapping(ui::ColorMode::DISPLAY_BT2020,
-                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
-    setInputDataspace(ui::Dataspace::DISPLAY_P3);
-    setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
-    setHasWideColorGamut(true);
-
-    getBestColorMode();
-
-    ASSERT_EQ(ui::Dataspace::DISPLAY_P3, mOutDataspace);
-    ASSERT_EQ(ui::ColorMode::DISPLAY_P3, mOutColorMode);
-    ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
-}
-
-TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDISPLAY_BT2020) {
-    addHwcColorModesMapping(ui::ColorMode::DISPLAY_BT2020,
-                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
-    setInputDataspace(ui::Dataspace::DISPLAY_P3);
-    setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
-    setHasWideColorGamut(true);
-
-    getBestColorMode();
-
-    ASSERT_EQ(ui::Dataspace::DISPLAY_BT2020, mOutDataspace);
-    ASSERT_EQ(ui::ColorMode::DISPLAY_BT2020, mOutColorMode);
-    ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
-}
-
-/* ------------------------------------------------------------------------
- * 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(ui::ROTATION_0, compositionState.displaySpace.orientation);
-        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
-        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
-        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
-        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(ui::ROTATION_90, compositionState.displaySpace.orientation);
-        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
-        // For 90, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
-        // size width and height swapped
-        EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)),
-                  compositionState.orientedDisplaySpace.content);
-        EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
-        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(ui::ROTATION_180, compositionState.displaySpace.orientation);
-        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
-        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
-        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(ui::ROTATION_270, compositionState.displaySpace.orientation);
-        EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
-        // For 270, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
-        // size width and height swapped
-        EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)),
-                  compositionState.orientedDisplaySpace.content);
-        EXPECT_EQ(Rect(swapWH(mHardwareDisplaySize)), compositionState.layerStackSpace.content);
-        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
- */
-
-class GetDisplayNativePrimaries : public DisplayTransactionTest {
-public:
-    GetDisplayNativePrimaries();
-    void populateDummyDisplayNativePrimaries(ui::DisplayPrimaries& primaries);
-    void checkDummyDisplayNativePrimaries(const ui::DisplayPrimaries& primaries);
-
-private:
-    static constexpr float mStartingTestValue = 1.0f;
-};
-
-GetDisplayNativePrimaries::GetDisplayNativePrimaries() {
-    SimplePrimaryDisplayCase::Display::injectHwcDisplay(this);
-    injectFakeNativeWindowSurfaceFactory();
-}
-
-void GetDisplayNativePrimaries::populateDummyDisplayNativePrimaries(
-        ui::DisplayPrimaries& primaries) {
-    float startingVal = mStartingTestValue;
-    primaries.red.X = startingVal++;
-    primaries.red.Y = startingVal++;
-    primaries.red.Z = startingVal++;
-    primaries.green.X = startingVal++;
-    primaries.green.Y = startingVal++;
-    primaries.green.Z = startingVal++;
-    primaries.blue.X = startingVal++;
-    primaries.blue.Y = startingVal++;
-    primaries.blue.Z = startingVal++;
-    primaries.white.X = startingVal++;
-    primaries.white.Y = startingVal++;
-    primaries.white.Z = startingVal++;
-}
-
-void GetDisplayNativePrimaries::checkDummyDisplayNativePrimaries(
-        const ui::DisplayPrimaries& primaries) {
-    float startingVal = mStartingTestValue;
-    EXPECT_EQ(primaries.red.X, startingVal++);
-    EXPECT_EQ(primaries.red.Y, startingVal++);
-    EXPECT_EQ(primaries.red.Z, startingVal++);
-    EXPECT_EQ(primaries.green.X, startingVal++);
-    EXPECT_EQ(primaries.green.Y, startingVal++);
-    EXPECT_EQ(primaries.green.Z, startingVal++);
-    EXPECT_EQ(primaries.blue.X, startingVal++);
-    EXPECT_EQ(primaries.blue.Y, startingVal++);
-    EXPECT_EQ(primaries.blue.Z, startingVal++);
-    EXPECT_EQ(primaries.white.X, startingVal++);
-    EXPECT_EQ(primaries.white.Y, startingVal++);
-    EXPECT_EQ(primaries.white.Z, startingVal++);
-}
-
-TEST_F(GetDisplayNativePrimaries, nullDisplayToken) {
-    ui::DisplayPrimaries primaries;
-    EXPECT_EQ(BAD_VALUE, mFlinger.getDisplayNativePrimaries(nullptr, primaries));
-}
-
-TEST_F(GetDisplayNativePrimaries, internalDisplayWithPrimariesData) {
-    auto injector = SimplePrimaryDisplayCase::Display::makeFakeExistingDisplayInjector(this);
-    injector.inject();
-    auto internalDisplayToken = injector.token();
-
-    ui::DisplayPrimaries expectedPrimaries;
-    populateDummyDisplayNativePrimaries(expectedPrimaries);
-    mFlinger.setInternalDisplayPrimaries(expectedPrimaries);
-
-    ui::DisplayPrimaries primaries;
-    EXPECT_EQ(NO_ERROR, mFlinger.getDisplayNativePrimaries(internalDisplayToken, primaries));
-
-    checkDummyDisplayNativePrimaries(primaries);
-}
-
-TEST_F(GetDisplayNativePrimaries, notInternalDisplayToken) {
-    sp<BBinder> notInternalDisplayToken = new BBinder();
-
-    ui::DisplayPrimaries primaries;
-    populateDummyDisplayNativePrimaries(primaries);
-    EXPECT_EQ(NAME_NOT_FOUND,
-              mFlinger.getDisplayNativePrimaries(notInternalDisplayToken, primaries));
-
-    // Check primaries argument wasn't modified in case of failure
-    checkDummyDisplayNativePrimaries(primaries);
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::setupNewDisplayDeviceInternal
- */
-
-class SetupNewDisplayDeviceInternalTest : public DisplayTransactionTest {
-public:
-    template <typename T>
-    void setupNewDisplayDeviceInternalTest();
-};
-
-template <typename Case>
-void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() {
-    const sp<BBinder> displayToken = new BBinder();
-    const sp<compositionengine::mock::DisplaySurface> displaySurface =
-            new compositionengine::mock::DisplaySurface();
-    const sp<mock::GraphicBufferProducer> producer = new mock::GraphicBufferProducer();
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // Wide color displays support is configured appropriately
-    Case::WideColorSupport::injectConfigChange(this);
-
-    // The display is setup with the HWC.
-    Case::Display::injectHwcDisplay(this);
-
-    // SurfaceFlinger will use a test-controlled factory for native window
-    // surfaces.
-    injectFakeNativeWindowSurfaceFactory();
-
-    // A compositionengine::Display has already been created
-    auto compositionDisplay = Case::Display::injectCompositionDisplay(this);
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    // Various native window calls will be made.
-    Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
-    Case::Display::setupHwcGetActiveConfigCallExpectations(this);
-    Case::WideColorSupport::setupComposerCallExpectations(this);
-    Case::HdrSupport::setupComposerCallExpectations(this);
-    Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    DisplayDeviceState state;
-    if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
-        const auto displayId = PhysicalDisplayId::tryCast(Case::Display::DISPLAY_ID::get());
-        ASSERT_TRUE(displayId);
-        const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
-        ASSERT_TRUE(hwcDisplayId);
-        state.physical = {.id = *displayId, .type = *connectionType, .hwcDisplayId = *hwcDisplayId};
-    }
-
-    state.isSecure = static_cast<bool>(Case::Display::SECURE);
-
-    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());
-    EXPECT_EQ(Case::Display::WIDTH, device->getWidth());
-    EXPECT_EQ(Case::Display::HEIGHT, device->getHeight());
-    EXPECT_EQ(Case::WideColorSupport::WIDE_COLOR_SUPPORTED, device->hasWideColorGamut());
-    EXPECT_EQ(Case::HdrSupport::HDR10_PLUS_SUPPORTED, device->hasHDR10PlusSupport());
-    EXPECT_EQ(Case::HdrSupport::HDR10_SUPPORTED, device->hasHDR10Support());
-    EXPECT_EQ(Case::HdrSupport::HDR_HLG_SUPPORTED, device->hasHLGSupport());
-    EXPECT_EQ(Case::HdrSupport::HDR_DOLBY_VISION_SUPPORTED, device->hasDolbyVisionSupport());
-    // Note: This is not Case::Display::HWC_ACTIVE_CONFIG_ID as the ids are
-    // remapped, and the test only ever sets up one config. If there were an error
-    // looking up the remapped index, device->getActiveConfig() would be -1 instead.
-    EXPECT_EQ(0, device->getActiveConfig().value());
-    EXPECT_EQ(Case::PerFrameMetadataSupport::PER_FRAME_METADATA_KEYS,
-              device->getSupportedPerFrameMetadata());
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createSimplePrimaryDisplay) {
-    setupNewDisplayDeviceInternalTest<SimplePrimaryDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createSimpleExternalDisplay) {
-    setupNewDisplayDeviceInternalTest<SimpleExternalDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createNonHwcVirtualDisplay) {
-    setupNewDisplayDeviceInternalTest<NonHwcVirtualDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createHwcVirtualDisplay) {
-    setupNewDisplayDeviceInternalTest<HwcVirtualDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) {
-    setupNewDisplayDeviceInternalTest<WideColorP3ColorimetricDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createHdr10PlusDisplay) {
-    setupNewDisplayDeviceInternalTest<Hdr10PlusDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createHdr10Display) {
-    setupNewDisplayDeviceInternalTest<Hdr10DisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createHdrHlgDisplay) {
-    setupNewDisplayDeviceInternalTest<HdrHlgDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createHdrDolbyVisionDisplay) {
-    setupNewDisplayDeviceInternalTest<HdrDolbyVisionDisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createHdrSmpte2086DisplayCase) {
-    setupNewDisplayDeviceInternalTest<HdrSmpte2086DisplayCase>();
-}
-
-TEST_F(SetupNewDisplayDeviceInternalTest, createHdrCta816_3_DisplayCase) {
-    setupNewDisplayDeviceInternalTest<HdrCta861_3_DisplayCase>();
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::handleTransactionLocked(eDisplayTransactionNeeded)
- */
-
-class HandleTransactionLockedTest : public DisplayTransactionTest {
-public:
-    template <typename Case>
-    void setupCommonPreconditions();
-
-    template <typename Case, bool connected>
-    static void expectHotplugReceived(mock::EventThread*);
-
-    template <typename Case>
-    void setupCommonCallExpectationsForConnectProcessing();
-
-    template <typename Case>
-    void setupCommonCallExpectationsForDisconnectProcessing();
-
-    template <typename Case>
-    void processesHotplugConnectCommon();
-
-    template <typename Case>
-    void ignoresHotplugConnectCommon();
-
-    template <typename Case>
-    void processesHotplugDisconnectCommon();
-
-    template <typename Case>
-    void verifyDisplayIsConnected(const sp<IBinder>& displayToken);
-
-    template <typename Case>
-    void verifyPhysicalDisplayIsConnected();
-
-    void verifyDisplayIsNotConnected(const sp<IBinder>& displayToken);
-};
-
-template <typename Case>
-void HandleTransactionLockedTest::setupCommonPreconditions() {
-    // Wide color displays support is configured appropriately
-    Case::WideColorSupport::injectConfigChange(this);
-
-    // SurfaceFlinger will use a test-controlled factory for BufferQueues
-    injectFakeBufferQueueFactory();
-
-    // SurfaceFlinger will use a test-controlled factory for native window
-    // surfaces.
-    injectFakeNativeWindowSurfaceFactory();
-}
-
-template <typename Case, bool connected>
-void HandleTransactionLockedTest::expectHotplugReceived(mock::EventThread* eventThread) {
-    const auto convert = [](auto physicalDisplayId) {
-        return std::make_optional(DisplayId{physicalDisplayId});
-    };
-
-    EXPECT_CALL(*eventThread,
-                onHotplugReceived(ResultOf(convert, Case::Display::DISPLAY_ID::get()), connected))
-            .Times(1);
-}
-
-template <typename Case>
-void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessing() {
-    Case::Display::setupHwcHotplugCallExpectations(this);
-
-    Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
-    Case::Display::setupFramebufferProducerBufferQueueCallExpectations(this);
-    Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
-    Case::Display::setupHwcGetActiveConfigCallExpectations(this);
-
-    Case::WideColorSupport::setupComposerCallExpectations(this);
-    Case::HdrSupport::setupComposerCallExpectations(this);
-    Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
-
-    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
-    expectHotplugReceived<Case, true>(mEventThread);
-    expectHotplugReceived<Case, true>(mSFEventThread);
-}
-
-template <typename Case>
-void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
-    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
-
-    expectHotplugReceived<Case, false>(mEventThread);
-    expectHotplugReceived<Case, false>(mSFEventThread);
-}
-
-template <typename Case>
-void HandleTransactionLockedTest::verifyDisplayIsConnected(const sp<IBinder>& displayToken) {
-    // The display device should have been set up in the list of displays.
-    ASSERT_TRUE(hasDisplayDevice(displayToken));
-    const auto& device = getDisplayDevice(displayToken);
-    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 = PhysicalDisplayId::tryCast(Case::Display::DISPLAY_ID::get());
-        ASSERT_TRUE(displayId);
-        const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
-        ASSERT_TRUE(hwcDisplayId);
-        expectedPhysical = {.id = *displayId,
-                            .type = *connectionType,
-                            .hwcDisplayId = *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(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(expectedPhysical, draw.physical);
-}
-
-template <typename Case>
-void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() {
-    // HWComposer should have an entry for the display
-    EXPECT_TRUE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
-
-    // SF should have a display token.
-    const auto displayId = Case::Display::DISPLAY_ID::get();
-    ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
-    ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
-    auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[displayId];
-
-    verifyDisplayIsConnected<Case>(displayToken);
-}
-
-void HandleTransactionLockedTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) {
-    EXPECT_FALSE(hasDisplayDevice(displayToken));
-    EXPECT_FALSE(hasCurrentDisplayState(displayToken));
-    EXPECT_FALSE(hasDrawingDisplayState(displayToken));
-}
-
-template <typename Case>
-void HandleTransactionLockedTest::processesHotplugConnectCommon() {
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    setupCommonPreconditions<Case>();
-
-    // A hotplug connect event is enqueued for a display
-    Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    setupCommonCallExpectationsForConnectProcessing<Case>();
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    verifyPhysicalDisplayIsConnected<Case>();
-
-    // --------------------------------------------------------------------
-    // Cleanup conditions
-
-    EXPECT_CALL(*mComposer,
-                setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
-            .WillOnce(Return(Error::NONE));
-    EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
-}
-
-template <typename Case>
-void HandleTransactionLockedTest::ignoresHotplugConnectCommon() {
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    setupCommonPreconditions<Case>();
-
-    // A hotplug connect event is enqueued for a display
-    Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // HWComposer should not have an entry for the display
-    EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
-}
-
-template <typename Case>
-void HandleTransactionLockedTest::processesHotplugDisconnectCommon() {
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    setupCommonPreconditions<Case>();
-
-    // A hotplug disconnect event is enqueued for a display
-    Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
-
-    // The display is already completely set up.
-    Case::Display::injectHwcDisplay(this);
-    auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
-    existing.inject();
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    EXPECT_CALL(*mComposer, getDisplayIdentificationData(Case::Display::HWC_DISPLAY_ID, _, _))
-            .Times(0);
-
-    setupCommonCallExpectationsForDisconnectProcessing<Case>();
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // HWComposer should not have an entry for the display
-    EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
-
-    // SF should not have a display token.
-    const auto displayId = Case::Display::DISPLAY_ID::get();
-    ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
-    ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
-
-    // The existing token should have been removed
-    verifyDisplayIsNotConnected(existing.token());
-}
-
-TEST_F(HandleTransactionLockedTest, processesHotplugConnectPrimaryDisplay) {
-    processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
-}
-
-TEST_F(HandleTransactionLockedTest,
-       processesHotplugConnectPrimaryDisplayWithExternalAlreadyConnected) {
-    // Inject an external display.
-    ExternalDisplayVariant::injectHwcDisplay(this);
-
-    processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
-}
-
-TEST_F(HandleTransactionLockedTest, processesHotplugConnectExternalDisplay) {
-    // Inject a primary display.
-    PrimaryDisplayVariant::injectHwcDisplay(this);
-
-    processesHotplugConnectCommon<SimpleExternalDisplayCase>();
-}
-
-TEST_F(HandleTransactionLockedTest, ignoresHotplugConnectIfPrimaryAndExternalAlreadyConnected) {
-    // Inject both a primary and external display.
-    PrimaryDisplayVariant::injectHwcDisplay(this);
-    ExternalDisplayVariant::injectHwcDisplay(this);
-
-    // TODO: This is an unnecessary call.
-    EXPECT_CALL(*mComposer,
-                getDisplayIdentificationData(TertiaryDisplayVariant::HWC_DISPLAY_ID, _, _))
-            .WillOnce(DoAll(SetArgPointee<1>(TertiaryDisplay::PORT),
-                            SetArgPointee<2>(TertiaryDisplay::GET_IDENTIFICATION_DATA()),
-                            Return(Error::NONE)));
-
-    ignoresHotplugConnectCommon<SimpleTertiaryDisplayCase>();
-}
-
-TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectPrimaryDisplay) {
-    processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>();
-}
-
-TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectExternalDisplay) {
-    processesHotplugDisconnectCommon<SimpleExternalDisplayCase>();
-}
-
-TEST_F(HandleTransactionLockedTest, processesHotplugConnectThenDisconnectPrimary) {
-    using Case = SimplePrimaryDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    setupCommonPreconditions<Case>();
-
-    // A hotplug connect event is enqueued for a display
-    Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
-    // A hotplug disconnect event is also enqueued for the same display
-    Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    setupCommonCallExpectationsForConnectProcessing<Case>();
-    setupCommonCallExpectationsForDisconnectProcessing<Case>();
-
-    EXPECT_CALL(*mComposer,
-                setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
-            .WillOnce(Return(Error::NONE));
-    EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // HWComposer should not have an entry for the display
-    EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
-
-    // SF should not have a display token.
-    const auto displayId = Case::Display::DISPLAY_ID::get();
-    ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
-    ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
-}
-
-TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary) {
-    using Case = SimplePrimaryDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    setupCommonPreconditions<Case>();
-
-    // The display is already completely set up.
-    Case::Display::injectHwcDisplay(this);
-    auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
-    existing.inject();
-
-    // A hotplug disconnect event is enqueued for a display
-    Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
-    // A hotplug connect event is also enqueued for the same display
-    Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    setupCommonCallExpectationsForConnectProcessing<Case>();
-    setupCommonCallExpectationsForDisconnectProcessing<Case>();
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The existing token should have been removed
-    verifyDisplayIsNotConnected(existing.token());
-    const auto displayId = Case::Display::DISPLAY_ID::get();
-    ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
-    ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
-    EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[displayId]);
-
-    // A new display should be connected in its place
-
-    verifyPhysicalDisplayIsConnected<Case>();
-
-    // --------------------------------------------------------------------
-    // Cleanup conditions
-
-    EXPECT_CALL(*mComposer,
-                setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
-            .WillOnce(Return(Error::NONE));
-    EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
-}
-
-TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAdded) {
-    using Case = HwcVirtualDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // The HWC supports at least one virtual display
-    injectMockComposer(1);
-
-    setupCommonPreconditions<Case>();
-
-    // A virtual display was added to the current state, and it has a
-    // surface(producer)
-    sp<BBinder> displayToken = new BBinder();
-
-    DisplayDeviceState state;
-    state.isSecure = static_cast<bool>(Case::Display::SECURE);
-
-    sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()};
-    state.surface = surface;
-    mFlinger.mutableCurrentState().displays.add(displayToken, state);
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
-    Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
-
-    EXPECT_CALL(*surface, query(NATIVE_WINDOW_WIDTH, _))
-            .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::WIDTH), Return(NO_ERROR)));
-    EXPECT_CALL(*surface, query(NATIVE_WINDOW_HEIGHT, _))
-            .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::HEIGHT), Return(NO_ERROR)));
-    EXPECT_CALL(*surface, query(NATIVE_WINDOW_FORMAT, _))
-            .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT),
-                                  Return(NO_ERROR)));
-    EXPECT_CALL(*surface, query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, _))
-            .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
-
-    EXPECT_CALL(*surface, setAsyncMode(true)).Times(1);
-
-    EXPECT_CALL(*mProducer, connect(_, NATIVE_WINDOW_API_EGL, false, _)).Times(1);
-    EXPECT_CALL(*mProducer, disconnect(_, _)).Times(1);
-
-    Case::Display::setupHwcVirtualDisplayCreationCallExpectations(this);
-    Case::WideColorSupport::setupComposerCallExpectations(this);
-    Case::HdrSupport::setupComposerCallExpectations(this);
-    Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The display device should have been set up in the list of displays.
-    verifyDisplayIsConnected<Case>(displayToken);
-
-    // --------------------------------------------------------------------
-    // Cleanup conditions
-
-    EXPECT_CALL(*mComposer, destroyVirtualDisplay(Case::Display::HWC_DISPLAY_ID))
-            .WillOnce(Return(Error::NONE));
-    EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
-
-    // Cleanup
-    mFlinger.mutableCurrentState().displays.removeItem(displayToken);
-    mFlinger.mutableDrawingState().displays.removeItem(displayToken);
-}
-
-TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAddedWithNoSurface) {
-    using Case = HwcVirtualDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // The HWC supports at least one virtual display
-    injectMockComposer(1);
-
-    setupCommonPreconditions<Case>();
-
-    // A virtual display was added to the current state, but it does not have a
-    // surface.
-    sp<BBinder> displayToken = new BBinder();
-
-    DisplayDeviceState state;
-    state.isSecure = static_cast<bool>(Case::Display::SECURE);
-
-    mFlinger.mutableCurrentState().displays.add(displayToken, state);
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // There will not be a display device set up.
-    EXPECT_FALSE(hasDisplayDevice(displayToken));
-
-    // The drawing display state will be set from the current display state.
-    ASSERT_TRUE(hasDrawingDisplayState(displayToken));
-    const auto& draw = getDrawingDisplayState(displayToken);
-    EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
-}
-
-TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) {
-    using Case = HwcVirtualDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A virtual display is set up but is removed from the current state.
-    const auto displayId = Case::Display::DISPLAY_ID::get();
-    ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId));
-    mFlinger.mutableHwcDisplayData().try_emplace(displayId);
-    Case::Display::injectHwcDisplay(this);
-    auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
-    existing.inject();
-    mFlinger.mutableCurrentState().displays.removeItem(existing.token());
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The existing token should have been removed
-    verifyDisplayIsNotConnected(existing.token());
-}
-
-TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackChanges) {
-    using Case = NonHwcVirtualDisplayCase;
-
-    constexpr uint32_t oldLayerStack = 0u;
-    constexpr uint32_t newLayerStack = 123u;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // There is a change to the layerStack state
-    display.mutableDrawingDisplayState().layerStack = oldLayerStack;
-    display.mutableCurrentDisplayState().layerStack = newLayerStack;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    EXPECT_EQ(newLayerStack, display.mutableDisplayDevice()->getLayerStack());
-}
-
-TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) {
-    using Case = NonHwcVirtualDisplayCase;
-
-    constexpr ui::Rotation oldTransform = ui::ROTATION_0;
-    constexpr ui::Rotation newTransform = ui::ROTATION_180;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // There is a change to the orientation state
-    display.mutableDrawingDisplayState().orientation = oldTransform;
-    display.mutableCurrentDisplayState().orientation = newTransform;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    EXPECT_EQ(newTransform, display.mutableDisplayDevice()->getOrientation());
-}
-
-TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackRectChanges) {
-    using Case = NonHwcVirtualDisplayCase;
-
-    const Rect oldLayerStackRect(0, 0, 0, 0);
-    const Rect newLayerStackRect(0, 0, 123, 456);
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // There is a change to the layerStackSpaceRect state
-    display.mutableDrawingDisplayState().layerStackSpaceRect = oldLayerStackRect;
-    display.mutableCurrentDisplayState().layerStackSpaceRect = newLayerStackRect;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    EXPECT_EQ(newLayerStackRect, display.mutableDisplayDevice()->getLayerStackSpaceRect());
-}
-
-TEST_F(HandleTransactionLockedTest, processesDisplayFrameChanges) {
-    using Case = NonHwcVirtualDisplayCase;
-
-    const Rect oldFrame(0, 0, 0, 0);
-    const Rect newFrame(0, 0, 123, 456);
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // There is a change to the layerStackSpaceRect state
-    display.mutableDrawingDisplayState().orientedDisplaySpaceRect = oldFrame;
-    display.mutableCurrentDisplayState().orientedDisplaySpaceRect = newFrame;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    EXPECT_EQ(newFrame, display.mutableDisplayDevice()->getOrientedDisplaySpaceRect());
-}
-
-TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) {
-    using Case = NonHwcVirtualDisplayCase;
-
-    constexpr int oldWidth = 0;
-    constexpr int oldHeight = 10;
-    constexpr int newWidth = 123;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is set up
-    auto nativeWindow = new mock::NativeWindow();
-    auto displaySurface = new compositionengine::mock::DisplaySurface();
-    sp<GraphicBuffer> buf = new GraphicBuffer();
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.setNativeWindow(nativeWindow);
-    display.setDisplaySurface(displaySurface);
-    // Setup injection expections
-    EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
-            .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
-    EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
-            .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
-    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
-    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
-    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
-    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1);
-    display.inject();
-
-    // There is a change to the layerStackSpaceRect state
-    display.mutableDrawingDisplayState().width = oldWidth;
-    display.mutableDrawingDisplayState().height = oldHeight;
-    display.mutableCurrentDisplayState().width = newWidth;
-    display.mutableCurrentDisplayState().height = oldHeight;
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    EXPECT_CALL(*displaySurface, resizeBuffers(newWidth, oldHeight)).Times(1);
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-}
-
-TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) {
-    using Case = NonHwcVirtualDisplayCase;
-
-    constexpr int oldWidth = 0;
-    constexpr int oldHeight = 10;
-    constexpr int newHeight = 123;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is set up
-    auto nativeWindow = new mock::NativeWindow();
-    auto displaySurface = new compositionengine::mock::DisplaySurface();
-    sp<GraphicBuffer> buf = new GraphicBuffer();
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.setNativeWindow(nativeWindow);
-    display.setDisplaySurface(displaySurface);
-    // Setup injection expections
-    EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
-            .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
-    EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
-            .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
-    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
-    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
-    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
-    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1);
-    display.inject();
-
-    // There is a change to the layerStackSpaceRect state
-    display.mutableDrawingDisplayState().width = oldWidth;
-    display.mutableDrawingDisplayState().height = oldHeight;
-    display.mutableCurrentDisplayState().width = oldWidth;
-    display.mutableCurrentDisplayState().height = newHeight;
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    EXPECT_CALL(*displaySurface, resizeBuffers(oldWidth, newHeight)).Times(1);
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::setDisplayStateLocked
- */
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWithUnknownDisplay) {
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // We have an unknown display token not associated with a known display
-    sp<BBinder> displayToken = new BBinder();
-
-    // The requested display state references the unknown display.
-    DisplayState state;
-    state.what = DisplayState::eLayerStackChanged;
-    state.token = displayToken;
-    state.layerStack = 456;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags are empty
-    EXPECT_EQ(0u, flags);
-
-    // The display token still doesn't match anything known.
-    EXPECT_FALSE(hasCurrentDisplayState(displayToken));
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWhenNoChanges) {
-    using Case = SimplePrimaryDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is already set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // No changes are made to the display
-    DisplayState state;
-    state.what = 0;
-    state.token = display.token();
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags are empty
-    EXPECT_EQ(0u, flags);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfSurfaceDidNotChange) {
-    using Case = SimplePrimaryDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is already set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // There is a surface that can be set.
-    sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer();
-
-    // The current display state has the surface set
-    display.mutableCurrentDisplayState().surface = surface;
-
-    // The incoming request sets the same surface
-    DisplayState state;
-    state.what = DisplayState::eSurfaceChanged;
-    state.token = display.token();
-    state.surface = surface;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags are empty
-    EXPECT_EQ(0u, flags);
-
-    // The current display state is unchanged.
-    EXPECT_EQ(surface.get(), display.getCurrentDisplayState().surface.get());
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfSurfaceChanged) {
-    using Case = SimplePrimaryDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is already set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // There is a surface that can be set.
-    sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer();
-
-    // The current display state does not have a surface
-    display.mutableCurrentDisplayState().surface = nullptr;
-
-    // The incoming request sets a surface
-    DisplayState state;
-    state.what = DisplayState::eSurfaceChanged;
-    state.token = display.token();
-    state.surface = surface;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags indicate a transaction is needed
-    EXPECT_EQ(eDisplayTransactionNeeded, flags);
-
-    // The current display layer stack state is set to the new value
-    EXPECT_EQ(surface.get(), display.getCurrentDisplayState().surface.get());
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfLayerStackDidNotChange) {
-    using Case = SimplePrimaryDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is already set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // The display has a layer stack set
-    display.mutableCurrentDisplayState().layerStack = 456u;
-
-    // The incoming request sets the same layer stack
-    DisplayState state;
-    state.what = DisplayState::eLayerStackChanged;
-    state.token = display.token();
-    state.layerStack = 456u;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags are empty
-    EXPECT_EQ(0u, flags);
-
-    // The current display state is unchanged
-    EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfLayerStackChanged) {
-    using Case = SimplePrimaryDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // The display has a layer stack set
-    display.mutableCurrentDisplayState().layerStack = 654u;
-
-    // The incoming request sets a different layer stack
-    DisplayState state;
-    state.what = DisplayState::eLayerStackChanged;
-    state.token = display.token();
-    state.layerStack = 456u;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags indicate a transaction is needed
-    EXPECT_EQ(eDisplayTransactionNeeded, flags);
-
-    // The desired display state has been set to the new value.
-    EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfProjectionDidNotChange) {
-    using Case = SimplePrimaryDisplayCase;
-    constexpr ui::Rotation initialOrientation = ui::ROTATION_180;
-    const Rect initialOrientedDisplayRect = {1, 2, 3, 4};
-    const Rect initialLayerStackRect = {5, 6, 7, 8};
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // The current display state projection state is all set
-    display.mutableCurrentDisplayState().orientation = initialOrientation;
-    display.mutableCurrentDisplayState().orientedDisplaySpaceRect = initialOrientedDisplayRect;
-    display.mutableCurrentDisplayState().layerStackSpaceRect = initialLayerStackRect;
-
-    // The incoming request sets the same projection state
-    DisplayState state;
-    state.what = DisplayState::eDisplayProjectionChanged;
-    state.token = display.token();
-    state.orientation = initialOrientation;
-    state.orientedDisplaySpaceRect = initialOrientedDisplayRect;
-    state.layerStackSpaceRect = initialLayerStackRect;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags are empty
-    EXPECT_EQ(0u, flags);
-
-    // The current display state is unchanged
-    EXPECT_EQ(initialOrientation, display.getCurrentDisplayState().orientation);
-
-    EXPECT_EQ(initialOrientedDisplayRect,
-              display.getCurrentDisplayState().orientedDisplaySpaceRect);
-    EXPECT_EQ(initialLayerStackRect, display.getCurrentDisplayState().layerStackSpaceRect);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfOrientationChanged) {
-    using Case = SimplePrimaryDisplayCase;
-    constexpr ui::Rotation initialOrientation = ui::ROTATION_90;
-    constexpr ui::Rotation desiredOrientation = ui::ROTATION_180;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // The current display state has an orientation set
-    display.mutableCurrentDisplayState().orientation = initialOrientation;
-
-    // The incoming request sets a different orientation
-    DisplayState state;
-    state.what = DisplayState::eDisplayProjectionChanged;
-    state.token = display.token();
-    state.orientation = desiredOrientation;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags indicate a transaction is needed
-    EXPECT_EQ(eDisplayTransactionNeeded, flags);
-
-    // The current display state has the new value.
-    EXPECT_EQ(desiredOrientation, display.getCurrentDisplayState().orientation);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfFrameChanged) {
-    using Case = SimplePrimaryDisplayCase;
-    const Rect initialOrientedDisplayRect = {0, 0, 0, 0};
-    const Rect desiredOrientedDisplayRect = {5, 6, 7, 8};
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // The current display state does not have a orientedDisplaySpaceRect
-    display.mutableCurrentDisplayState().orientedDisplaySpaceRect = initialOrientedDisplayRect;
-
-    // The incoming request sets a orientedDisplaySpaceRect
-    DisplayState state;
-    state.what = DisplayState::eDisplayProjectionChanged;
-    state.token = display.token();
-    state.orientedDisplaySpaceRect = desiredOrientedDisplayRect;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags indicate a transaction is needed
-    EXPECT_EQ(eDisplayTransactionNeeded, flags);
-
-    // The current display state has the new value.
-    EXPECT_EQ(desiredOrientedDisplayRect,
-              display.getCurrentDisplayState().orientedDisplaySpaceRect);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfLayerStackRectChanged) {
-    using Case = SimplePrimaryDisplayCase;
-    const Rect initialLayerStackRect = {0, 0, 0, 0};
-    const Rect desiredLayerStackRect = {5, 6, 7, 8};
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // The current display state does not have a layerStackSpaceRect
-    display.mutableCurrentDisplayState().layerStackSpaceRect = initialLayerStackRect;
-
-    // The incoming request sets a layerStackSpaceRect
-    DisplayState state;
-    state.what = DisplayState::eDisplayProjectionChanged;
-    state.token = display.token();
-    state.layerStackSpaceRect = desiredLayerStackRect;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags indicate a transaction is needed
-    EXPECT_EQ(eDisplayTransactionNeeded, flags);
-
-    // The current display state has the new value.
-    EXPECT_EQ(desiredLayerStackRect, display.getCurrentDisplayState().layerStackSpaceRect);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfSizeDidNotChange) {
-    using Case = SimplePrimaryDisplayCase;
-    constexpr uint32_t initialWidth = 1024;
-    constexpr uint32_t initialHeight = 768;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // The current display state has a size set
-    display.mutableCurrentDisplayState().width = initialWidth;
-    display.mutableCurrentDisplayState().height = initialHeight;
-
-    // The incoming request sets the same display size
-    DisplayState state;
-    state.what = DisplayState::eDisplaySizeChanged;
-    state.token = display.token();
-    state.width = initialWidth;
-    state.height = initialHeight;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags are empty
-    EXPECT_EQ(0u, flags);
-
-    // The current display state is unchanged
-    EXPECT_EQ(initialWidth, display.getCurrentDisplayState().width);
-    EXPECT_EQ(initialHeight, display.getCurrentDisplayState().height);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfWidthChanged) {
-    using Case = SimplePrimaryDisplayCase;
-    constexpr uint32_t initialWidth = 0;
-    constexpr uint32_t desiredWidth = 1024;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // The display does not yet have a width
-    display.mutableCurrentDisplayState().width = initialWidth;
-
-    // The incoming request sets a display width
-    DisplayState state;
-    state.what = DisplayState::eDisplaySizeChanged;
-    state.token = display.token();
-    state.width = desiredWidth;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags indicate a transaction is needed
-    EXPECT_EQ(eDisplayTransactionNeeded, flags);
-
-    // The current display state has the new value.
-    EXPECT_EQ(desiredWidth, display.getCurrentDisplayState().width);
-}
-
-TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfHeightChanged) {
-    using Case = SimplePrimaryDisplayCase;
-    constexpr uint32_t initialHeight = 0;
-    constexpr uint32_t desiredHeight = 768;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A display is set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // The display does not yet have a height
-    display.mutableCurrentDisplayState().height = initialHeight;
-
-    // The incoming request sets a display height
-    DisplayState state;
-    state.what = DisplayState::eDisplaySizeChanged;
-    state.token = display.token();
-    state.height = desiredHeight;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags indicate a transaction is needed
-    EXPECT_EQ(eDisplayTransactionNeeded, flags);
-
-    // The current display state has the new value.
-    EXPECT_EQ(desiredHeight, display.getCurrentDisplayState().height);
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::onInitializeDisplays
- */
-
-TEST_F(DisplayTransactionTest, onInitializeDisplaysSetsUpPrimaryDisplay) {
-    using Case = SimplePrimaryDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A primary display is set up
-    Case::Display::injectHwcDisplay(this);
-    auto primaryDisplay = Case::Display::makeFakeExistingDisplayInjector(this);
-    primaryDisplay.inject();
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    // We expect the surface interceptor to possibly be used, but we treat it as
-    // disabled since it is called as a side effect rather than directly by this
-    // function.
-    EXPECT_CALL(*mSurfaceInterceptor, isEnabled()).WillOnce(Return(false));
-
-    // We expect a call to get the active display config.
-    Case::Display::setupHwcGetActiveConfigCallExpectations(this);
-
-    // We expect invalidate() to be invoked once to trigger display transaction
-    // processing.
-    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
-
-    EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.onInitializeDisplays();
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The primary display should have a current state
-    ASSERT_TRUE(hasCurrentDisplayState(primaryDisplay.token()));
-    const auto& primaryDisplayState = getCurrentDisplayState(primaryDisplay.token());
-    // The layer stack state should be set to zero
-    EXPECT_EQ(0u, primaryDisplayState.layerStack);
-    // The orientation state should be set to zero
-    EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation);
-
-    // The orientedDisplaySpaceRect state should be set to INVALID
-    EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.orientedDisplaySpaceRect);
-
-    // The layerStackSpaceRect state should be set to INVALID
-    EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.layerStackSpaceRect);
-
-    // The width and height should both be zero
-    EXPECT_EQ(0u, primaryDisplayState.width);
-    EXPECT_EQ(0u, primaryDisplayState.height);
-
-    // The display should be set to PowerMode::ON
-    ASSERT_TRUE(hasDisplayDevice(primaryDisplay.token()));
-    auto displayDevice = primaryDisplay.mutableDisplayDevice();
-    EXPECT_EQ(PowerMode::ON, displayDevice->getPowerMode());
-
-    // The display refresh period should be set in the orientedDisplaySpaceRect tracker.
-    FrameStats stats;
-    mFlinger.getAnimFrameTracker().getStats(&stats);
-    EXPECT_EQ(DEFAULT_REFRESH_RATE, stats.refreshPeriodNano);
-
-    // The display transaction needed flag should be set.
-    EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
-
-    // The compositor timing should be set to default values
-    const auto& compositorTiming = mFlinger.getCompositorTiming();
-    EXPECT_EQ(-DEFAULT_REFRESH_RATE, compositorTiming.deadline);
-    EXPECT_EQ(DEFAULT_REFRESH_RATE, compositorTiming.interval);
-    EXPECT_EQ(DEFAULT_REFRESH_RATE, compositorTiming.presentLatency);
-}
-
-/* ------------------------------------------------------------------------
- * SurfaceFlinger::setPowerModeInternal
- */
-
-// Used when we simulate a display that supports doze.
-template <typename Display>
-struct DozeIsSupportedVariant {
-    static constexpr bool DOZE_SUPPORTED = true;
-    static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE =
-            IComposerClient::PowerMode::DOZE;
-    static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND =
-            IComposerClient::PowerMode::DOZE_SUSPEND;
-
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getDisplayCapabilities(Display::HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(
-                                        std::vector<DisplayCapability>({DisplayCapability::DOZE})),
-                                Return(Error::NONE)));
-    }
-};
-
-template <typename Display>
-// Used when we simulate a display that does not support doze.
-struct DozeNotSupportedVariant {
-    static constexpr bool DOZE_SUPPORTED = false;
-    static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE =
-            IComposerClient::PowerMode::ON;
-    static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND =
-            IComposerClient::PowerMode::ON;
-
-    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getDisplayCapabilities(Display::HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<DisplayCapability>({})),
-                                Return(Error::NONE)));
-    }
-};
-
-struct EventThreadBaseSupportedVariant {
-    static void setupVsyncAndEventThreadNoCallExpectations(DisplayTransactionTest* test) {
-        // The callback should not be notified to toggle VSYNC.
-        EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(_)).Times(0);
-
-        // The event thread should not be notified.
-        EXPECT_CALL(*test->mEventThread, onScreenReleased()).Times(0);
-        EXPECT_CALL(*test->mEventThread, onScreenAcquired()).Times(0);
-    }
-};
-
-struct EventThreadNotSupportedVariant : public EventThreadBaseSupportedVariant {
-    static void setupAcquireAndEnableVsyncCallExpectations(DisplayTransactionTest* test) {
-        // These calls are only expected for the primary display.
-
-        // Instead expect no calls.
-        setupVsyncAndEventThreadNoCallExpectations(test);
-    }
-
-    static void setupReleaseAndDisableVsyncCallExpectations(DisplayTransactionTest* test) {
-        // These calls are only expected for the primary display.
-
-        // Instead expect no calls.
-        setupVsyncAndEventThreadNoCallExpectations(test);
-    }
-};
-
-struct EventThreadIsSupportedVariant : public EventThreadBaseSupportedVariant {
-    static void setupAcquireAndEnableVsyncCallExpectations(DisplayTransactionTest* test) {
-        // The callback should be notified to enable VSYNC.
-        EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(true)).Times(1);
-
-        // The event thread should be notified that the screen was acquired.
-        EXPECT_CALL(*test->mEventThread, onScreenAcquired()).Times(1);
-    }
-
-    static void setupReleaseAndDisableVsyncCallExpectations(DisplayTransactionTest* test) {
-        // The callback should be notified to disable VSYNC.
-        EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(false)).Times(1);
-
-        // The event thread should not be notified that the screen was released.
-        EXPECT_CALL(*test->mEventThread, onScreenReleased()).Times(1);
-    }
-};
-
-struct DispSyncIsSupportedVariant {
-    static void setupResetModelCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mVsyncController, startPeriodTransition(DEFAULT_REFRESH_RATE)).Times(1);
-        EXPECT_CALL(*test->mVSyncTracker, resetModel()).Times(1);
-    }
-};
-
-struct DispSyncNotSupportedVariant {
-    static void setupResetModelCallExpectations(DisplayTransactionTest* /* test */) {}
-};
-
-// --------------------------------------------------------------------
-// Note:
-//
-// There are a large number of transitions we could test, however we only test a
-// selected subset which provides complete test coverage of the implementation.
-// --------------------------------------------------------------------
-
-template <PowerMode initialPowerMode, PowerMode targetPowerMode>
-struct TransitionVariantCommon {
-    static constexpr auto INITIAL_POWER_MODE = initialPowerMode;
-    static constexpr auto TARGET_POWER_MODE = targetPowerMode;
-
-    static void verifyPostconditions(DisplayTransactionTest*) {}
-};
-
-struct TransitionOffToOnVariant : public TransitionVariantCommon<PowerMode::OFF, PowerMode::ON> {
-    template <typename Case>
-    static void setupCallExpectations(DisplayTransactionTest* test) {
-        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
-        Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
-        Case::DispSync::setupResetModelCallExpectations(test);
-        Case::setupRepaintEverythingCallExpectations(test);
-    }
-
-    static void verifyPostconditions(DisplayTransactionTest* test) {
-        EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
-        EXPECT_TRUE(test->mFlinger.getHasPoweredOff());
-    }
-};
-
-struct TransitionOffToDozeSuspendVariant
-      : 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);
-        Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
-        Case::setupRepaintEverythingCallExpectations(test);
-    }
-
-    static void verifyPostconditions(DisplayTransactionTest* test) {
-        EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
-        EXPECT_TRUE(test->mFlinger.getHasPoweredOff());
-    }
-};
-
-struct TransitionOnToOffVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::OFF> {
-    template <typename Case>
-    static void setupCallExpectations(DisplayTransactionTest* test) {
-        Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
-        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
-    }
-
-    static void verifyPostconditions(DisplayTransactionTest* test) {
-        EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
-    }
-};
-
-struct TransitionDozeSuspendToOffVariant
-      : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::OFF> {
-    template <typename Case>
-    static void setupCallExpectations(DisplayTransactionTest* test) {
-        Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
-        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
-    }
-
-    static void verifyPostconditions(DisplayTransactionTest* test) {
-        EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
-    }
-};
-
-struct TransitionOnToDozeVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE> {
-    template <typename Case>
-    static void setupCallExpectations(DisplayTransactionTest* test) {
-        Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
-        Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
-    }
-};
-
-struct TransitionDozeSuspendToDozeVariant
-      : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::DOZE> {
-    template <typename Case>
-    static void setupCallExpectations(DisplayTransactionTest* test) {
-        Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
-        Case::DispSync::setupResetModelCallExpectations(test);
-        Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
-    }
-};
-
-struct TransitionDozeToOnVariant : public TransitionVariantCommon<PowerMode::DOZE, PowerMode::ON> {
-    template <typename Case>
-    static void setupCallExpectations(DisplayTransactionTest* test) {
-        Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
-        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
-    }
-};
-
-struct TransitionDozeSuspendToOnVariant
-      : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::ON> {
-    template <typename Case>
-    static void setupCallExpectations(DisplayTransactionTest* test) {
-        Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
-        Case::DispSync::setupResetModelCallExpectations(test);
-        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
-    }
-};
-
-struct TransitionOnToDozeSuspendVariant
-      : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE_SUSPEND> {
-    template <typename Case>
-    static void setupCallExpectations(DisplayTransactionTest* test) {
-        Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
-        Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
-    }
-};
-
-struct TransitionOnToUnknownVariant
-      : public TransitionVariantCommon<PowerMode::ON, static_cast<PowerMode>(POWER_MODE_LEET)> {
-    template <typename Case>
-    static void setupCallExpectations(DisplayTransactionTest* test) {
-        Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
-        Case::setupNoComposerPowerModeCallExpectations(test);
-    }
-};
-
-// --------------------------------------------------------------------
-// Note:
-//
-// Rather than testing the cartesian product of of
-// DozeIsSupported/DozeNotSupported with all other options, we use one for one
-// display type, and the other for another display type.
-// --------------------------------------------------------------------
-
-template <typename DisplayVariant, typename DozeVariant, typename EventThreadVariant,
-          typename DispSyncVariant, typename TransitionVariant>
-struct DisplayPowerCase {
-    using Display = DisplayVariant;
-    using Doze = DozeVariant;
-    using EventThread = EventThreadVariant;
-    using DispSync = DispSyncVariant;
-    using Transition = TransitionVariant;
-
-    static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, PowerMode mode) {
-        Display::injectHwcDisplayWithNoDefaultCapabilities(test);
-        auto display = Display::makeFakeExistingDisplayInjector(test);
-        display.inject();
-        display.mutableDisplayDevice()->setPowerMode(mode);
-        return display;
-    }
-
-    static void setInitialPrimaryHWVsyncEnabled(DisplayTransactionTest* test, bool enabled) {
-        test->mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = enabled;
-    }
-
-    static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
-    }
-
-    static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test,
-                                                        PowerMode mode) {
-        EXPECT_CALL(*test->mSurfaceInterceptor, isEnabled()).WillOnce(Return(true));
-        EXPECT_CALL(*test->mSurfaceInterceptor, savePowerModeUpdate(_, static_cast<int32_t>(mode)))
-                .Times(1);
-    }
-
-    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),
-                                      Return(Error::NONE)));
-
-        // Any calls to get whether the display supports dozing will return the value set by the
-        // policy variant.
-        EXPECT_CALL(*test->mComposer, getDozeSupport(Display::HWC_DISPLAY_ID, _))
-                .WillRepeatedly(DoAll(SetArgPointee<1>(Doze::DOZE_SUPPORTED), Return(Error::NONE)));
-
-        EXPECT_CALL(*test->mComposer, setPowerMode(Display::HWC_DISPLAY_ID, mode)).Times(1);
-    }
-
-    static void setupNoComposerPowerModeCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, setPowerMode(Display::HWC_DISPLAY_ID, _)).Times(0);
-    }
-};
-
-// A sample configuration for the primary display.
-// In addition to having event thread support, we emulate doze support.
-template <typename TransitionVariant>
-using PrimaryDisplayPowerCase =
-        DisplayPowerCase<PrimaryDisplayVariant, DozeIsSupportedVariant<PrimaryDisplayVariant>,
-                         EventThreadIsSupportedVariant, DispSyncIsSupportedVariant,
-                         TransitionVariant>;
-
-// A sample configuration for the external display.
-// In addition to not having event thread support, we emulate not having doze
-// support.
-template <typename TransitionVariant>
-using ExternalDisplayPowerCase =
-        DisplayPowerCase<ExternalDisplayVariant, DozeNotSupportedVariant<ExternalDisplayVariant>,
-                         EventThreadNotSupportedVariant, DispSyncNotSupportedVariant,
-                         TransitionVariant>;
-
-class SetPowerModeInternalTest : public DisplayTransactionTest {
-public:
-    template <typename Case>
-    void transitionDisplayCommon();
-};
-
-template <PowerMode PowerMode>
-struct PowerModeInitialVSyncEnabled : public std::false_type {};
-
-template <>
-struct PowerModeInitialVSyncEnabled<PowerMode::ON> : public std::true_type {};
-
-template <>
-struct PowerModeInitialVSyncEnabled<PowerMode::DOZE> : public std::true_type {};
-
-template <typename Case>
-void SetPowerModeInternalTest::transitionDisplayCommon() {
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    Case::Doze::setupComposerCallExpectations(this);
-    auto display =
-            Case::injectDisplayWithInitialPowerMode(this, Case::Transition::INITIAL_POWER_MODE);
-    Case::setInitialPrimaryHWVsyncEnabled(this,
-                                          PowerModeInitialVSyncEnabled<
-                                                  Case::Transition::INITIAL_POWER_MODE>::value);
-
-    // --------------------------------------------------------------------
-    // Call Expectations
-
-    Case::setupSurfaceInterceptorCallExpectations(this, Case::Transition::TARGET_POWER_MODE);
-    Case::Transition::template setupCallExpectations<Case>(this);
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(),
-                                  Case::Transition::TARGET_POWER_MODE);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    Case::Transition::verifyPostconditions(this);
-}
-
-TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfNoChange) {
-    using Case = SimplePrimaryDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // A primary display device is set up
-    Case::Display::injectHwcDisplay(this);
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // The display is already set to PowerMode::ON
-    display.mutableDisplayDevice()->setPowerMode(PowerMode::ON);
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::ON);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
-}
-
-TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay) {
-    using Case = HwcVirtualDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // Insert display data so that the HWC thinks it created the virtual display.
-    const auto displayId = Case::Display::DISPLAY_ID::get();
-    ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId));
-    mFlinger.mutableHwcDisplayData().try_emplace(displayId);
-
-    // A virtual display device is set up
-    Case::Display::injectHwcDisplay(this);
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // The display is set to PowerMode::ON
-    getDisplayDevice(display.token())->setPowerMode(PowerMode::ON);
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::OFF);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnPrimaryDisplay) {
-    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToOnVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendPrimaryDisplay) {
-    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToDozeSuspendVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffPrimaryDisplay) {
-    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToOffVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffPrimaryDisplay) {
-    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOffVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozePrimaryDisplay) {
-    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozePrimaryDisplay) {
-    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnPrimaryDisplay) {
-    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeToOnVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnPrimaryDisplay) {
-    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendPrimaryDisplay) {
-    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownPrimaryDisplay) {
-    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToUnknownVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnExternalDisplay) {
-    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToOnVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendExternalDisplay) {
-    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToDozeSuspendVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffExternalDisplay) {
-    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToOffVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffExternalDisplay) {
-    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOffVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeExternalDisplay) {
-    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozeExternalDisplay) {
-    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnExternalDisplay) {
-    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeToOnVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnExternalDisplay) {
-    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendExternalDisplay) {
-    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
-}
-
-TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownExternalDisplay) {
-    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToUnknownVariant>>();
-}
-
-} // 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/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
new file mode 100644
index 0000000..01cdb28
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -0,0 +1,756 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+#include <type_traits>
+#include "DisplayIdentificationTest.h"
+
+#include <binder/IPCThreadState.h>
+#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 <private/android_filesystem_config.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <ui/DebugUtils.h>
+
+#include "TestableScheduler.h"
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockPowerAdvisor.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockMessageQueue.h"
+#include "mock/MockNativeWindowSurface.h"
+#include "mock/MockSchedulerCallback.h"
+#include "mock/MockSurfaceInterceptor.h"
+#include "mock/MockVsyncController.h"
+#include "mock/system/window/MockNativeWindow.h"
+
+namespace android {
+
+// TODO: Do not polute the 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::SetArgPointee;
+
+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;
+
+class DisplayTransactionTest : public testing::Test {
+public:
+    ~DisplayTransactionTest() override;
+
+    // --------------------------------------------------------------------
+    // Mock/Fake injection
+
+    void injectMockScheduler();
+    void injectMockComposer(int virtualDisplayCount);
+    void injectFakeBufferQueueFactory();
+    void injectFakeNativeWindowSurfaceFactory();
+    sp<DisplayDevice> injectDefaultInternalDisplay(
+            std::function<void(TestableSurfaceFlinger::FakeDisplayDeviceInjector&)>);
+
+    // --------------------------------------------------------------------
+    // Postcondition helpers
+
+    bool hasPhysicalHwcDisplay(hal::HWDisplayId hwcDisplayId);
+    bool hasTransactionFlagSet(int flag);
+    bool hasDisplayDevice(sp<IBinder> displayToken);
+    sp<DisplayDevice> getDisplayDevice(sp<IBinder> displayToken);
+    bool hasCurrentDisplayState(sp<IBinder> displayToken);
+    const DisplayDeviceState& getCurrentDisplayState(sp<IBinder> displayToken);
+    bool hasDrawingDisplayState(sp<IBinder> displayToken);
+    const DisplayDeviceState& getDrawingDisplayState(sp<IBinder> displayToken);
+
+    // --------------------------------------------------------------------
+    // Test instances
+
+    TestableSurfaceFlinger mFlinger;
+    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
+    // to keep a reference to them for use in setting up call expectations.
+    renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
+    Hwc2::mock::Composer* mComposer = nullptr;
+    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+    sp<mock::SurfaceInterceptor> mSurfaceInterceptor = new mock::SurfaceInterceptor;
+
+    mock::VsyncController* mVsyncController = new mock::VsyncController;
+    mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker;
+    mock::SchedulerCallback mSchedulerCallback;
+    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;
+    sp<mock::GraphicBufferProducer> mProducer;
+    surfaceflinger::mock::NativeWindowSurface* mNativeWindowSurface = nullptr;
+
+protected:
+    DisplayTransactionTest();
+};
+
+constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'667;
+constexpr int32_t DEFAULT_DPI = 320;
+constexpr int DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT = HAL_PIXEL_FORMAT_RGB_565;
+
+constexpr int POWER_MODE_LEET = 1337; // An out of range power mode value
+
+/* ------------------------------------------------------------------------
+ * Boolean avoidance
+ *
+ * To make calls and template instantiations more readable, we define some
+ * local enums along with an implicit bool conversion.
+ */
+
+#define BOOL_SUBSTITUTE(TYPENAME) enum class TYPENAME : bool { FALSE = false, TRUE = true };
+
+BOOL_SUBSTITUTE(Async);
+BOOL_SUBSTITUTE(Critical);
+BOOL_SUBSTITUTE(Primary);
+BOOL_SUBSTITUTE(Secure);
+BOOL_SUBSTITUTE(Virtual);
+
+template <typename PhysicalDisplay>
+struct PhysicalDisplayIdType {};
+
+template <uint64_t displayId>
+using HalVirtualDisplayIdType = std::integral_constant<uint64_t, displayId>;
+
+struct GpuVirtualDisplayIdType {};
+
+template <typename>
+struct IsPhysicalDisplayId : std::bool_constant<false> {};
+
+template <typename PhysicalDisplay>
+struct IsPhysicalDisplayId<PhysicalDisplayIdType<PhysicalDisplay>> : std::bool_constant<true> {};
+
+template <typename>
+struct DisplayIdGetter;
+
+template <typename PhysicalDisplay>
+struct DisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
+    static PhysicalDisplayId get() {
+        if (!PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
+            return PhysicalDisplayId::fromPort(static_cast<bool>(PhysicalDisplay::PRIMARY)
+                                                       ? LEGACY_DISPLAY_TYPE_PRIMARY
+                                                       : LEGACY_DISPLAY_TYPE_EXTERNAL);
+        }
+
+        const auto info =
+                parseDisplayIdentificationData(PhysicalDisplay::PORT,
+                                               PhysicalDisplay::GET_IDENTIFICATION_DATA());
+        return info ? info->id : PhysicalDisplayId::fromPort(PhysicalDisplay::PORT);
+    }
+};
+
+template <uint64_t displayId>
+struct DisplayIdGetter<HalVirtualDisplayIdType<displayId>> {
+    static HalVirtualDisplayId get() { return HalVirtualDisplayId(displayId); }
+};
+
+template <>
+struct DisplayIdGetter<GpuVirtualDisplayIdType> {
+    static GpuVirtualDisplayId get() { return GpuVirtualDisplayId(0); }
+};
+
+template <typename>
+struct DisplayConnectionTypeGetter {
+    static constexpr std::optional<DisplayConnectionType> value;
+};
+
+template <typename PhysicalDisplay>
+struct DisplayConnectionTypeGetter<PhysicalDisplayIdType<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 <uint64_t displayId>
+struct HwcDisplayIdGetter<HalVirtualDisplayIdType<displayId>> {
+    static constexpr std::optional<HWDisplayId> value = HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID;
+};
+
+template <typename PhysicalDisplay>
+struct HwcDisplayIdGetter<PhysicalDisplayIdType<PhysicalDisplay>> {
+    static constexpr std::optional<HWDisplayId> value = PhysicalDisplay::HWC_DISPLAY_ID;
+};
+
+// DisplayIdType can be:
+//     1) PhysicalDisplayIdType<...> for generated ID of physical display backed by HWC.
+//     2) HalVirtualDisplayIdType<...> for hard-coded ID of virtual display backed by HWC.
+//     3) GpuVirtualDisplayIdType for virtual display without HWC backing.
+template <typename DisplayIdType, int width, int height, Critical critical, Async async,
+          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;
+    static constexpr int HEIGHT = height;
+
+    static constexpr int GRALLOC_USAGE = grallocUsage;
+
+    // Whether the display is virtual or physical
+    static constexpr Virtual VIRTUAL =
+            IsPhysicalDisplayId<DisplayIdType>{} ? Virtual::FALSE : Virtual::TRUE;
+
+    // When creating native window surfaces for the framebuffer, whether those should be critical
+    static constexpr Critical CRITICAL = critical;
+
+    // When creating native window surfaces for the framebuffer, whether those should be async
+    static constexpr Async ASYNC = async;
+
+    // Whether the display should be treated as secure
+    static constexpr Secure SECURE = secure;
+
+    // Whether the display is primary
+    static constexpr Primary PRIMARY = primary;
+
+    static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
+        auto ceDisplayArgs = compositionengine::DisplayCreationArgsBuilder();
+        if (auto displayId = PhysicalDisplayId::tryCast(DISPLAY_ID::get())) {
+            ceDisplayArgs.setPhysical({*displayId, DisplayConnectionType::Internal});
+        } else {
+            // We turn off the use of HwcVirtualDisplays, to prevent Composition Engine
+            // from calling into HWComposer. This way all virtual displays will get
+            // a GpuVirtualDisplayId, even if we are in the HwcVirtualDisplayVariant.
+            // In this case we later override it by calling display.setDisplayIdForTesting().
+            ceDisplayArgs.setUseHwcVirtualDisplays(false);
+
+            GpuVirtualDisplayId desiredDisplayId = GpuVirtualDisplayId::tryCast(DISPLAY_ID::get())
+                                                           .value_or(GpuVirtualDisplayId(0));
+
+            ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
+                    .WillByDefault(Return(desiredDisplayId));
+
+            auto& generator = test->mFlinger.gpuVirtualDisplayIdGenerator();
+            ceDisplayArgs.setGpuVirtualDisplayIdGenerator(generator);
+        }
+        ceDisplayArgs.setPixels({WIDTH, HEIGHT}).setPowerAdvisor(&test->mPowerAdvisor);
+
+        auto compositionDisplay =
+                compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+                                                       ceDisplayArgs.build());
+
+        if (HalVirtualDisplayId::tryCast(DISPLAY_ID::get())) {
+            // CompositionEngine has assigned a placeholder GpuVirtualDisplayId and we need to
+            // override it with the correct HalVirtualDisplayId.
+            compositionDisplay->setDisplayIdForTesting(DISPLAY_ID::get());
+        }
+
+        auto injector =
+                TestableSurfaceFlinger::FakeDisplayDeviceInjector(test->mFlinger,
+                                                                  compositionDisplay,
+                                                                  CONNECTION_TYPE::value,
+                                                                  HWC_DISPLAY_ID_OPT::value,
+                                                                  static_cast<bool>(PRIMARY));
+
+        injector.setSecure(static_cast<bool>(SECURE));
+        injector.setNativeWindow(test->mNativeWindow);
+
+        // Creating a DisplayDevice requires getting default dimensions from the
+        // native window along with some other initial setup.
+        EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
+        EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
+        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT))
+                .WillRepeatedly(Return(0));
+        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT))
+                .WillRepeatedly(Return(0));
+        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64))
+                .WillRepeatedly(Return(0));
+        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT))
+                .WillRepeatedly(Return(0));
+
+        return injector;
+    }
+
+    // Called by tests to set up any native window creation call expectations.
+    static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mNativeWindowSurface, getNativeWindow())
+                .WillOnce(Return(test->mNativeWindow));
+
+        EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(WIDTH), Return(0)));
+        EXPECT_CALL(*test->mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(HEIGHT), Return(0)));
+        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT))
+                .WillRepeatedly(Return(0));
+        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_CONNECT))
+                .WillRepeatedly(Return(0));
+        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_USAGE64))
+                .WillRepeatedly(Return(0));
+        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT))
+                .WillRepeatedly(Return(0));
+    }
+
+    static void setupFramebufferConsumerBufferQueueCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mConsumer, consumerConnect(_, false)).WillOnce(Return(NO_ERROR));
+        EXPECT_CALL(*test->mConsumer, setConsumerName(_)).WillRepeatedly(Return(NO_ERROR));
+        EXPECT_CALL(*test->mConsumer, setConsumerUsageBits(GRALLOC_USAGE))
+                .WillRepeatedly(Return(NO_ERROR));
+        EXPECT_CALL(*test->mConsumer, setDefaultBufferSize(WIDTH, HEIGHT))
+                .WillRepeatedly(Return(NO_ERROR));
+        EXPECT_CALL(*test->mConsumer, setMaxAcquiredBufferCount(_))
+                .WillRepeatedly(Return(NO_ERROR));
+    }
+
+    static void setupFramebufferProducerBufferQueueCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mProducer, allocateBuffers(0, 0, 0, 0)).WillRepeatedly(Return());
+    }
+};
+
+template <HWDisplayId hwcDisplayId, DisplayType hwcDisplayType, typename DisplayVariant,
+          typename PhysicalDisplay = void>
+struct HwcDisplayVariant {
+    // The display id supplied by the HWC
+    static constexpr HWDisplayId HWC_DISPLAY_ID = hwcDisplayId;
+
+    // The HWC display type
+    static constexpr DisplayType HWC_DISPLAY_TYPE = hwcDisplayType;
+
+    // The HWC active configuration id
+    static constexpr int HWC_ACTIVE_CONFIG_ID = 2001;
+    static constexpr PowerMode INIT_POWER_MODE = hal::PowerMode::ON;
+
+    static void injectPendingHotplugEvent(DisplayTransactionTest* test, Connection connection) {
+        test->mFlinger.mutablePendingHotplugEvents().emplace_back(
+                TestableSurfaceFlinger::HotplugEvent{HWC_DISPLAY_ID, connection});
+    }
+
+    // Called by tests to inject a HWC display setup
+    static void injectHwcDisplayWithNoDefaultCapabilities(DisplayTransactionTest* test) {
+        const auto displayId = DisplayVariant::DISPLAY_ID::get();
+        ASSERT_FALSE(GpuVirtualDisplayId::tryCast(displayId));
+        TestableSurfaceFlinger::FakeHwcDisplayInjector(displayId, HWC_DISPLAY_TYPE,
+                                                       static_cast<bool>(DisplayVariant::PRIMARY))
+                .setHwcDisplayId(HWC_DISPLAY_ID)
+                .setWidth(DisplayVariant::WIDTH)
+                .setHeight(DisplayVariant::HEIGHT)
+                .setActiveConfig(HWC_ACTIVE_CONFIG_ID)
+                .setPowerMode(INIT_POWER_MODE)
+                .inject(&test->mFlinger, test->mComposer);
+    }
+
+    // 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<DisplayCapability>({})),
+                                Return(Error::NONE)));
+        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) {
+        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)));
+        EXPECT_CALL(*test->mComposer,
+                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                        IComposerClient::Attribute::WIDTH, _))
+                .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::WIDTH), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                        IComposerClient::Attribute::HEIGHT, _))
+                .WillOnce(DoAll(SetArgPointee<3>(DisplayVariant::HEIGHT), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                        IComposerClient::Attribute::VSYNC_PERIOD, _))
+                .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_REFRESH_RATE), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                        IComposerClient::Attribute::DPI_X, _))
+                .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                        IComposerClient::Attribute::DPI_Y, _))
+                .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
+                                        IComposerClient::Attribute::CONFIG_GROUP, _))
+                .WillOnce(DoAll(SetArgPointee<3>(-1), Return(Error::NONE)));
+
+        if (PhysicalDisplay::HAS_IDENTIFICATION_DATA) {
+            EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
+                    .WillOnce(DoAll(SetArgPointee<1>(PhysicalDisplay::PORT),
+                                    SetArgPointee<2>(PhysicalDisplay::GET_IDENTIFICATION_DATA()),
+                                    Return(Error::NONE)));
+        } else {
+            EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
+                    .WillOnce(Return(Error::UNSUPPORTED));
+        }
+    }
+
+    // Called by tests to set up HWC call expectations
+    static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY_ID, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(HWC_ACTIVE_CONFIG_ID), Return(Error::NONE)));
+    }
+};
+
+// Physical displays are expected to be synchronous, secure, and have a HWC display for output.
+constexpr uint32_t GRALLOC_USAGE_PHYSICAL_DISPLAY =
+        GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER | GRALLOC_USAGE_HW_FB;
+
+template <typename PhysicalDisplay, int width, int height, Critical critical>
+struct PhysicalDisplayVariant
+      : DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height, critical,
+                       Async::FALSE, Secure::TRUE, PhysicalDisplay::PRIMARY,
+                       GRALLOC_USAGE_PHYSICAL_DISPLAY>,
+        HwcDisplayVariant<PhysicalDisplay::HWC_DISPLAY_ID, DisplayType::PHYSICAL,
+                          DisplayVariant<PhysicalDisplayIdType<PhysicalDisplay>, width, height,
+                                         critical, Async::FALSE, Secure::TRUE,
+                                         PhysicalDisplay::PRIMARY, GRALLOC_USAGE_PHYSICAL_DISPLAY>,
+                          PhysicalDisplay> {};
+
+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;
+};
+
+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<PrimaryDisplay<false>, 3840, 2160, Critical::TRUE>;
+
+// An external display is physical display that is not critical.
+using ExternalDisplayVariant =
+        PhysicalDisplayVariant<ExternalDisplay<false>, 1920, 1280, 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;
+
+template <int width, int height, Secure secure>
+struct NonHwcVirtualDisplayVariant
+      : DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE, Async::TRUE, secure,
+                       Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY> {
+    using Base =
+            DisplayVariant<GpuVirtualDisplayIdType, width, height, Critical::FALSE, Async::TRUE,
+                           secure, Primary::FALSE, GRALLOC_USAGE_NONHWC_VIRTUAL_DISPLAY>;
+
+    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();
+
+        ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
+                .WillByDefault(Return(Base::DISPLAY_ID::get()));
+
+        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())
+                                     .setGpuVirtualDisplayIdGenerator(
+                                             test->mFlinger.gpuVirtualDisplayIdGenerator())
+                                     .build();
+
+        return compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+                                                      ceDisplayArgs);
+    }
+
+    static void setupHwcGetActiveConfigCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getActiveConfig(_, _)).Times(0);
+    }
+
+    static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
+        Base::setupNativeWindowSurfaceCreationCallExpectations(test);
+        EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1);
+    }
+};
+
+// A virtual display supported by the HWC.
+constexpr uint32_t GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY = GRALLOC_USAGE_HW_COMPOSER;
+
+template <int width, int height, Secure secure>
+struct HwcVirtualDisplayVariant
+      : DisplayVariant<HalVirtualDisplayIdType<42>, width, height, Critical::FALSE, Async::TRUE,
+                       secure, Primary::FALSE, GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>,
+        HwcDisplayVariant<HWC_VIRTUAL_DISPLAY_HWC_DISPLAY_ID, DisplayType::VIRTUAL,
+                          DisplayVariant<HalVirtualDisplayIdType<42>, width, height,
+                                         Critical::FALSE, Async::TRUE, secure, Primary::FALSE,
+                                         GRALLOC_USAGE_HWC_VIRTUAL_DISPLAY>> {
+    using Base = DisplayVariant<HalVirtualDisplayIdType<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();
+
+        // In order to prevent compostition engine calling into HWComposer, we
+        // 1. turn off the use of HWC virtual displays,
+        // 2. provide a GpuVirtualDisplayIdGenerator which always returns some fake ID
+        // 3. override the ID by calling setDisplayIdForTesting()
+
+        ON_CALL(test->mFlinger.gpuVirtualDisplayIdGenerator(), nextId())
+                .WillByDefault(Return(GpuVirtualDisplayId(0)));
+
+        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())
+                                     .setGpuVirtualDisplayIdGenerator(
+                                             test->mFlinger.gpuVirtualDisplayIdGenerator())
+                                     .build();
+
+        auto compositionDisplay =
+                compositionengine::impl::createDisplay(test->mFlinger.getCompositionEngine(),
+                                                       ceDisplayArgs);
+        compositionDisplay->setDisplayIdForTesting(Base::DISPLAY_ID::get());
+
+        // Insert display data so that the HWC thinks it created the virtual display.
+        if (const auto displayId = Base::DISPLAY_ID::get();
+            HalVirtualDisplayId::tryCast(displayId)) {
+            test->mFlinger.mutableHwcDisplayData().try_emplace(displayId);
+        }
+
+        return compositionDisplay;
+    }
+
+    static void setupNativeWindowSurfaceCreationCallExpectations(DisplayTransactionTest* test) {
+        Base::setupNativeWindowSurfaceCreationCallExpectations(test);
+        EXPECT_CALL(*test->mNativeWindow, setSwapInterval(0)).Times(1);
+    }
+
+    static void setupHwcVirtualDisplayCreationCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, createVirtualDisplay(Base::WIDTH, Base::HEIGHT, _, _))
+                .WillOnce(DoAll(SetArgPointee<3>(Self::HWC_DISPLAY_ID), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer, setClientTargetSlotCount(_)).WillOnce(Return(Error::NONE));
+    }
+};
+
+// For this variant, the display is not a HWC display, so no HDR support should
+// be configured.
+struct NonHwcDisplayHdrSupportVariant {
+    static constexpr bool HDR10_PLUS_SUPPORTED = false;
+    static constexpr bool HDR10_SUPPORTED = false;
+    static constexpr bool HDR_HLG_SUPPORTED = false;
+    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getHdrCapabilities(_, _, _, _, _)).Times(0);
+    }
+};
+
+// For this variant, the composer should respond with am empty list of HDR
+// modes, so no HDR support should be configured.
+template <typename Display>
+struct HdrNotSupportedVariant {
+    static constexpr bool HDR10_PLUS_SUPPORTED = false;
+    static constexpr bool HDR10_SUPPORTED = false;
+    static constexpr bool HDR_HLG_SUPPORTED = false;
+    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>()), Return(Error::NONE)));
+    }
+};
+
+struct NonHwcPerFrameMetadataSupportVariant {
+    static constexpr int PER_FRAME_METADATA_KEYS = 0;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(_)).Times(0);
+    }
+};
+
+template <typename Display>
+struct NoPerFrameMetadataSupportVariant {
+    static constexpr int PER_FRAME_METADATA_KEYS = 0;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
+                .WillOnce(Return(std::vector<PerFrameMetadataKey>()));
+    }
+};
+
+// For this variant, SurfaceFlinger should configure itself with wide display
+// support, but the display should respond with an empty list of supported color
+// modes. Wide-color support for the display should not be configured.
+template <typename Display>
+struct WideColorNotSupportedVariant {
+    static constexpr bool WIDE_COLOR_SUPPORTED = false;
+
+    static void injectConfigChange(DisplayTransactionTest* test) {
+        test->mFlinger.mutableUseColorManagement() = true;
+        test->mFlinger.mutableHasWideColorDisplay() = true;
+    }
+
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>()), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0);
+    }
+};
+
+// For this variant, SurfaceFlinger should not configure itself with wide
+// display support, so the display should not be configured for wide-color
+// support.
+struct WideColorSupportNotConfiguredVariant {
+    static constexpr bool WIDE_COLOR_SUPPORTED = false;
+
+    static void injectConfigChange(DisplayTransactionTest* test) {
+        test->mFlinger.mutableHasWideColorDisplay() = false;
+        test->mFlinger.mutableUseColorManagement() = false;
+        test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
+    }
+
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getColorModes(_, _)).Times(0);
+        EXPECT_CALL(*test->mComposer, getRenderIntents(_, _, _)).Times(0);
+        EXPECT_CALL(*test->mComposer, setColorMode(_, _, _)).Times(0);
+    }
+};
+
+/* ------------------------------------------------------------------------
+ * Typical display configurations to test
+ */
+
+template <typename DisplayPolicy, typename WideColorSupportPolicy, typename HdrSupportPolicy,
+          typename PerFrameMetadataSupportPolicy>
+struct Case {
+    using Display = DisplayPolicy;
+    using WideColorSupport = WideColorSupportPolicy;
+    using HdrSupport = HdrSupportPolicy;
+    using PerFrameMetadataSupport = PerFrameMetadataSupportPolicy;
+};
+
+using SimplePrimaryDisplayCase =
+        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+             HdrNotSupportedVariant<PrimaryDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using SimpleExternalDisplayCase =
+        Case<ExternalDisplayVariant, WideColorNotSupportedVariant<ExternalDisplayVariant>,
+             HdrNotSupportedVariant<ExternalDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<ExternalDisplayVariant>>;
+using SimpleTertiaryDisplayCase =
+        Case<TertiaryDisplayVariant, WideColorNotSupportedVariant<TertiaryDisplayVariant>,
+             HdrNotSupportedVariant<TertiaryDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<TertiaryDisplayVariant>>;
+
+using NonHwcVirtualDisplayCase =
+        Case<NonHwcVirtualDisplayVariant<1024, 768, Secure::FALSE>,
+             WideColorSupportNotConfiguredVariant, NonHwcDisplayHdrSupportVariant,
+             NonHwcPerFrameMetadataSupportVariant>;
+using SimpleHwcVirtualDisplayVariant = HwcVirtualDisplayVariant<1024, 768, Secure::TRUE>;
+using HwcVirtualDisplayCase =
+        Case<SimpleHwcVirtualDisplayVariant, WideColorSupportNotConfiguredVariant,
+             HdrNotSupportedVariant<SimpleHwcVirtualDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<SimpleHwcVirtualDisplayVariant>>;
+
+} // 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/SurfaceFlinger_CreateDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
new file mode 100644
index 0000000..2362a31
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_CreateDisplayTest.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 "DisplayTransactionTestHelpers.h"
+
+namespace android {
+namespace {
+
+class CreateDisplayTest : public DisplayTransactionTest {};
+
+TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForNonsecureDisplay) {
+    const String8 name("virtual.test");
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // The call should notify the interceptor that a display was created.
+    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    sp<IBinder> displayToken = mFlinger.createDisplay(name, false);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The display should have been added to the current state
+    ASSERT_TRUE(hasCurrentDisplayState(displayToken));
+    const auto& display = getCurrentDisplayState(displayToken);
+    EXPECT_TRUE(display.isVirtual());
+    EXPECT_FALSE(display.isSecure);
+    EXPECT_EQ(name.string(), display.displayName);
+
+    // --------------------------------------------------------------------
+    // Cleanup conditions
+
+    // Destroying the display invalidates the display state.
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+}
+
+TEST_F(CreateDisplayTest, createDisplaySetsCurrentStateForSecureDisplay) {
+    const String8 name("virtual.test");
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // The call should notify the interceptor that a display was created.
+    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
+
+    // --------------------------------------------------------------------
+    // Invocation
+    int64_t oldId = IPCThreadState::self()->clearCallingIdentity();
+    // Set the calling identity to graphics so captureDisplay with secure is allowed.
+    IPCThreadState::self()->restoreCallingIdentity(static_cast<int64_t>(AID_GRAPHICS) << 32 |
+                                                   AID_GRAPHICS);
+    sp<IBinder> displayToken = mFlinger.createDisplay(name, true);
+    IPCThreadState::self()->restoreCallingIdentity(oldId);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The display should have been added to the current state
+    ASSERT_TRUE(hasCurrentDisplayState(displayToken));
+    const auto& display = getCurrentDisplayState(displayToken);
+    EXPECT_TRUE(display.isVirtual());
+    EXPECT_TRUE(display.isSecure);
+    EXPECT_EQ(name.string(), display.displayName);
+
+    // --------------------------------------------------------------------
+    // Cleanup conditions
+
+    // Destroying the display invalidates the display state.
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+}
+
+} // namespace
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
new file mode 100644
index 0000000..0614434
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_DestroyDisplayTest.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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 "DisplayTransactionTestHelpers.h"
+
+namespace android {
+namespace {
+
+class DestroyDisplayTest : public DisplayTransactionTest {};
+
+TEST_F(DestroyDisplayTest, destroyDisplayClearsCurrentStateForDisplay) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A virtual display exists
+    auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+    existing.inject();
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // The call should notify the interceptor that a display was created.
+    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
+
+    // Destroying the display invalidates the display state.
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.destroyDisplay(existing.token());
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The display should have been removed from the current state
+    EXPECT_FALSE(hasCurrentDisplayState(existing.token()));
+
+    // Ths display should still exist in the drawing state
+    EXPECT_TRUE(hasDrawingDisplayState(existing.token()));
+
+    // The display transaction needed flasg should be set
+    EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+}
+
+TEST_F(DestroyDisplayTest, destroyDisplayHandlesUnknownDisplay) {
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    sp<BBinder> displayToken = new BBinder();
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.destroyDisplay(displayToken);
+}
+
+} // namespace
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp
new file mode 100644
index 0000000..0171f1b
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp
@@ -0,0 +1,110 @@
+/*
+ * 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 "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+class GetDisplayNativePrimaries : public DisplayTransactionTest {
+public:
+    GetDisplayNativePrimaries();
+    void populateDummyDisplayNativePrimaries(ui::DisplayPrimaries& primaries);
+    void checkDummyDisplayNativePrimaries(const ui::DisplayPrimaries& primaries);
+
+private:
+    static constexpr float mStartingTestValue = 1.0f;
+};
+
+GetDisplayNativePrimaries::GetDisplayNativePrimaries() {
+    SimplePrimaryDisplayCase::Display::injectHwcDisplay(this);
+    injectFakeNativeWindowSurfaceFactory();
+}
+
+void GetDisplayNativePrimaries::populateDummyDisplayNativePrimaries(
+        ui::DisplayPrimaries& primaries) {
+    float startingVal = mStartingTestValue;
+    primaries.red.X = startingVal++;
+    primaries.red.Y = startingVal++;
+    primaries.red.Z = startingVal++;
+    primaries.green.X = startingVal++;
+    primaries.green.Y = startingVal++;
+    primaries.green.Z = startingVal++;
+    primaries.blue.X = startingVal++;
+    primaries.blue.Y = startingVal++;
+    primaries.blue.Z = startingVal++;
+    primaries.white.X = startingVal++;
+    primaries.white.Y = startingVal++;
+    primaries.white.Z = startingVal++;
+}
+
+void GetDisplayNativePrimaries::checkDummyDisplayNativePrimaries(
+        const ui::DisplayPrimaries& primaries) {
+    float startingVal = mStartingTestValue;
+    EXPECT_EQ(primaries.red.X, startingVal++);
+    EXPECT_EQ(primaries.red.Y, startingVal++);
+    EXPECT_EQ(primaries.red.Z, startingVal++);
+    EXPECT_EQ(primaries.green.X, startingVal++);
+    EXPECT_EQ(primaries.green.Y, startingVal++);
+    EXPECT_EQ(primaries.green.Z, startingVal++);
+    EXPECT_EQ(primaries.blue.X, startingVal++);
+    EXPECT_EQ(primaries.blue.Y, startingVal++);
+    EXPECT_EQ(primaries.blue.Z, startingVal++);
+    EXPECT_EQ(primaries.white.X, startingVal++);
+    EXPECT_EQ(primaries.white.Y, startingVal++);
+    EXPECT_EQ(primaries.white.Z, startingVal++);
+}
+
+TEST_F(GetDisplayNativePrimaries, nullDisplayToken) {
+    ui::DisplayPrimaries primaries;
+    EXPECT_EQ(BAD_VALUE, mFlinger.getDisplayNativePrimaries(nullptr, primaries));
+}
+
+TEST_F(GetDisplayNativePrimaries, internalDisplayWithPrimariesData) {
+    auto injector = SimplePrimaryDisplayCase::Display::makeFakeExistingDisplayInjector(this);
+    injector.inject();
+    auto internalDisplayToken = injector.token();
+
+    ui::DisplayPrimaries expectedPrimaries;
+    populateDummyDisplayNativePrimaries(expectedPrimaries);
+    mFlinger.setInternalDisplayPrimaries(expectedPrimaries);
+
+    ui::DisplayPrimaries primaries;
+    EXPECT_EQ(NO_ERROR, mFlinger.getDisplayNativePrimaries(internalDisplayToken, primaries));
+
+    checkDummyDisplayNativePrimaries(primaries);
+}
+
+TEST_F(GetDisplayNativePrimaries, notInternalDisplayToken) {
+    sp<BBinder> notInternalDisplayToken = new BBinder();
+
+    ui::DisplayPrimaries primaries;
+    populateDummyDisplayNativePrimaries(primaries);
+    EXPECT_EQ(NAME_NOT_FOUND,
+              mFlinger.getDisplayNativePrimaries(notInternalDisplayToken, primaries));
+
+    // Check primaries argument wasn't modified in case of failure
+    checkDummyDisplayNativePrimaries(primaries);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
new file mode 100644
index 0000000..cd3f6ab
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
@@ -0,0 +1,734 @@
+/*
+ * 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 "DisplayTransactionTestHelpers.h"
+
+namespace android {
+namespace {
+
+class HandleTransactionLockedTest : public DisplayTransactionTest {
+public:
+    template <typename Case>
+    void setupCommonPreconditions();
+
+    template <typename Case, bool connected>
+    static void expectHotplugReceived(mock::EventThread*);
+
+    template <typename Case>
+    void setupCommonCallExpectationsForConnectProcessing();
+
+    template <typename Case>
+    void setupCommonCallExpectationsForDisconnectProcessing();
+
+    template <typename Case>
+    void processesHotplugConnectCommon();
+
+    template <typename Case>
+    void ignoresHotplugConnectCommon();
+
+    template <typename Case>
+    void processesHotplugDisconnectCommon();
+
+    template <typename Case>
+    void verifyDisplayIsConnected(const sp<IBinder>& displayToken);
+
+    template <typename Case>
+    void verifyPhysicalDisplayIsConnected();
+
+    void verifyDisplayIsNotConnected(const sp<IBinder>& displayToken);
+};
+
+template <typename Case>
+void HandleTransactionLockedTest::setupCommonPreconditions() {
+    // Wide color displays support is configured appropriately
+    Case::WideColorSupport::injectConfigChange(this);
+
+    // SurfaceFlinger will use a test-controlled factory for BufferQueues
+    injectFakeBufferQueueFactory();
+
+    // SurfaceFlinger will use a test-controlled factory for native window
+    // surfaces.
+    injectFakeNativeWindowSurfaceFactory();
+}
+
+template <typename Case, bool connected>
+void HandleTransactionLockedTest::expectHotplugReceived(mock::EventThread* eventThread) {
+    const auto convert = [](auto physicalDisplayId) {
+        return std::make_optional(DisplayId{physicalDisplayId});
+    };
+
+    EXPECT_CALL(*eventThread,
+                onHotplugReceived(ResultOf(convert, Case::Display::DISPLAY_ID::get()), connected))
+            .Times(1);
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::setupCommonCallExpectationsForConnectProcessing() {
+    Case::Display::setupHwcHotplugCallExpectations(this);
+
+    Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
+    Case::Display::setupFramebufferProducerBufferQueueCallExpectations(this);
+    Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
+    Case::Display::setupHwcGetActiveConfigCallExpectations(this);
+
+    Case::WideColorSupport::setupComposerCallExpectations(this);
+    Case::HdrSupport::setupComposerCallExpectations(this);
+    Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
+
+    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
+    expectHotplugReceived<Case, true>(mEventThread);
+    expectHotplugReceived<Case, true>(mSFEventThread);
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
+    EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
+
+    expectHotplugReceived<Case, false>(mEventThread);
+    expectHotplugReceived<Case, false>(mSFEventThread);
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::verifyDisplayIsConnected(const sp<IBinder>& displayToken) {
+    // The display device should have been set up in the list of displays.
+    ASSERT_TRUE(hasDisplayDevice(displayToken));
+    const auto& device = getDisplayDevice(displayToken);
+    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 = PhysicalDisplayId::tryCast(Case::Display::DISPLAY_ID::get());
+        ASSERT_TRUE(displayId);
+        const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
+        ASSERT_TRUE(hwcDisplayId);
+        expectedPhysical = {.id = *displayId,
+                            .type = *connectionType,
+                            .hwcDisplayId = *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(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(expectedPhysical, draw.physical);
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::verifyPhysicalDisplayIsConnected() {
+    // HWComposer should have an entry for the display
+    EXPECT_TRUE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+
+    // SF should have a display token.
+    const auto displayId = Case::Display::DISPLAY_ID::get();
+    ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
+    ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
+    auto& displayToken = mFlinger.mutablePhysicalDisplayTokens()[displayId];
+
+    verifyDisplayIsConnected<Case>(displayToken);
+}
+
+void HandleTransactionLockedTest::verifyDisplayIsNotConnected(const sp<IBinder>& displayToken) {
+    EXPECT_FALSE(hasDisplayDevice(displayToken));
+    EXPECT_FALSE(hasCurrentDisplayState(displayToken));
+    EXPECT_FALSE(hasDrawingDisplayState(displayToken));
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::processesHotplugConnectCommon() {
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    setupCommonPreconditions<Case>();
+
+    // A hotplug connect event is enqueued for a display
+    Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    setupCommonCallExpectationsForConnectProcessing<Case>();
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    verifyPhysicalDisplayIsConnected<Case>();
+
+    // --------------------------------------------------------------------
+    // Cleanup conditions
+
+    EXPECT_CALL(*mComposer,
+                setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
+            .WillOnce(Return(Error::NONE));
+    EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::ignoresHotplugConnectCommon() {
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    setupCommonPreconditions<Case>();
+
+    // A hotplug connect event is enqueued for a display
+    Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // HWComposer should not have an entry for the display
+    EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+}
+
+template <typename Case>
+void HandleTransactionLockedTest::processesHotplugDisconnectCommon() {
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    setupCommonPreconditions<Case>();
+
+    // A hotplug disconnect event is enqueued for a display
+    Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
+
+    // The display is already completely set up.
+    Case::Display::injectHwcDisplay(this);
+    auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+    existing.inject();
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    EXPECT_CALL(*mComposer, getDisplayIdentificationData(Case::Display::HWC_DISPLAY_ID, _, _))
+            .Times(0);
+
+    setupCommonCallExpectationsForDisconnectProcessing<Case>();
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // HWComposer should not have an entry for the display
+    EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+
+    // SF should not have a display token.
+    const auto displayId = Case::Display::DISPLAY_ID::get();
+    ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
+    ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
+
+    // The existing token should have been removed
+    verifyDisplayIsNotConnected(existing.token());
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugConnectPrimaryDisplay) {
+    processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest,
+       processesHotplugConnectPrimaryDisplayWithExternalAlreadyConnected) {
+    // Inject an external display.
+    ExternalDisplayVariant::injectHwcDisplay(this);
+
+    processesHotplugConnectCommon<SimplePrimaryDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugConnectExternalDisplay) {
+    // Inject a primary display.
+    PrimaryDisplayVariant::injectHwcDisplay(this);
+
+    processesHotplugConnectCommon<SimpleExternalDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, ignoresHotplugConnectIfPrimaryAndExternalAlreadyConnected) {
+    // Inject both a primary and external display.
+    PrimaryDisplayVariant::injectHwcDisplay(this);
+    ExternalDisplayVariant::injectHwcDisplay(this);
+
+    // TODO: This is an unnecessary call.
+    EXPECT_CALL(*mComposer,
+                getDisplayIdentificationData(TertiaryDisplayVariant::HWC_DISPLAY_ID, _, _))
+            .WillOnce(DoAll(SetArgPointee<1>(TertiaryDisplay::PORT),
+                            SetArgPointee<2>(TertiaryDisplay::GET_IDENTIFICATION_DATA()),
+                            Return(Error::NONE)));
+
+    ignoresHotplugConnectCommon<SimpleTertiaryDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectPrimaryDisplay) {
+    processesHotplugDisconnectCommon<SimplePrimaryDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectExternalDisplay) {
+    processesHotplugDisconnectCommon<SimpleExternalDisplayCase>();
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugConnectThenDisconnectPrimary) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    setupCommonPreconditions<Case>();
+
+    // A hotplug connect event is enqueued for a display
+    Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
+    // A hotplug disconnect event is also enqueued for the same display
+    Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    setupCommonCallExpectationsForConnectProcessing<Case>();
+    setupCommonCallExpectationsForDisconnectProcessing<Case>();
+
+    EXPECT_CALL(*mComposer,
+                setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
+            .WillOnce(Return(Error::NONE));
+    EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // HWComposer should not have an entry for the display
+    EXPECT_FALSE(hasPhysicalHwcDisplay(Case::Display::HWC_DISPLAY_ID));
+
+    // SF should not have a display token.
+    const auto displayId = Case::Display::DISPLAY_ID::get();
+    ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
+    ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 0);
+}
+
+TEST_F(HandleTransactionLockedTest, processesHotplugDisconnectThenConnectPrimary) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    setupCommonPreconditions<Case>();
+
+    // The display is already completely set up.
+    Case::Display::injectHwcDisplay(this);
+    auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+    existing.inject();
+
+    // A hotplug disconnect event is enqueued for a display
+    Case::Display::injectPendingHotplugEvent(this, Connection::DISCONNECTED);
+    // A hotplug connect event is also enqueued for the same display
+    Case::Display::injectPendingHotplugEvent(this, Connection::CONNECTED);
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    setupCommonCallExpectationsForConnectProcessing<Case>();
+    setupCommonCallExpectationsForDisconnectProcessing<Case>();
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The existing token should have been removed
+    verifyDisplayIsNotConnected(existing.token());
+    const auto displayId = Case::Display::DISPLAY_ID::get();
+    ASSERT_TRUE(PhysicalDisplayId::tryCast(displayId));
+    ASSERT_TRUE(mFlinger.mutablePhysicalDisplayTokens().count(displayId) == 1);
+    EXPECT_NE(existing.token(), mFlinger.mutablePhysicalDisplayTokens()[displayId]);
+
+    // A new display should be connected in its place
+
+    verifyPhysicalDisplayIsConnected<Case>();
+
+    // --------------------------------------------------------------------
+    // Cleanup conditions
+
+    EXPECT_CALL(*mComposer,
+                setVsyncEnabled(Case::Display::HWC_DISPLAY_ID, IComposerClient::Vsync::DISABLE))
+            .WillOnce(Return(Error::NONE));
+    EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+}
+
+TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAdded) {
+    using Case = HwcVirtualDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // The HWC supports at least one virtual display
+    injectMockComposer(1);
+
+    setupCommonPreconditions<Case>();
+
+    // A virtual display was added to the current state, and it has a
+    // surface(producer)
+    sp<BBinder> displayToken = new BBinder();
+
+    DisplayDeviceState state;
+    state.isSecure = static_cast<bool>(Case::Display::SECURE);
+
+    sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()};
+    state.surface = surface;
+    mFlinger.mutableCurrentState().displays.add(displayToken, state);
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    Case::Display::setupFramebufferConsumerBufferQueueCallExpectations(this);
+    Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
+
+    EXPECT_CALL(*surface, query(NATIVE_WINDOW_WIDTH, _))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::WIDTH), Return(NO_ERROR)));
+    EXPECT_CALL(*surface, query(NATIVE_WINDOW_HEIGHT, _))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(Case::Display::HEIGHT), Return(NO_ERROR)));
+    EXPECT_CALL(*surface, query(NATIVE_WINDOW_FORMAT, _))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_VIRTUAL_DISPLAY_SURFACE_FORMAT),
+                                  Return(NO_ERROR)));
+    EXPECT_CALL(*surface, query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, _))
+            .WillRepeatedly(DoAll(SetArgPointee<1>(0), Return(NO_ERROR)));
+
+    EXPECT_CALL(*surface, setAsyncMode(true)).Times(1);
+
+    EXPECT_CALL(*mProducer, connect(_, NATIVE_WINDOW_API_EGL, false, _)).Times(1);
+    EXPECT_CALL(*mProducer, disconnect(_, _)).Times(1);
+
+    Case::Display::setupHwcVirtualDisplayCreationCallExpectations(this);
+    Case::WideColorSupport::setupComposerCallExpectations(this);
+    Case::HdrSupport::setupComposerCallExpectations(this);
+    Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The display device should have been set up in the list of displays.
+    verifyDisplayIsConnected<Case>(displayToken);
+
+    // --------------------------------------------------------------------
+    // Cleanup conditions
+
+    EXPECT_CALL(*mComposer, destroyVirtualDisplay(Case::Display::HWC_DISPLAY_ID))
+            .WillOnce(Return(Error::NONE));
+    EXPECT_CALL(*mConsumer, consumerDisconnect()).WillOnce(Return(NO_ERROR));
+
+    // Cleanup
+    mFlinger.mutableCurrentState().displays.removeItem(displayToken);
+    mFlinger.mutableDrawingState().displays.removeItem(displayToken);
+}
+
+TEST_F(HandleTransactionLockedTest, processesVirtualDisplayAddedWithNoSurface) {
+    using Case = HwcVirtualDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // The HWC supports at least one virtual display
+    injectMockComposer(1);
+
+    setupCommonPreconditions<Case>();
+
+    // A virtual display was added to the current state, but it does not have a
+    // surface.
+    sp<BBinder> displayToken = new BBinder();
+
+    DisplayDeviceState state;
+    state.isSecure = static_cast<bool>(Case::Display::SECURE);
+
+    mFlinger.mutableCurrentState().displays.add(displayToken, state);
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // There will not be a display device set up.
+    EXPECT_FALSE(hasDisplayDevice(displayToken));
+
+    // The drawing display state will be set from the current display state.
+    ASSERT_TRUE(hasDrawingDisplayState(displayToken));
+    const auto& draw = getDrawingDisplayState(displayToken);
+    EXPECT_EQ(static_cast<bool>(Case::Display::VIRTUAL), draw.isVirtual());
+}
+
+TEST_F(HandleTransactionLockedTest, processesVirtualDisplayRemoval) {
+    using Case = HwcVirtualDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A virtual display is set up but is removed from the current state.
+    const auto displayId = Case::Display::DISPLAY_ID::get();
+    ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId));
+    mFlinger.mutableHwcDisplayData().try_emplace(displayId);
+    Case::Display::injectHwcDisplay(this);
+    auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
+    existing.inject();
+    mFlinger.mutableCurrentState().displays.removeItem(existing.token());
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The existing token should have been removed
+    verifyDisplayIsNotConnected(existing.token());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackChanges) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    constexpr uint32_t oldLayerStack = 0u;
+    constexpr uint32_t newLayerStack = 123u;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // There is a change to the layerStack state
+    display.mutableDrawingDisplayState().layerStack = oldLayerStack;
+    display.mutableCurrentDisplayState().layerStack = newLayerStack;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    EXPECT_EQ(newLayerStack, display.mutableDisplayDevice()->getLayerStack());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    constexpr ui::Rotation oldTransform = ui::ROTATION_0;
+    constexpr ui::Rotation newTransform = ui::ROTATION_180;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // There is a change to the orientation state
+    display.mutableDrawingDisplayState().orientation = oldTransform;
+    display.mutableCurrentDisplayState().orientation = newTransform;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    EXPECT_EQ(newTransform, display.mutableDisplayDevice()->getOrientation());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayLayerStackRectChanges) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    const Rect oldLayerStackRect(0, 0, 0, 0);
+    const Rect newLayerStackRect(0, 0, 123, 456);
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // There is a change to the layerStackSpaceRect state
+    display.mutableDrawingDisplayState().layerStackSpaceRect = oldLayerStackRect;
+    display.mutableCurrentDisplayState().layerStackSpaceRect = newLayerStackRect;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    EXPECT_EQ(newLayerStackRect, display.mutableDisplayDevice()->getLayerStackSpaceRect());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayFrameChanges) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    const Rect oldFrame(0, 0, 0, 0);
+    const Rect newFrame(0, 0, 123, 456);
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // There is a change to the layerStackSpaceRect state
+    display.mutableDrawingDisplayState().orientedDisplaySpaceRect = oldFrame;
+    display.mutableCurrentDisplayState().orientedDisplaySpaceRect = newFrame;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    EXPECT_EQ(newFrame, display.mutableDisplayDevice()->getOrientedDisplaySpaceRect());
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayWidthChanges) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    constexpr int oldWidth = 0;
+    constexpr int oldHeight = 10;
+    constexpr int newWidth = 123;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto nativeWindow = new mock::NativeWindow();
+    auto displaySurface = new compositionengine::mock::DisplaySurface();
+    sp<GraphicBuffer> buf = new GraphicBuffer();
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.setNativeWindow(nativeWindow);
+    display.setDisplaySurface(displaySurface);
+    // Setup injection expectations
+    EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+            .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
+    EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+            .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
+    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
+    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
+    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
+    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1);
+    display.inject();
+
+    // There is a change to the layerStackSpaceRect state
+    display.mutableDrawingDisplayState().width = oldWidth;
+    display.mutableDrawingDisplayState().height = oldHeight;
+    display.mutableCurrentDisplayState().width = newWidth;
+    display.mutableCurrentDisplayState().height = oldHeight;
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    EXPECT_CALL(*displaySurface, resizeBuffers(newWidth, oldHeight)).Times(1);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+}
+
+TEST_F(HandleTransactionLockedTest, processesDisplayHeightChanges) {
+    using Case = NonHwcVirtualDisplayCase;
+
+    constexpr int oldWidth = 0;
+    constexpr int oldHeight = 10;
+    constexpr int newHeight = 123;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto nativeWindow = new mock::NativeWindow();
+    auto displaySurface = new compositionengine::mock::DisplaySurface();
+    sp<GraphicBuffer> buf = new GraphicBuffer();
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.setNativeWindow(nativeWindow);
+    display.setDisplaySurface(displaySurface);
+    // Setup injection expectations
+    EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_WIDTH, _))
+            .WillOnce(DoAll(SetArgPointee<1>(oldWidth), Return(0)));
+    EXPECT_CALL(*nativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
+            .WillOnce(DoAll(SetArgPointee<1>(oldHeight), Return(0)));
+    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_FORMAT)).Times(1);
+    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_CONNECT)).Times(1);
+    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_SET_USAGE64)).Times(1);
+    EXPECT_CALL(*nativeWindow, perform(NATIVE_WINDOW_API_DISCONNECT)).Times(1);
+    display.inject();
+
+    // There is a change to the layerStackSpaceRect state
+    display.mutableDrawingDisplayState().width = oldWidth;
+    display.mutableDrawingDisplayState().height = oldHeight;
+    display.mutableCurrentDisplayState().width = oldWidth;
+    display.mutableCurrentDisplayState().height = newHeight;
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    EXPECT_CALL(*displaySurface, resizeBuffers(oldWidth, newHeight)).Times(1);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.handleTransactionLocked(eDisplayTransactionNeeded);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp
new file mode 100644
index 0000000..69e0501
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyPowerBoostTest.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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 "DisplayTransactionTestHelpers.h"
+
+#include <android/hardware/power/Boost.h>
+
+namespace android {
+namespace {
+
+using android::hardware::power::Boost;
+
+TEST_F(DisplayTransactionTest, notifyPowerBoostNotifiesTouchEvent) {
+    mFlinger.scheduler()->replaceTouchTimer(100);
+    std::this_thread::sleep_for(10ms);                  // wait for callback to be triggered
+    EXPECT_TRUE(mFlinger.scheduler()->isTouchActive()); // Starting timer activates touch
+
+    std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
+    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+
+    EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::CAMERA_SHOT)));
+    std::this_thread::sleep_for(10ms); // wait for callback to maybe be triggered
+    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+
+    std::this_thread::sleep_for(110ms); // wait for reset touch timer to expire and trigger callback
+    EXPECT_FALSE(mFlinger.scheduler()->isTouchActive());
+
+    EXPECT_EQ(NO_ERROR, mFlinger.notifyPowerBoost(static_cast<int32_t>(Boost::INTERACTION)));
+    std::this_thread::sleep_for(10ms); // wait for callback to be triggered.
+    EXPECT_TRUE(mFlinger.scheduler()->isTouchActive());
+}
+
+} // namespace
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnHotplugReceivedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnHotplugReceivedTest.cpp
new file mode 100644
index 0000000..42f4cf3
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnHotplugReceivedTest.cpp
@@ -0,0 +1,158 @@
+/*
+ * 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 "DisplayTransactionTestHelpers.h"
+
+namespace android {
+namespace {
+
+class OnHotplugReceivedTest : public DisplayTransactionTest {};
+
+TEST_F(OnHotplugReceivedTest, hotplugEnqueuesEventsForDisplayTransaction) {
+    constexpr int currentSequenceId = 123;
+    constexpr HWDisplayId hwcDisplayId1 = 456;
+    constexpr HWDisplayId hwcDisplayId2 = 654;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // Set the current sequence id for accepted events
+    mFlinger.mutableComposerSequenceId() = currentSequenceId;
+
+    // Set the main thread id so that the current thread does not appear to be
+    // the main thread.
+    mFlinger.mutableMainThreadId() = std::thread::id();
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // We expect invalidate() to be invoked once to trigger display transaction
+    // processing.
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    // Simulate two hotplug events (a connect and a disconnect)
+    mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId1, Connection::CONNECTED);
+    mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId2, Connection::DISCONNECTED);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The display transaction needed flag should be set.
+    EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+
+    // All events should be in the pending event queue.
+    const auto& pendingEvents = mFlinger.mutablePendingHotplugEvents();
+    ASSERT_EQ(2u, pendingEvents.size());
+    EXPECT_EQ(hwcDisplayId1, pendingEvents[0].hwcDisplayId);
+    EXPECT_EQ(Connection::CONNECTED, pendingEvents[0].connection);
+    EXPECT_EQ(hwcDisplayId2, pendingEvents[1].hwcDisplayId);
+    EXPECT_EQ(Connection::DISCONNECTED, pendingEvents[1].connection);
+}
+
+TEST_F(OnHotplugReceivedTest, hotplugDiscardsUnexpectedEvents) {
+    constexpr int currentSequenceId = 123;
+    constexpr int otherSequenceId = 321;
+    constexpr HWDisplayId displayId = 456;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // Set the current sequence id for accepted events
+    mFlinger.mutableComposerSequenceId() = currentSequenceId;
+
+    // Set the main thread id so that the current thread does not appear to be
+    // the main thread.
+    mFlinger.mutableMainThreadId() = std::thread::id();
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // We do not expect any calls to invalidate().
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(0);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    // Call with an unexpected sequence id
+    mFlinger.onHotplugReceived(otherSequenceId, displayId, Connection::INVALID);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The display transaction needed flag should not be set
+    EXPECT_FALSE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+
+    // There should be no pending events
+    EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty());
+}
+
+TEST_F(OnHotplugReceivedTest, hotplugProcessesEnqueuedEventsIfCalledOnMainThread) {
+    constexpr int currentSequenceId = 123;
+    constexpr HWDisplayId displayId1 = 456;
+
+    // --------------------------------------------------------------------
+    // Note:
+    // --------------------------------------------------------------------
+    // This test case is a bit tricky. We want to verify that
+    // onHotplugReceived() calls processDisplayHotplugEventsLocked(), but we
+    // don't really want to provide coverage for everything the later function
+    // does as there are specific tests for it.
+    // --------------------------------------------------------------------
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // Set the current sequence id for accepted events
+    mFlinger.mutableComposerSequenceId() = currentSequenceId;
+
+    // Set the main thread id so that the current thread does appear to be the
+    // main thread.
+    mFlinger.mutableMainThreadId() = std::this_thread::get_id();
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // We expect invalidate() to be invoked once to trigger display transaction
+    // processing.
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    // 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, Connection::DISCONNECTED);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The display transaction needed flag should be set.
+    EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+
+    // There should be no event queued on return, as it should have been
+    // processed.
+    EXPECT_TRUE(mFlinger.mutablePendingHotplugEvents().empty());
+}
+
+} // namespace
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
new file mode 100644
index 0000000..7a9403b
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_OnInitializeDisplaysTest.cpp
@@ -0,0 +1,102 @@
+/*
+ * 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 "DisplayTransactionTestHelpers.h"
+
+namespace android {
+namespace {
+
+class OnInitializeDisplaysTest : public DisplayTransactionTest {};
+
+TEST_F(OnInitializeDisplaysTest, onInitializeDisplaysSetsUpPrimaryDisplay) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A primary display is set up
+    Case::Display::injectHwcDisplay(this);
+    auto primaryDisplay = Case::Display::makeFakeExistingDisplayInjector(this);
+    primaryDisplay.inject();
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // We expect the surface interceptor to possibly be used, but we treat it as
+    // disabled since it is called as a side effect rather than directly by this
+    // function.
+    EXPECT_CALL(*mSurfaceInterceptor, isEnabled()).WillOnce(Return(false));
+
+    // We expect a call to get the active display config.
+    Case::Display::setupHwcGetActiveConfigCallExpectations(this);
+
+    // We expect invalidate() to be invoked once to trigger display transaction
+    // processing.
+    EXPECT_CALL(*mMessageQueue, invalidate()).Times(1);
+
+    EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.onInitializeDisplays();
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The primary display should have a current state
+    ASSERT_TRUE(hasCurrentDisplayState(primaryDisplay.token()));
+    const auto& primaryDisplayState = getCurrentDisplayState(primaryDisplay.token());
+    // The layer stack state should be set to zero
+    EXPECT_EQ(0u, primaryDisplayState.layerStack);
+    // The orientation state should be set to zero
+    EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation);
+
+    // The orientedDisplaySpaceRect state should be set to INVALID
+    EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.orientedDisplaySpaceRect);
+
+    // The layerStackSpaceRect state should be set to INVALID
+    EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.layerStackSpaceRect);
+
+    // The width and height should both be zero
+    EXPECT_EQ(0u, primaryDisplayState.width);
+    EXPECT_EQ(0u, primaryDisplayState.height);
+
+    // The display should be set to PowerMode::ON
+    ASSERT_TRUE(hasDisplayDevice(primaryDisplay.token()));
+    auto displayDevice = primaryDisplay.mutableDisplayDevice();
+    EXPECT_EQ(PowerMode::ON, displayDevice->getPowerMode());
+
+    // The display refresh period should be set in the orientedDisplaySpaceRect tracker.
+    FrameStats stats;
+    mFlinger.getAnimFrameTracker().getStats(&stats);
+    EXPECT_EQ(DEFAULT_REFRESH_RATE, stats.refreshPeriodNano);
+
+    // The display transaction needed flag should be set.
+    EXPECT_TRUE(hasTransactionFlagSet(eDisplayTransactionNeeded));
+
+    // The compositor timing should be set to default values
+    const auto& compositorTiming = mFlinger.getCompositorTiming();
+    EXPECT_EQ(-DEFAULT_REFRESH_RATE, compositorTiming.deadline);
+    EXPECT_EQ(DEFAULT_REFRESH_RATE, compositorTiming.interval);
+    EXPECT_EQ(DEFAULT_REFRESH_RATE, compositorTiming.presentLatency);
+}
+
+} // namespace
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
new file mode 100644
index 0000000..be01984
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetDisplayStateTest.cpp
@@ -0,0 +1,493 @@
+/*
+ * 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 "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+class SetDisplayStateLockedTest : public DisplayTransactionTest {};
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingWithUnknownDisplay) {
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // We have an unknown display token not associated with a known display
+    sp<BBinder> displayToken = new BBinder();
+
+    // The requested display state references the unknown display.
+    DisplayState state;
+    state.what = DisplayState::eLayerStackChanged;
+    state.token = displayToken;
+    state.layerStack = 456;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags are empty
+    EXPECT_EQ(0u, flags);
+
+    // The display token still doesn't match anything known.
+    EXPECT_FALSE(hasCurrentDisplayState(displayToken));
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingWhenNoChanges) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is already set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // No changes are made to the display
+    DisplayState state;
+    state.what = 0;
+    state.token = display.token();
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags are empty
+    EXPECT_EQ(0u, flags);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfSurfaceDidNotChange) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is already set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // There is a surface that can be set.
+    sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer();
+
+    // The current display state has the surface set
+    display.mutableCurrentDisplayState().surface = surface;
+
+    // The incoming request sets the same surface
+    DisplayState state;
+    state.what = DisplayState::eSurfaceChanged;
+    state.token = display.token();
+    state.surface = surface;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags are empty
+    EXPECT_EQ(0u, flags);
+
+    // The current display state is unchanged.
+    EXPECT_EQ(surface.get(), display.getCurrentDisplayState().surface.get());
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfSurfaceChanged) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is already set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // There is a surface that can be set.
+    sp<mock::GraphicBufferProducer> surface = new mock::GraphicBufferProducer();
+
+    // The current display state does not have a surface
+    display.mutableCurrentDisplayState().surface = nullptr;
+
+    // The incoming request sets a surface
+    DisplayState state;
+    state.what = DisplayState::eSurfaceChanged;
+    state.token = display.token();
+    state.surface = surface;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags indicate a transaction is needed
+    EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+    // The current display layer stack state is set to the new value
+    EXPECT_EQ(surface.get(), display.getCurrentDisplayState().surface.get());
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfLayerStackDidNotChange) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is already set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The display has a layer stack set
+    display.mutableCurrentDisplayState().layerStack = 456u;
+
+    // The incoming request sets the same layer stack
+    DisplayState state;
+    state.what = DisplayState::eLayerStackChanged;
+    state.token = display.token();
+    state.layerStack = 456u;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags are empty
+    EXPECT_EQ(0u, flags);
+
+    // The current display state is unchanged
+    EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStackChanged) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The display has a layer stack set
+    display.mutableCurrentDisplayState().layerStack = 654u;
+
+    // The incoming request sets a different layer stack
+    DisplayState state;
+    state.what = DisplayState::eLayerStackChanged;
+    state.token = display.token();
+    state.layerStack = 456u;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags indicate a transaction is needed
+    EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+    // The desired display state has been set to the new value.
+    EXPECT_EQ(456u, display.getCurrentDisplayState().layerStack);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfProjectionDidNotChange) {
+    using Case = SimplePrimaryDisplayCase;
+    constexpr ui::Rotation initialOrientation = ui::ROTATION_180;
+    const Rect initialOrientedDisplayRect = {1, 2, 3, 4};
+    const Rect initialLayerStackRect = {5, 6, 7, 8};
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The current display state projection state is all set
+    display.mutableCurrentDisplayState().orientation = initialOrientation;
+    display.mutableCurrentDisplayState().orientedDisplaySpaceRect = initialOrientedDisplayRect;
+    display.mutableCurrentDisplayState().layerStackSpaceRect = initialLayerStackRect;
+
+    // The incoming request sets the same projection state
+    DisplayState state;
+    state.what = DisplayState::eDisplayProjectionChanged;
+    state.token = display.token();
+    state.orientation = initialOrientation;
+    state.orientedDisplaySpaceRect = initialOrientedDisplayRect;
+    state.layerStackSpaceRect = initialLayerStackRect;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags are empty
+    EXPECT_EQ(0u, flags);
+
+    // The current display state is unchanged
+    EXPECT_EQ(initialOrientation, display.getCurrentDisplayState().orientation);
+
+    EXPECT_EQ(initialOrientedDisplayRect,
+              display.getCurrentDisplayState().orientedDisplaySpaceRect);
+    EXPECT_EQ(initialLayerStackRect, display.getCurrentDisplayState().layerStackSpaceRect);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfOrientationChanged) {
+    using Case = SimplePrimaryDisplayCase;
+    constexpr ui::Rotation initialOrientation = ui::ROTATION_90;
+    constexpr ui::Rotation desiredOrientation = ui::ROTATION_180;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The current display state has an orientation set
+    display.mutableCurrentDisplayState().orientation = initialOrientation;
+
+    // The incoming request sets a different orientation
+    DisplayState state;
+    state.what = DisplayState::eDisplayProjectionChanged;
+    state.token = display.token();
+    state.orientation = desiredOrientation;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags indicate a transaction is needed
+    EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+    // The current display state has the new value.
+    EXPECT_EQ(desiredOrientation, display.getCurrentDisplayState().orientation);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfFrameChanged) {
+    using Case = SimplePrimaryDisplayCase;
+    const Rect initialOrientedDisplayRect = {0, 0, 0, 0};
+    const Rect desiredOrientedDisplayRect = {5, 6, 7, 8};
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The current display state does not have a orientedDisplaySpaceRect
+    display.mutableCurrentDisplayState().orientedDisplaySpaceRect = initialOrientedDisplayRect;
+
+    // The incoming request sets a orientedDisplaySpaceRect
+    DisplayState state;
+    state.what = DisplayState::eDisplayProjectionChanged;
+    state.token = display.token();
+    state.orientedDisplaySpaceRect = desiredOrientedDisplayRect;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags indicate a transaction is needed
+    EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+    // The current display state has the new value.
+    EXPECT_EQ(desiredOrientedDisplayRect,
+              display.getCurrentDisplayState().orientedDisplaySpaceRect);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfLayerStackRectChanged) {
+    using Case = SimplePrimaryDisplayCase;
+    const Rect initialLayerStackRect = {0, 0, 0, 0};
+    const Rect desiredLayerStackRect = {5, 6, 7, 8};
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The current display state does not have a layerStackSpaceRect
+    display.mutableCurrentDisplayState().layerStackSpaceRect = initialLayerStackRect;
+
+    // The incoming request sets a layerStackSpaceRect
+    DisplayState state;
+    state.what = DisplayState::eDisplayProjectionChanged;
+    state.token = display.token();
+    state.layerStackSpaceRect = desiredLayerStackRect;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags indicate a transaction is needed
+    EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+    // The current display state has the new value.
+    EXPECT_EQ(desiredLayerStackRect, display.getCurrentDisplayState().layerStackSpaceRect);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedDoesNothingIfSizeDidNotChange) {
+    using Case = SimplePrimaryDisplayCase;
+    constexpr uint32_t initialWidth = 1024;
+    constexpr uint32_t initialHeight = 768;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The current display state has a size set
+    display.mutableCurrentDisplayState().width = initialWidth;
+    display.mutableCurrentDisplayState().height = initialHeight;
+
+    // The incoming request sets the same display size
+    DisplayState state;
+    state.what = DisplayState::eDisplaySizeChanged;
+    state.token = display.token();
+    state.width = initialWidth;
+    state.height = initialHeight;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags are empty
+    EXPECT_EQ(0u, flags);
+
+    // The current display state is unchanged
+    EXPECT_EQ(initialWidth, display.getCurrentDisplayState().width);
+    EXPECT_EQ(initialHeight, display.getCurrentDisplayState().height);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfWidthChanged) {
+    using Case = SimplePrimaryDisplayCase;
+    constexpr uint32_t initialWidth = 0;
+    constexpr uint32_t desiredWidth = 1024;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The display does not yet have a width
+    display.mutableCurrentDisplayState().width = initialWidth;
+
+    // The incoming request sets a display width
+    DisplayState state;
+    state.what = DisplayState::eDisplaySizeChanged;
+    state.token = display.token();
+    state.width = desiredWidth;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags indicate a transaction is needed
+    EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+    // The current display state has the new value.
+    EXPECT_EQ(desiredWidth, display.getCurrentDisplayState().width);
+}
+
+TEST_F(SetDisplayStateLockedTest, setDisplayStateLockedRequestsUpdateIfHeightChanged) {
+    using Case = SimplePrimaryDisplayCase;
+    constexpr uint32_t initialHeight = 0;
+    constexpr uint32_t desiredHeight = 768;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A display is set up
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The display does not yet have a height
+    display.mutableCurrentDisplayState().height = initialHeight;
+
+    // The incoming request sets a display height
+    DisplayState state;
+    state.what = DisplayState::eDisplaySizeChanged;
+    state.token = display.token();
+    state.height = desiredHeight;
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    uint32_t flags = mFlinger.setDisplayStateLocked(state);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    // The returned flags indicate a transaction is needed
+    EXPECT_EQ(eDisplayTransactionNeeded, flags);
+
+    // The current display state has the new value.
+    EXPECT_EQ(desiredHeight, display.getCurrentDisplayState().height);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
new file mode 100644
index 0000000..2117628
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetPowerModeInternalTest.cpp
@@ -0,0 +1,498 @@
+/*
+ * 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 "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+// Used when we simulate a display that supports doze.
+template <typename Display>
+struct DozeIsSupportedVariant {
+    static constexpr bool DOZE_SUPPORTED = true;
+    static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE =
+            IComposerClient::PowerMode::DOZE;
+    static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND =
+            IComposerClient::PowerMode::DOZE_SUSPEND;
+
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getDisplayCapabilities(Display::HWC_DISPLAY_ID, _))
+                .WillOnce(DoAll(SetArgPointee<1>(
+                                        std::vector<DisplayCapability>({DisplayCapability::DOZE})),
+                                Return(Error::NONE)));
+    }
+};
+
+template <typename Display>
+// Used when we simulate a display that does not support doze.
+struct DozeNotSupportedVariant {
+    static constexpr bool DOZE_SUPPORTED = false;
+    static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE =
+            IComposerClient::PowerMode::ON;
+    static constexpr IComposerClient::PowerMode ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND =
+            IComposerClient::PowerMode::ON;
+
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getDisplayCapabilities(Display::HWC_DISPLAY_ID, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<DisplayCapability>({})),
+                                Return(Error::NONE)));
+    }
+};
+
+struct EventThreadBaseSupportedVariant {
+    static void setupVsyncAndEventThreadNoCallExpectations(DisplayTransactionTest* test) {
+        // The callback should not be notified to toggle VSYNC.
+        EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(_)).Times(0);
+
+        // The event thread should not be notified.
+        EXPECT_CALL(*test->mEventThread, onScreenReleased()).Times(0);
+        EXPECT_CALL(*test->mEventThread, onScreenAcquired()).Times(0);
+    }
+};
+
+struct EventThreadNotSupportedVariant : public EventThreadBaseSupportedVariant {
+    static void setupAcquireAndEnableVsyncCallExpectations(DisplayTransactionTest* test) {
+        // These calls are only expected for the primary display.
+
+        // Instead expect no calls.
+        setupVsyncAndEventThreadNoCallExpectations(test);
+    }
+
+    static void setupReleaseAndDisableVsyncCallExpectations(DisplayTransactionTest* test) {
+        // These calls are only expected for the primary display.
+
+        // Instead expect no calls.
+        setupVsyncAndEventThreadNoCallExpectations(test);
+    }
+};
+
+struct EventThreadIsSupportedVariant : public EventThreadBaseSupportedVariant {
+    static void setupAcquireAndEnableVsyncCallExpectations(DisplayTransactionTest* test) {
+        // The callback should be notified to enable VSYNC.
+        EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(true)).Times(1);
+
+        // The event thread should be notified that the screen was acquired.
+        EXPECT_CALL(*test->mEventThread, onScreenAcquired()).Times(1);
+    }
+
+    static void setupReleaseAndDisableVsyncCallExpectations(DisplayTransactionTest* test) {
+        // The callback should be notified to disable VSYNC.
+        EXPECT_CALL(test->mSchedulerCallback, setVsyncEnabled(false)).Times(1);
+
+        // The event thread should not be notified that the screen was released.
+        EXPECT_CALL(*test->mEventThread, onScreenReleased()).Times(1);
+    }
+};
+
+struct DispSyncIsSupportedVariant {
+    static void setupResetModelCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mVsyncController, startPeriodTransition(DEFAULT_REFRESH_RATE)).Times(1);
+        EXPECT_CALL(*test->mVSyncTracker, resetModel()).Times(1);
+    }
+};
+
+struct DispSyncNotSupportedVariant {
+    static void setupResetModelCallExpectations(DisplayTransactionTest* /* test */) {}
+};
+
+// --------------------------------------------------------------------
+// Note:
+//
+// There are a large number of transitions we could test, however we only test a
+// selected subset which provides complete test coverage of the implementation.
+// --------------------------------------------------------------------
+
+template <PowerMode initialPowerMode, PowerMode targetPowerMode>
+struct TransitionVariantCommon {
+    static constexpr auto INITIAL_POWER_MODE = initialPowerMode;
+    static constexpr auto TARGET_POWER_MODE = targetPowerMode;
+
+    static void verifyPostconditions(DisplayTransactionTest*) {}
+};
+
+struct TransitionOffToOnVariant : public TransitionVariantCommon<PowerMode::OFF, PowerMode::ON> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
+        Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+        Case::DispSync::setupResetModelCallExpectations(test);
+        Case::setupRepaintEverythingCallExpectations(test);
+    }
+
+    static void verifyPostconditions(DisplayTransactionTest* test) {
+        EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
+        EXPECT_TRUE(test->mFlinger.getHasPoweredOff());
+    }
+};
+
+struct TransitionOffToDozeSuspendVariant
+      : 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);
+        Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+        Case::setupRepaintEverythingCallExpectations(test);
+    }
+
+    static void verifyPostconditions(DisplayTransactionTest* test) {
+        EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
+        EXPECT_TRUE(test->mFlinger.getHasPoweredOff());
+    }
+};
+
+struct TransitionOnToOffVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::OFF> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
+        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
+    }
+
+    static void verifyPostconditions(DisplayTransactionTest* test) {
+        EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
+    }
+};
+
+struct TransitionDozeSuspendToOffVariant
+      : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::OFF> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::OFF);
+    }
+
+    static void verifyPostconditions(DisplayTransactionTest* test) {
+        EXPECT_TRUE(test->mFlinger.getVisibleRegionsDirty());
+    }
+};
+
+struct TransitionOnToDozeVariant : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+        Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
+    }
+};
+
+struct TransitionDozeSuspendToDozeVariant
+      : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::DOZE> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+        Case::DispSync::setupResetModelCallExpectations(test);
+        Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE);
+    }
+};
+
+struct TransitionDozeToOnVariant : public TransitionVariantCommon<PowerMode::DOZE, PowerMode::ON> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
+    }
+};
+
+struct TransitionDozeSuspendToOnVariant
+      : public TransitionVariantCommon<PowerMode::DOZE_SUSPEND, PowerMode::ON> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupAcquireAndEnableVsyncCallExpectations(test);
+        Case::DispSync::setupResetModelCallExpectations(test);
+        Case::setupComposerCallExpectations(test, IComposerClient::PowerMode::ON);
+    }
+};
+
+struct TransitionOnToDozeSuspendVariant
+      : public TransitionVariantCommon<PowerMode::ON, PowerMode::DOZE_SUSPEND> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupReleaseAndDisableVsyncCallExpectations(test);
+        Case::setupComposerCallExpectations(test, Case::Doze::ACTUAL_POWER_MODE_FOR_DOZE_SUSPEND);
+    }
+};
+
+struct TransitionOnToUnknownVariant
+      : public TransitionVariantCommon<PowerMode::ON, static_cast<PowerMode>(POWER_MODE_LEET)> {
+    template <typename Case>
+    static void setupCallExpectations(DisplayTransactionTest* test) {
+        Case::EventThread::setupVsyncAndEventThreadNoCallExpectations(test);
+        Case::setupNoComposerPowerModeCallExpectations(test);
+    }
+};
+
+// --------------------------------------------------------------------
+// Note:
+//
+// Rather than testing the cartesian product of
+// DozeIsSupported/DozeNotSupported with all other options, we use one for one
+// display type, and the other for another display type.
+// --------------------------------------------------------------------
+
+template <typename DisplayVariant, typename DozeVariant, typename EventThreadVariant,
+          typename DispSyncVariant, typename TransitionVariant>
+struct DisplayPowerCase {
+    using Display = DisplayVariant;
+    using Doze = DozeVariant;
+    using EventThread = EventThreadVariant;
+    using DispSync = DispSyncVariant;
+    using Transition = TransitionVariant;
+
+    static auto injectDisplayWithInitialPowerMode(DisplayTransactionTest* test, PowerMode mode) {
+        Display::injectHwcDisplayWithNoDefaultCapabilities(test);
+        auto display = Display::makeFakeExistingDisplayInjector(test);
+        display.inject();
+        display.mutableDisplayDevice()->setPowerMode(mode);
+        return display;
+    }
+
+    static void setInitialPrimaryHWVsyncEnabled(DisplayTransactionTest* test, bool enabled) {
+        test->mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = enabled;
+    }
+
+    static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+    }
+
+    static void setupSurfaceInterceptorCallExpectations(DisplayTransactionTest* test,
+                                                        PowerMode mode) {
+        EXPECT_CALL(*test->mSurfaceInterceptor, isEnabled()).WillOnce(Return(true));
+        EXPECT_CALL(*test->mSurfaceInterceptor, savePowerModeUpdate(_, static_cast<int32_t>(mode)))
+                .Times(1);
+    }
+
+    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),
+                                      Return(Error::NONE)));
+
+        // Any calls to get whether the display supports dozing will return the value set by the
+        // policy variant.
+        EXPECT_CALL(*test->mComposer, getDozeSupport(Display::HWC_DISPLAY_ID, _))
+                .WillRepeatedly(DoAll(SetArgPointee<1>(Doze::DOZE_SUPPORTED), Return(Error::NONE)));
+
+        EXPECT_CALL(*test->mComposer, setPowerMode(Display::HWC_DISPLAY_ID, mode)).Times(1);
+    }
+
+    static void setupNoComposerPowerModeCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, setPowerMode(Display::HWC_DISPLAY_ID, _)).Times(0);
+    }
+};
+
+// A sample configuration for the primary display.
+// In addition to having event thread support, we emulate doze support.
+template <typename TransitionVariant>
+using PrimaryDisplayPowerCase =
+        DisplayPowerCase<PrimaryDisplayVariant, DozeIsSupportedVariant<PrimaryDisplayVariant>,
+                         EventThreadIsSupportedVariant, DispSyncIsSupportedVariant,
+                         TransitionVariant>;
+
+// A sample configuration for the external display.
+// In addition to not having event thread support, we emulate not having doze
+// support.
+template <typename TransitionVariant>
+using ExternalDisplayPowerCase =
+        DisplayPowerCase<ExternalDisplayVariant, DozeNotSupportedVariant<ExternalDisplayVariant>,
+                         EventThreadNotSupportedVariant, DispSyncNotSupportedVariant,
+                         TransitionVariant>;
+
+class SetPowerModeInternalTest : public DisplayTransactionTest {
+public:
+    template <typename Case>
+    void transitionDisplayCommon();
+};
+
+template <PowerMode PowerMode>
+struct PowerModeInitialVSyncEnabled : public std::false_type {};
+
+template <>
+struct PowerModeInitialVSyncEnabled<PowerMode::ON> : public std::true_type {};
+
+template <>
+struct PowerModeInitialVSyncEnabled<PowerMode::DOZE> : public std::true_type {};
+
+template <typename Case>
+void SetPowerModeInternalTest::transitionDisplayCommon() {
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    Case::Doze::setupComposerCallExpectations(this);
+    auto display =
+            Case::injectDisplayWithInitialPowerMode(this, Case::Transition::INITIAL_POWER_MODE);
+    Case::setInitialPrimaryHWVsyncEnabled(this,
+                                          PowerModeInitialVSyncEnabled<
+                                                  Case::Transition::INITIAL_POWER_MODE>::value);
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    Case::setupSurfaceInterceptorCallExpectations(this, Case::Transition::TARGET_POWER_MODE);
+    Case::Transition::template setupCallExpectations<Case>(this);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(),
+                                  Case::Transition::TARGET_POWER_MODE);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    Case::Transition::verifyPostconditions(this);
+}
+
+TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfNoChange) {
+    using Case = SimplePrimaryDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // A primary display device is set up
+    Case::Display::injectHwcDisplay(this);
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The display is already set to PowerMode::ON
+    display.mutableDisplayDevice()->setPowerMode(PowerMode::ON);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::ON);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
+}
+
+TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay) {
+    using Case = HwcVirtualDisplayCase;
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // Insert display data so that the HWC thinks it created the virtual display.
+    const auto displayId = Case::Display::DISPLAY_ID::get();
+    ASSERT_TRUE(HalVirtualDisplayId::tryCast(displayId));
+    mFlinger.mutableHwcDisplayData().try_emplace(displayId);
+
+    // A virtual display device is set up
+    Case::Display::injectHwcDisplay(this);
+    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
+    display.inject();
+
+    // The display is set to PowerMode::ON
+    getDisplayDevice(display.token())->setPowerMode(PowerMode::ON);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), PowerMode::OFF);
+
+    // --------------------------------------------------------------------
+    // Postconditions
+
+    EXPECT_EQ(PowerMode::ON, display.mutableDisplayDevice()->getPowerMode());
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOffToDozeSuspendVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToOffVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOffVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozePrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozePrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownPrimaryDisplay) {
+    transitionDisplayCommon<PrimaryDisplayPowerCase<TransitionOnToUnknownVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToOnExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOffToDozeSuspendExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOffToDozeSuspendVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToOffExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToOffVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOffExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOffVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToDozeExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToDozeVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeToOnExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromDozeSuspendToOnExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionDozeSuspendToOnVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToDozeSuspendExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToDozeSuspendVariant>>();
+}
+
+TEST_F(SetPowerModeInternalTest, transitionsDisplayFromOnToUnknownExternalDisplay) {
+    transitionDisplayCommon<ExternalDisplayPowerCase<TransitionOnToUnknownVariant>>();
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
new file mode 100644
index 0000000..61f0788
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -0,0 +1,316 @@
+/*
+ * 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 "DisplayTransactionTestHelpers.h"
+
+namespace android {
+namespace {
+
+using hal::RenderIntent;
+
+// For this variant, SurfaceFlinger should configure itself with wide display
+// support, and the display should respond with an non-empty list of supported
+// color modes. Wide-color support should be configured.
+template <typename Display>
+struct WideColorP3ColorimetricSupportedVariant {
+    static constexpr bool WIDE_COLOR_SUPPORTED = true;
+
+    static void injectConfigChange(DisplayTransactionTest* test) {
+        test->mFlinger.mutableUseColorManagement() = true;
+        test->mFlinger.mutableHasWideColorDisplay() = true;
+        test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
+    }
+
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mNativeWindow, perform(NATIVE_WINDOW_SET_BUFFERS_DATASPACE)).Times(1);
+
+        EXPECT_CALL(*test->mComposer, getColorModes(Display::HWC_DISPLAY_ID, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<ColorMode>({ColorMode::DISPLAY_P3})),
+                                Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    getRenderIntents(Display::HWC_DISPLAY_ID, ColorMode::DISPLAY_P3, _))
+                .WillOnce(DoAll(SetArgPointee<2>(
+                                        std::vector<RenderIntent>({RenderIntent::COLORIMETRIC})),
+                                Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer,
+                    setColorMode(Display::HWC_DISPLAY_ID, ColorMode::SRGB,
+                                 RenderIntent::COLORIMETRIC))
+                .WillOnce(Return(Error::NONE));
+    }
+};
+
+template <typename Display>
+struct Hdr10PlusSupportedVariant {
+    static constexpr bool HDR10_PLUS_SUPPORTED = true;
+    static constexpr bool HDR10_SUPPORTED = true;
+    static constexpr bool HDR_HLG_SUPPORTED = false;
+    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getHdrCapabilities(_, _, _, _, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>({
+                                        Hdr::HDR10_PLUS,
+                                        Hdr::HDR10,
+                                })),
+                                Return(Error::NONE)));
+    }
+};
+
+// For this variant, the composer should respond with a non-empty list of HDR
+// modes containing HDR10, so HDR10 support should be configured.
+template <typename Display>
+struct Hdr10SupportedVariant {
+    static constexpr bool HDR10_PLUS_SUPPORTED = false;
+    static constexpr bool HDR10_SUPPORTED = true;
+    static constexpr bool HDR_HLG_SUPPORTED = false;
+    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::HDR10})),
+                                Return(Error::NONE)));
+    }
+};
+
+// For this variant, the composer should respond with a non-empty list of HDR
+// modes containing HLG, so HLG support should be configured.
+template <typename Display>
+struct HdrHlgSupportedVariant {
+    static constexpr bool HDR10_PLUS_SUPPORTED = false;
+    static constexpr bool HDR10_SUPPORTED = false;
+    static constexpr bool HDR_HLG_SUPPORTED = true;
+    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = false;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
+                .WillOnce(
+                        DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::HLG})), Return(Error::NONE)));
+    }
+};
+
+// For this variant, the composer should respond with a non-empty list of HDR
+// modes containing DOLBY_VISION, so DOLBY_VISION support should be configured.
+template <typename Display>
+struct HdrDolbyVisionSupportedVariant {
+    static constexpr bool HDR10_PLUS_SUPPORTED = false;
+    static constexpr bool HDR10_SUPPORTED = false;
+    static constexpr bool HDR_HLG_SUPPORTED = false;
+    static constexpr bool HDR_DOLBY_VISION_SUPPORTED = true;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getHdrCapabilities(Display::HWC_DISPLAY_ID, _, _, _, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hdr>({Hdr::DOLBY_VISION})),
+                                Return(Error::NONE)));
+    }
+};
+
+template <typename Display>
+struct Smpte2086PerFrameMetadataSupportVariant {
+    static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::SMPTE2086;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
+                .WillOnce(Return(std::vector<PerFrameMetadataKey>({
+                        PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X,
+                        PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y,
+                        PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X,
+                        PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_Y,
+                        PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_X,
+                        PerFrameMetadataKey::DISPLAY_BLUE_PRIMARY_Y,
+                        PerFrameMetadataKey::WHITE_POINT_X,
+                        PerFrameMetadataKey::WHITE_POINT_Y,
+                        PerFrameMetadataKey::MAX_LUMINANCE,
+                        PerFrameMetadataKey::MIN_LUMINANCE,
+                })));
+    }
+};
+
+template <typename Display>
+struct Cta861_3_PerFrameMetadataSupportVariant {
+    static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::CTA861_3;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
+                .WillOnce(Return(std::vector<PerFrameMetadataKey>({
+                        PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL,
+                        PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL,
+                })));
+    }
+};
+
+template <typename Display>
+struct Hdr10_Plus_PerFrameMetadataSupportVariant {
+    static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::HDR10PLUS;
+    static void setupComposerCallExpectations(DisplayTransactionTest* test) {
+        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
+                .WillOnce(Return(std::vector<PerFrameMetadataKey>({
+                        PerFrameMetadataKey::HDR10_PLUS_SEI,
+                })));
+    }
+};
+
+using WideColorP3ColorimetricDisplayCase =
+        Case<PrimaryDisplayVariant, WideColorP3ColorimetricSupportedVariant<PrimaryDisplayVariant>,
+             HdrNotSupportedVariant<PrimaryDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using Hdr10PlusDisplayCase =
+        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+             Hdr10SupportedVariant<PrimaryDisplayVariant>,
+             Hdr10_Plus_PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using Hdr10DisplayCase =
+        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+             Hdr10SupportedVariant<PrimaryDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using HdrHlgDisplayCase =
+        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+             HdrHlgSupportedVariant<PrimaryDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using HdrDolbyVisionDisplayCase =
+        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+             HdrDolbyVisionSupportedVariant<PrimaryDisplayVariant>,
+             NoPerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using HdrSmpte2086DisplayCase =
+        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+             HdrNotSupportedVariant<PrimaryDisplayVariant>,
+             Smpte2086PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+using HdrCta861_3_DisplayCase =
+        Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
+             HdrNotSupportedVariant<PrimaryDisplayVariant>,
+             Cta861_3_PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
+
+class SetupNewDisplayDeviceInternalTest : public DisplayTransactionTest {
+public:
+    template <typename T>
+    void setupNewDisplayDeviceInternalTest();
+};
+
+template <typename Case>
+void SetupNewDisplayDeviceInternalTest::setupNewDisplayDeviceInternalTest() {
+    const sp<BBinder> displayToken = new BBinder();
+    const sp<compositionengine::mock::DisplaySurface> displaySurface =
+            new compositionengine::mock::DisplaySurface();
+    const sp<mock::GraphicBufferProducer> producer = new mock::GraphicBufferProducer();
+
+    // --------------------------------------------------------------------
+    // Preconditions
+
+    // Wide color displays support is configured appropriately
+    Case::WideColorSupport::injectConfigChange(this);
+
+    // The display is setup with the HWC.
+    Case::Display::injectHwcDisplay(this);
+
+    // SurfaceFlinger will use a test-controlled factory for native window
+    // surfaces.
+    injectFakeNativeWindowSurfaceFactory();
+
+    // A compositionengine::Display has already been created
+    auto compositionDisplay = Case::Display::injectCompositionDisplay(this);
+
+    // --------------------------------------------------------------------
+    // Call Expectations
+
+    // Various native window calls will be made.
+    Case::Display::setupNativeWindowSurfaceCreationCallExpectations(this);
+    Case::Display::setupHwcGetActiveConfigCallExpectations(this);
+    Case::WideColorSupport::setupComposerCallExpectations(this);
+    Case::HdrSupport::setupComposerCallExpectations(this);
+    Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    DisplayDeviceState state;
+    if (const auto connectionType = Case::Display::CONNECTION_TYPE::value) {
+        const auto displayId = PhysicalDisplayId::tryCast(Case::Display::DISPLAY_ID::get());
+        ASSERT_TRUE(displayId);
+        const auto hwcDisplayId = Case::Display::HWC_DISPLAY_ID_OPT::value;
+        ASSERT_TRUE(hwcDisplayId);
+        state.physical = {.id = *displayId, .type = *connectionType, .hwcDisplayId = *hwcDisplayId};
+    }
+
+    state.isSecure = static_cast<bool>(Case::Display::SECURE);
+
+    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());
+    EXPECT_EQ(Case::Display::WIDTH, device->getWidth());
+    EXPECT_EQ(Case::Display::HEIGHT, device->getHeight());
+    EXPECT_EQ(Case::WideColorSupport::WIDE_COLOR_SUPPORTED, device->hasWideColorGamut());
+    EXPECT_EQ(Case::HdrSupport::HDR10_PLUS_SUPPORTED, device->hasHDR10PlusSupport());
+    EXPECT_EQ(Case::HdrSupport::HDR10_SUPPORTED, device->hasHDR10Support());
+    EXPECT_EQ(Case::HdrSupport::HDR_HLG_SUPPORTED, device->hasHLGSupport());
+    EXPECT_EQ(Case::HdrSupport::HDR_DOLBY_VISION_SUPPORTED, device->hasDolbyVisionSupport());
+    // Note: This is not Case::Display::HWC_ACTIVE_CONFIG_ID as the ids are
+    // remapped, and the test only ever sets up one config. If there were an error
+    // looking up the remapped index, device->getActiveConfig() would be -1 instead.
+    EXPECT_EQ(0, device->getActiveConfig().value());
+    EXPECT_EQ(Case::PerFrameMetadataSupport::PER_FRAME_METADATA_KEYS,
+              device->getSupportedPerFrameMetadata());
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createSimplePrimaryDisplay) {
+    setupNewDisplayDeviceInternalTest<SimplePrimaryDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createSimpleExternalDisplay) {
+    setupNewDisplayDeviceInternalTest<SimpleExternalDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createNonHwcVirtualDisplay) {
+    setupNewDisplayDeviceInternalTest<NonHwcVirtualDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHwcVirtualDisplay) {
+    setupNewDisplayDeviceInternalTest<HwcVirtualDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createWideColorP3Display) {
+    setupNewDisplayDeviceInternalTest<WideColorP3ColorimetricDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdr10PlusDisplay) {
+    setupNewDisplayDeviceInternalTest<Hdr10PlusDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdr10Display) {
+    setupNewDisplayDeviceInternalTest<Hdr10DisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdrHlgDisplay) {
+    setupNewDisplayDeviceInternalTest<HdrHlgDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdrDolbyVisionDisplay) {
+    setupNewDisplayDeviceInternalTest<HdrDolbyVisionDisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdrSmpte2086DisplayCase) {
+    setupNewDisplayDeviceInternalTest<HdrSmpte2086DisplayCase>();
+}
+
+TEST_F(SetupNewDisplayDeviceInternalTest, createHdrCta816_3_DisplayCase) {
+    setupNewDisplayDeviceInternalTest<HdrCta861_3_DisplayCase>();
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h
index 8e1f943..5c5b18e 100644
--- a/services/surfaceflinger/tests/utils/TransactionUtils.h
+++ b/services/surfaceflinger/tests/utils/TransactionUtils.h
@@ -16,6 +16,9 @@
 
 #pragma once
 
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include <chrono>
 
 #include <android/native_window.h>
@@ -181,3 +184,6 @@
 };
 } // namespace
 } // 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/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp b/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
index 0d4c55e..6589f74 100644
--- a/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
+++ b/services/vibratorservice/benchmarks/VibratorHalControllerBenchmarks.cpp
@@ -46,13 +46,26 @@
 
     auto getOtherArg(const State& state, std::size_t index) const { return state.range(index + 0); }
 
-    bool hasCapabilities(vibrator::HalResult<vibrator::Capabilities> result,
-                         vibrator::Capabilities query) {
+    bool hasCapabilities(const vibrator::HalResult<vibrator::Capabilities>& result,
+                         vibrator::Capabilities&& query, State& state) {
+        if (result.isFailed()) {
+            state.SkipWithError(result.errorMessage());
+            return false;
+        }
         if (!result.isOk()) {
             return false;
         }
         return (result.value() & query) == query;
     }
+
+    template <class R>
+    bool checkHalResult(const vibrator::HalResult<R>& result, State& state) {
+        if (result.isFailed()) {
+            state.SkipWithError(result.errorMessage());
+            return false;
+        }
+        return true;
+    }
 };
 
 #define BENCHMARK_WRAPPER(fixt, test, code)                \
@@ -79,7 +92,10 @@
 
 BENCHMARK_WRAPPER(VibratorBench, ping, {
     for (auto _ : state) {
-        mController.ping();
+        state.ResumeTiming();
+        auto ret = mController.ping();
+        state.PauseTiming();
+        checkHalResult(ret, state);
     }
 });
 
@@ -95,9 +111,11 @@
 
     for (auto _ : state) {
         state.ResumeTiming();
-        mController.on(duration, callback);
+        auto ret = mController.on(duration, callback);
         state.PauseTiming();
-        mController.off();
+        if (checkHalResult(ret, state)) {
+            checkHalResult(mController.off(), state);
+        }
     }
 });
 
@@ -107,16 +125,18 @@
 
     for (auto _ : state) {
         state.PauseTiming();
-        mController.on(duration, callback);
+        if (!checkHalResult(mController.on(duration, callback), state)) {
+            continue;
+        }
         state.ResumeTiming();
-        mController.off();
+        checkHalResult(mController.off(), state);
     }
 });
 
 BENCHMARK_WRAPPER(VibratorBench, setAmplitude, {
-    auto capabilitiesResult = mController.getCapabilities();
+    auto result = mController.getCapabilities();
 
-    if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::AMPLITUDE_CONTROL)) {
+    if (!hasCapabilities(result, vibrator::Capabilities::AMPLITUDE_CONTROL, state)) {
         return;
     }
 
@@ -128,18 +148,22 @@
         state.PauseTiming();
         vibrator::HalController controller;
         controller.init();
-        controller.on(duration, callback);
+        if (!checkHalResult(controller.on(duration, callback), state)) {
+            continue;
+        }
         state.ResumeTiming();
-        controller.setAmplitude(amplitude);
+        auto ret = controller.setAmplitude(amplitude);
         state.PauseTiming();
-        controller.off();
+        if (checkHalResult(ret, state)) {
+            checkHalResult(controller.off(), state);
+        }
     }
 });
 
 BENCHMARK_WRAPPER(VibratorBench, setAmplitudeCached, {
-    auto capabilitiesResult = mController.getCapabilities();
+    auto result = mController.getCapabilities();
 
-    if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::AMPLITUDE_CONTROL)) {
+    if (!hasCapabilities(result, vibrator::Capabilities::AMPLITUDE_CONTROL, state)) {
         return;
     }
 
@@ -147,19 +171,19 @@
     auto callback = []() {};
     auto amplitude = UINT8_MAX;
 
-    mController.on(duration, callback);
+    checkHalResult(mController.on(duration, callback), state);
 
     for (auto _ : state) {
-        mController.setAmplitude(amplitude);
+        checkHalResult(mController.setAmplitude(amplitude), state);
     }
 
-    mController.off();
+    checkHalResult(mController.off(), state);
 });
 
 BENCHMARK_WRAPPER(VibratorBench, setExternalControl, {
-    auto capabilitiesResult = mController.getCapabilities();
+    auto result = mController.getCapabilities();
 
-    if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::EXTERNAL_CONTROL)) {
+    if (!hasCapabilities(result, vibrator::Capabilities::EXTERNAL_CONTROL, state)) {
         return;
     }
 
@@ -168,43 +192,47 @@
         vibrator::HalController controller;
         controller.init();
         state.ResumeTiming();
-        controller.setExternalControl(true);
+        auto ret = controller.setExternalControl(true);
         state.PauseTiming();
-        controller.setExternalControl(false);
+        if (checkHalResult(ret, state)) {
+            checkHalResult(controller.setExternalControl(false), state);
+        }
     }
 });
 
 BENCHMARK_WRAPPER(VibratorBench, setExternalControlCached, {
-    auto capabilitiesResult = mController.getCapabilities();
+    auto result = mController.getCapabilities();
 
-    if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::EXTERNAL_CONTROL)) {
+    if (!hasCapabilities(result, vibrator::Capabilities::EXTERNAL_CONTROL, state)) {
         return;
     }
 
     for (auto _ : state) {
         state.ResumeTiming();
-        mController.setExternalControl(true);
+        auto ret = mController.setExternalControl(true);
         state.PauseTiming();
-        mController.setExternalControl(false);
+        if (checkHalResult(ret, state)) {
+            checkHalResult(mController.setExternalControl(false), state);
+        }
     }
 });
 
 BENCHMARK_WRAPPER(VibratorBench, setExternalAmplitudeCached, {
-    auto capabilitiesResult = mController.getCapabilities();
+    auto result = mController.getCapabilities();
 
-    if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::EXTERNAL_AMPLITUDE_CONTROL)) {
+    if (!hasCapabilities(result, vibrator::Capabilities::EXTERNAL_AMPLITUDE_CONTROL, state)) {
         return;
     }
 
     auto amplitude = UINT8_MAX;
 
-    mController.setExternalControl(true);
+    checkHalResult(mController.setExternalControl(true), state);
 
     for (auto _ : state) {
-        mController.setAmplitude(amplitude);
+        checkHalResult(mController.setAmplitude(amplitude), state);
     }
 
-    mController.setExternalControl(false);
+    checkHalResult(mController.setExternalControl(false), state);
 });
 
 BENCHMARK_WRAPPER(VibratorBench, getCapabilities, {
@@ -213,16 +241,16 @@
         vibrator::HalController controller;
         controller.init();
         state.ResumeTiming();
-        controller.getCapabilities();
+        checkHalResult(controller.getCapabilities(), state);
     }
 });
 
 BENCHMARK_WRAPPER(VibratorBench, getCapabilitiesCached, {
     // First call to cache values.
-    mController.getCapabilities();
+    checkHalResult(mController.getCapabilities(), state);
 
     for (auto _ : state) {
-        mController.getCapabilities();
+        checkHalResult(mController.getCapabilities(), state);
     }
 });
 
@@ -232,16 +260,16 @@
         vibrator::HalController controller;
         controller.init();
         state.ResumeTiming();
-        controller.getSupportedEffects();
+        checkHalResult(controller.getSupportedEffects(), state);
     }
 });
 
 BENCHMARK_WRAPPER(VibratorBench, getSupportedEffectsCached, {
     // First call to cache values.
-    mController.getSupportedEffects();
+    checkHalResult(mController.getSupportedEffects(), state);
 
     for (auto _ : state) {
-        mController.getSupportedEffects();
+        checkHalResult(mController.getSupportedEffects(), state);
     }
 });
 
@@ -251,16 +279,16 @@
         vibrator::HalController controller;
         controller.init();
         state.ResumeTiming();
-        controller.getSupportedPrimitives();
+        checkHalResult(controller.getSupportedPrimitives(), state);
     }
 });
 
 BENCHMARK_WRAPPER(VibratorBench, getSupportedPrimitivesCached, {
     // First call to cache values.
-    mController.getSupportedPrimitives();
+    checkHalResult(mController.getSupportedPrimitives(), state);
 
     for (auto _ : state) {
-        mController.getSupportedPrimitives();
+        checkHalResult(mController.getSupportedPrimitives(), state);
     }
 });
 
@@ -274,6 +302,10 @@
         }
 
         std::vector<hardware::vibrator::Effect> supported = effectsResult.value();
+        if (supported.empty()) {
+            return;
+        }
+
         b->ArgNames({"Effect", "Strength"});
         for (const auto& effect : enum_range<hardware::vibrator::Effect>()) {
             if (std::find(supported.begin(), supported.end(), effect) == supported.end()) {
@@ -296,9 +328,9 @@
 };
 
 BENCHMARK_WRAPPER(VibratorEffectsBench, alwaysOnEnable, {
-    auto capabilitiesResult = mController.getCapabilities();
+    auto result = mController.getCapabilities();
 
-    if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::ALWAYS_ON_CONTROL)) {
+    if (!hasCapabilities(result, vibrator::Capabilities::ALWAYS_ON_CONTROL, state)) {
         return;
     }
 
@@ -308,16 +340,18 @@
 
     for (auto _ : state) {
         state.ResumeTiming();
-        mController.alwaysOnEnable(id, effect, strength);
+        auto ret = mController.alwaysOnEnable(id, effect, strength);
         state.PauseTiming();
-        mController.alwaysOnDisable(id);
+        if (checkHalResult(ret, state)) {
+            checkHalResult(mController.alwaysOnDisable(id), state);
+        }
     }
 });
 
 BENCHMARK_WRAPPER(VibratorEffectsBench, alwaysOnDisable, {
-    auto capabilitiesResult = mController.getCapabilities();
+    auto result = mController.getCapabilities();
 
-    if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::ALWAYS_ON_CONTROL)) {
+    if (!hasCapabilities(result, vibrator::Capabilities::ALWAYS_ON_CONTROL, state)) {
         return;
     }
 
@@ -327,9 +361,11 @@
 
     for (auto _ : state) {
         state.PauseTiming();
-        mController.alwaysOnEnable(id, effect, strength);
+        if (!checkHalResult(mController.alwaysOnEnable(id, effect, strength), state)) {
+            continue;
+        }
         state.ResumeTiming();
-        mController.alwaysOnDisable(id);
+        checkHalResult(mController.alwaysOnDisable(id), state);
     }
 });
 
@@ -340,9 +376,11 @@
 
     for (auto _ : state) {
         state.ResumeTiming();
-        mController.performEffect(effect, strength, callback);
+        auto ret = mController.performEffect(effect, strength, callback);
         state.PauseTiming();
-        mController.off();
+        if (checkHalResult(ret, state)) {
+            checkHalResult(mController.off(), state);
+        }
     }
 });
 
@@ -356,11 +394,18 @@
         }
 
         std::vector<hardware::vibrator::CompositePrimitive> supported = primitivesResult.value();
+        if (supported.empty()) {
+            return;
+        }
+
         b->ArgNames({"Primitive"});
         for (const auto& primitive : enum_range<hardware::vibrator::CompositePrimitive>()) {
             if (std::find(supported.begin(), supported.end(), primitive) == supported.end()) {
                 continue;
             }
+            if (primitive == hardware::vibrator::CompositePrimitive::NOOP) {
+                continue;
+            }
             b->Args({static_cast<long>(primitive)});
         }
     }
@@ -372,16 +417,16 @@
 };
 
 BENCHMARK_WRAPPER(VibratorPrimitivesBench, performComposedEffect, {
-    auto capabilitiesResult = mController.getCapabilities();
+    auto result = mController.getCapabilities();
 
-    if (!hasCapabilities(capabilitiesResult, vibrator::Capabilities::COMPOSE_EFFECTS)) {
+    if (!hasCapabilities(result, vibrator::Capabilities::COMPOSE_EFFECTS, state)) {
         return;
     }
 
     hardware::vibrator::CompositeEffect effect;
     effect.primitive = getPrimitive(state);
     effect.scale = 1.0f;
-    effect.delayMs = 0;
+    effect.delayMs = static_cast<int32_t>(0);
 
     std::vector<hardware::vibrator::CompositeEffect> effects;
     effects.push_back(effect);
@@ -389,9 +434,11 @@
 
     for (auto _ : state) {
         state.ResumeTiming();
-        mController.performComposedEffect(effects, callback);
+        auto ret = mController.performComposedEffect(effects, callback);
         state.PauseTiming();
-        mController.off();
+        if (checkHalResult(ret, state)) {
+            checkHalResult(mController.off(), state);
+        }
     }
 });
 
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index f69de1f..1d29bab 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -21,7 +21,7 @@
 }
 
 llndk_library {
-    name: "libvulkan",
+    name: "libvulkan.llndk",
     symbol_file: "libvulkan.map.txt",
     export_llndk_headers: [
         "vulkan_headers_llndk",
@@ -30,6 +30,7 @@
 
 cc_library_shared {
     name: "libvulkan",
+    llndk_stubs: "libvulkan.llndk",
     clang: true,
     sanitize: {
         misc_undefined: ["integer"],
@@ -89,7 +90,6 @@
         "libhardware",
         "libsync",
         "libbase",
-        "libdl_android",
         "libhidlbase",
         "liblog",
         "libui",
@@ -100,6 +100,7 @@
         "libnativebridge_lazy",
         "libnativeloader_lazy",
         "libnativewindow",
+        "libvndksupport",
         "android.hardware.graphics.common@1.0",
         "libSurfaceFlingerProp",
     ],
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index d9a9427..26052fb 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -226,6 +226,7 @@
     INIT_PROC(true, dev, CreateQueryPool);
     INIT_PROC(true, dev, DestroyQueryPool);
     INIT_PROC(true, dev, GetQueryPoolResults);
+    INIT_PROC(false, dev, ResetQueryPool);
     INIT_PROC(true, dev, CreateBuffer);
     INIT_PROC(true, dev, DestroyBuffer);
     INIT_PROC(true, dev, CreateBufferView);
@@ -337,8 +338,20 @@
     INIT_PROC(false, dev, DestroySamplerYcbcrConversion);
     INIT_PROC(false, dev, GetDeviceQueue2);
     INIT_PROC(false, dev, GetDescriptorSetLayoutSupport);
+    INIT_PROC(false, dev, CreateRenderPass2);
+    INIT_PROC(false, dev, CmdBeginRenderPass2);
+    INIT_PROC(false, dev, CmdNextSubpass2);
+    INIT_PROC(false, dev, CmdEndRenderPass2);
+    INIT_PROC(false, dev, GetSemaphoreCounterValue);
+    INIT_PROC(false, dev, WaitSemaphores);
+    INIT_PROC(false, dev, SignalSemaphore);
     INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, true, dev, GetAndroidHardwareBufferPropertiesANDROID);
     INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, true, dev, GetMemoryAndroidHardwareBufferANDROID);
+    INIT_PROC(false, dev, CmdDrawIndirectCount);
+    INIT_PROC(false, dev, CmdDrawIndexedIndirectCount);
+    INIT_PROC(false, dev, GetBufferOpaqueCaptureAddress);
+    INIT_PROC(false, dev, GetBufferDeviceAddress);
+    INIT_PROC(false, dev, GetDeviceMemoryOpaqueCaptureAddress);
     // clang-format on
 
     return success;
@@ -391,6 +404,7 @@
 VKAPI_ATTR VkResult CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool);
 VKAPI_ATTR void DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator);
 VKAPI_ATTR VkResult GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags);
+VKAPI_ATTR void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
 VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer);
 VKAPI_ATTR void DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator);
 VKAPI_ATTR VkResult CreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView);
@@ -520,8 +534,20 @@
 VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
 VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
 VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
+VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
+VKAPI_ATTR void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo);
+VKAPI_ATTR void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue);
+VKAPI_ATTR VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout);
+VKAPI_ATTR VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo);
 VKAPI_ATTR VkResult GetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties);
 VKAPI_ATTR VkResult GetMemoryAndroidHardwareBufferANDROID(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer);
+VKAPI_ATTR void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo);
 
 VKAPI_ATTR VkResult EnumeratePhysicalDevices(VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices) {
     return GetData(instance).dispatch.EnumeratePhysicalDevices(instance, pPhysicalDeviceCount, pPhysicalDevices);
@@ -551,6 +577,7 @@
         "vkEnumerateInstanceVersion",
         "vkEnumeratePhysicalDeviceGroups",
         "vkEnumeratePhysicalDeviceGroupsKHR",
+        "vkEnumeratePhysicalDeviceQueueFamilyPerformanceQueryCountersKHR",
         "vkEnumeratePhysicalDevices",
         "vkGetDisplayModeProperties2KHR",
         "vkGetDisplayPlaneCapabilities2KHR",
@@ -571,7 +598,7 @@
         "vkGetPhysicalDeviceFormatProperties",
         "vkGetPhysicalDeviceFormatProperties2",
         "vkGetPhysicalDeviceFormatProperties2KHR",
-        "vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX",
+        "vkGetPhysicalDeviceFragmentShadingRatesKHR",
         "vkGetPhysicalDeviceImageFormatProperties",
         "vkGetPhysicalDeviceImageFormatProperties2",
         "vkGetPhysicalDeviceImageFormatProperties2KHR",
@@ -583,6 +610,7 @@
         "vkGetPhysicalDeviceProperties",
         "vkGetPhysicalDeviceProperties2",
         "vkGetPhysicalDeviceProperties2KHR",
+        "vkGetPhysicalDeviceQueueFamilyPerformanceQueryPassesKHR",
         "vkGetPhysicalDeviceQueueFamilyProperties",
         "vkGetPhysicalDeviceQueueFamilyProperties2",
         "vkGetPhysicalDeviceQueueFamilyProperties2KHR",
@@ -595,6 +623,7 @@
         "vkGetPhysicalDeviceSurfaceFormatsKHR",
         "vkGetPhysicalDeviceSurfacePresentModesKHR",
         "vkGetPhysicalDeviceSurfaceSupportKHR",
+        "vkGetPhysicalDeviceToolPropertiesEXT",
         "vkSubmitDebugUtilsMessageEXT",
     };
     // clang-format on
@@ -646,6 +675,7 @@
         { "vkBindImageMemory2", reinterpret_cast<PFN_vkVoidFunction>(BindImageMemory2) },
         { "vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginQuery) },
         { "vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass) },
+        { "vkCmdBeginRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(CmdBeginRenderPass2) },
         { "vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(CmdBindDescriptorSets) },
         { "vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdBindIndexBuffer) },
         { "vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(CmdBindPipeline) },
@@ -665,12 +695,16 @@
         { "vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(CmdDraw) },
         { "vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexed) },
         { "vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirect) },
+        { "vkCmdDrawIndexedIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndexedIndirectCount) },
         { "vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirect) },
+        { "vkCmdDrawIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(CmdDrawIndirectCount) },
         { "vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(CmdEndQuery) },
         { "vkCmdEndRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CmdEndRenderPass) },
+        { "vkCmdEndRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(CmdEndRenderPass2) },
         { "vkCmdExecuteCommands", reinterpret_cast<PFN_vkVoidFunction>(CmdExecuteCommands) },
         { "vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(CmdFillBuffer) },
         { "vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass) },
+        { "vkCmdNextSubpass2", reinterpret_cast<PFN_vkVoidFunction>(CmdNextSubpass2) },
         { "vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(CmdPipelineBarrier) },
         { "vkCmdPushConstants", reinterpret_cast<PFN_vkVoidFunction>(CmdPushConstants) },
         { "vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(CmdResetEvent) },
@@ -709,6 +743,7 @@
         { "vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(CreatePipelineLayout) },
         { "vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(CreateQueryPool) },
         { "vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass) },
+        { "vkCreateRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(CreateRenderPass2) },
         { "vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(CreateSampler) },
         { "vkCreateSamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(CreateSamplerYcbcrConversion) },
         { "vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(CreateSemaphore) },
@@ -749,13 +784,16 @@
         { "vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(FreeDescriptorSets) },
         { "vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(FreeMemory) },
         { "vkGetAndroidHardwareBufferPropertiesANDROID", reinterpret_cast<PFN_vkVoidFunction>(GetAndroidHardwareBufferPropertiesANDROID) },
+        { "vkGetBufferDeviceAddress", reinterpret_cast<PFN_vkVoidFunction>(GetBufferDeviceAddress) },
         { "vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements) },
         { "vkGetBufferMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(GetBufferMemoryRequirements2) },
+        { "vkGetBufferOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(GetBufferOpaqueCaptureAddress) },
         { "vkGetDescriptorSetLayoutSupport", reinterpret_cast<PFN_vkVoidFunction>(GetDescriptorSetLayoutSupport) },
         { "vkGetDeviceGroupPeerMemoryFeatures", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPeerMemoryFeatures) },
         { "vkGetDeviceGroupPresentCapabilitiesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupPresentCapabilitiesKHR) },
         { "vkGetDeviceGroupSurfacePresentModesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceGroupSurfacePresentModesKHR) },
         { "vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceMemoryCommitment) },
+        { "vkGetDeviceMemoryOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceMemoryOpaqueCaptureAddress) },
         { "vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceProcAddr) },
         { "vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue) },
         { "vkGetDeviceQueue2", reinterpret_cast<PFN_vkVoidFunction>(GetDeviceQueue2) },
@@ -771,6 +809,7 @@
         { "vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(GetPipelineCacheData) },
         { "vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(GetQueryPoolResults) },
         { "vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(GetRenderAreaGranularity) },
+        { "vkGetSemaphoreCounterValue", reinterpret_cast<PFN_vkVoidFunction>(GetSemaphoreCounterValue) },
         { "vkGetSwapchainImagesKHR", reinterpret_cast<PFN_vkVoidFunction>(GetSwapchainImagesKHR) },
         { "vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(InvalidateMappedMemoryRanges) },
         { "vkMapMemory", reinterpret_cast<PFN_vkVoidFunction>(MapMemory) },
@@ -784,12 +823,15 @@
         { "vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(ResetDescriptorPool) },
         { "vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(ResetEvent) },
         { "vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(ResetFences) },
+        { "vkResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(ResetQueryPool) },
         { "vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(SetEvent) },
+        { "vkSignalSemaphore", reinterpret_cast<PFN_vkVoidFunction>(SignalSemaphore) },
         { "vkTrimCommandPool", reinterpret_cast<PFN_vkVoidFunction>(TrimCommandPool) },
         { "vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(UnmapMemory) },
         { "vkUpdateDescriptorSetWithTemplate", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSetWithTemplate) },
         { "vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(UpdateDescriptorSets) },
         { "vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(WaitForFences) },
+        { "vkWaitSemaphores", reinterpret_cast<PFN_vkVoidFunction>(WaitSemaphores) },
     };
     // clang-format on
     constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
@@ -965,6 +1007,10 @@
     return GetData(device).dispatch.GetQueryPoolResults(device, queryPool, firstQuery, queryCount, dataSize, pData, stride, flags);
 }
 
+VKAPI_ATTR void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
+    GetData(device).dispatch.ResetQueryPool(device, queryPool, firstQuery, queryCount);
+}
+
 VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer) {
     return GetData(device).dispatch.CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
 }
@@ -1481,6 +1527,34 @@
     GetData(device).dispatch.GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
 }
 
+VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass) {
+    return GetData(device).dispatch.CreateRenderPass2(device, pCreateInfo, pAllocator, pRenderPass);
+}
+
+VKAPI_ATTR void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo) {
+    GetData(commandBuffer).dispatch.CmdBeginRenderPass2(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
+}
+
+VKAPI_ATTR void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo) {
+    GetData(commandBuffer).dispatch.CmdNextSubpass2(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
+}
+
+VKAPI_ATTR void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo) {
+    GetData(commandBuffer).dispatch.CmdEndRenderPass2(commandBuffer, pSubpassEndInfo);
+}
+
+VKAPI_ATTR VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue) {
+    return GetData(device).dispatch.GetSemaphoreCounterValue(device, semaphore, pValue);
+}
+
+VKAPI_ATTR VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout) {
+    return GetData(device).dispatch.WaitSemaphores(device, pWaitInfo, timeout);
+}
+
+VKAPI_ATTR VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo) {
+    return GetData(device).dispatch.SignalSemaphore(device, pSignalInfo);
+}
+
 VKAPI_ATTR VkResult GetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
     return GetData(device).dispatch.GetAndroidHardwareBufferPropertiesANDROID(device, buffer, pProperties);
 }
@@ -1489,6 +1563,26 @@
     return GetData(device).dispatch.GetMemoryAndroidHardwareBufferANDROID(device, pInfo, pBuffer);
 }
 
+VKAPI_ATTR void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+    GetData(commandBuffer).dispatch.CmdDrawIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+VKAPI_ATTR void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+    GetData(commandBuffer).dispatch.CmdDrawIndexedIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+VKAPI_ATTR uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+    return GetData(device).dispatch.GetBufferOpaqueCaptureAddress(device, pInfo);
+}
+
+VKAPI_ATTR VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+    return GetData(device).dispatch.GetBufferDeviceAddress(device, pInfo);
+}
+
+VKAPI_ATTR uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo) {
+    return GetData(device).dispatch.GetDeviceMemoryOpaqueCaptureAddress(device, pInfo);
+}
+
 
 }  // anonymous namespace
 
@@ -1755,6 +1849,11 @@
 }
 
 __attribute__((visibility("default")))
+VKAPI_ATTR void vkResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
+    vulkan::api::ResetQueryPool(device, queryPool, firstQuery, queryCount);
+}
+
+__attribute__((visibility("default")))
 VKAPI_ATTR VkResult vkCreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer) {
     return vulkan::api::CreateBuffer(device, pCreateInfo, pAllocator, pBuffer);
 }
@@ -2400,6 +2499,41 @@
 }
 
 __attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkCreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass) {
+    return vulkan::api::CreateRenderPass2(device, pCreateInfo, pAllocator, pRenderPass);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo) {
+    vulkan::api::CmdBeginRenderPass2(commandBuffer, pRenderPassBegin, pSubpassBeginInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo) {
+    vulkan::api::CmdNextSubpass2(commandBuffer, pSubpassBeginInfo, pSubpassEndInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo) {
+    vulkan::api::CmdEndRenderPass2(commandBuffer, pSubpassEndInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue) {
+    return vulkan::api::GetSemaphoreCounterValue(device, semaphore, pValue);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkWaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout) {
+    return vulkan::api::WaitSemaphores(device, pWaitInfo, timeout);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkSignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo) {
+    return vulkan::api::SignalSemaphore(device, pSignalInfo);
+}
+
+__attribute__((visibility("default")))
 VKAPI_ATTR VkResult vkGetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
     return vulkan::api::GetAndroidHardwareBufferPropertiesANDROID(device, buffer, pProperties);
 }
@@ -2409,4 +2543,29 @@
     return vulkan::api::GetMemoryAndroidHardwareBufferANDROID(device, pInfo, pBuffer);
 }
 
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+    vulkan::api::CmdDrawIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+    vulkan::api::CmdDrawIndexedIndirectCount(commandBuffer, buffer, offset, countBuffer, countBufferOffset, maxDrawCount, stride);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR uint64_t vkGetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+    return vulkan::api::GetBufferOpaqueCaptureAddress(device, pInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkDeviceAddress vkGetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+    return vulkan::api::GetBufferDeviceAddress(device, pInfo);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR uint64_t vkGetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo) {
+    return vulkan::api::GetDeviceMemoryOpaqueCaptureAddress(device, pInfo);
+}
+
 // clang-format on
diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h
index 2195845..ad5cc34 100644
--- a/vulkan/libvulkan/api_gen.h
+++ b/vulkan/libvulkan/api_gen.h
@@ -99,6 +99,7 @@
     PFN_vkCreateQueryPool CreateQueryPool;
     PFN_vkDestroyQueryPool DestroyQueryPool;
     PFN_vkGetQueryPoolResults GetQueryPoolResults;
+    PFN_vkResetQueryPool ResetQueryPool;
     PFN_vkCreateBuffer CreateBuffer;
     PFN_vkDestroyBuffer DestroyBuffer;
     PFN_vkCreateBufferView CreateBufferView;
@@ -210,8 +211,20 @@
     PFN_vkDestroySamplerYcbcrConversion DestroySamplerYcbcrConversion;
     PFN_vkGetDeviceQueue2 GetDeviceQueue2;
     PFN_vkGetDescriptorSetLayoutSupport GetDescriptorSetLayoutSupport;
+    PFN_vkCreateRenderPass2 CreateRenderPass2;
+    PFN_vkCmdBeginRenderPass2 CmdBeginRenderPass2;
+    PFN_vkCmdNextSubpass2 CmdNextSubpass2;
+    PFN_vkCmdEndRenderPass2 CmdEndRenderPass2;
+    PFN_vkGetSemaphoreCounterValue GetSemaphoreCounterValue;
+    PFN_vkWaitSemaphores WaitSemaphores;
+    PFN_vkSignalSemaphore SignalSemaphore;
     PFN_vkGetAndroidHardwareBufferPropertiesANDROID GetAndroidHardwareBufferPropertiesANDROID;
     PFN_vkGetMemoryAndroidHardwareBufferANDROID GetMemoryAndroidHardwareBufferANDROID;
+    PFN_vkCmdDrawIndirectCount CmdDrawIndirectCount;
+    PFN_vkCmdDrawIndexedIndirectCount CmdDrawIndexedIndirectCount;
+    PFN_vkGetBufferOpaqueCaptureAddress GetBufferOpaqueCaptureAddress;
+    PFN_vkGetBufferDeviceAddress GetBufferDeviceAddress;
+    PFN_vkGetDeviceMemoryOpaqueCaptureAddress GetDeviceMemoryOpaqueCaptureAddress;
     // clang-format on
 };
 
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 4068a16..6f09a8c 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -28,20 +28,17 @@
 #include <android/dlext.h>
 #include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
 #include <configstore/Utils.h>
-#include <cutils/properties.h>
 #include <graphicsenv/GraphicsEnv.h>
 #include <log/log.h>
-#include <nativeloader/dlext_namespaces.h>
 #include <sys/prctl.h>
 #include <utils/Timers.h>
 #include <utils/Trace.h>
+#include <vndksupport/linker.h>
 
 #include <algorithm>
 #include <array>
 #include <climits>
 #include <new>
-#include <string_view>
-#include <sstream>
 #include <vector>
 
 #include "stubhal.h"
@@ -157,19 +154,11 @@
 
 Hal Hal::hal_;
 
-void* LoadLibrary(const android_dlextinfo& dlextinfo,
-                  const std::string_view subname) {
-    ATRACE_CALL();
-
-    std::stringstream ss;
-    ss << "vulkan." << subname << ".so";
-    return android_dlopen_ext(ss.str().c_str(), RTLD_LOCAL | RTLD_NOW, &dlextinfo);
-}
-
 const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{
     "ro.hardware.vulkan",
     "ro.board.platform",
 }};
+constexpr int LIB_DL_FLAGS = RTLD_LOCAL | RTLD_NOW;
 
 // LoadDriver returns:
 // * 0 when succeed, or
@@ -180,20 +169,26 @@
                const hwvulkan_module_t** module) {
     ATRACE_CALL();
 
-    const android_dlextinfo dlextinfo = {
-        .flags = ANDROID_DLEXT_USE_NAMESPACE,
-        .library_namespace = library_namespace,
-    };
     void* so = nullptr;
-    char prop[PROPERTY_VALUE_MAX];
     for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
-        int prop_len = property_get(key, prop, nullptr);
-        if (prop_len > 0 && prop_len <= UINT_MAX) {
-            std::string_view lib_name(prop, static_cast<unsigned int>(prop_len));
-            so = LoadLibrary(dlextinfo, lib_name);
-            if (so)
-                break;
+        std::string lib_name = android::base::GetProperty(key, "");
+        if (lib_name.empty())
+            continue;
+
+        lib_name = "vulkan." + lib_name + ".so";
+        if (library_namespace) {
+            // load updated driver
+            const android_dlextinfo dlextinfo = {
+                .flags = ANDROID_DLEXT_USE_NAMESPACE,
+                .library_namespace = library_namespace,
+            };
+            so = android_dlopen_ext(lib_name.c_str(), LIB_DL_FLAGS, &dlextinfo);
+        } else {
+            // load built-in driver
+            so = android_load_sphal_library(lib_name.c_str(), LIB_DL_FLAGS);
         }
+        if (so)
+            break;
     }
     if (!so)
         return -ENOENT;
@@ -217,12 +212,9 @@
 int LoadBuiltinDriver(const hwvulkan_module_t** module) {
     ATRACE_CALL();
 
-    auto ns = android_get_exported_namespace("sphal");
-    if (!ns)
-        return -ENOENT;
     android::GraphicsEnv::getInstance().setDriverToLoad(
         android::GpuStatsInfo::Driver::VULKAN);
-    return LoadDriver(ns, module);
+    return LoadDriver(nullptr, module);
 }
 
 int LoadUpdatedDriver(const hwvulkan_module_t** module) {
@@ -323,7 +315,7 @@
                 "hw_device_t::close() failed.");
 
     // Close the opened shared library in the hw_module_t
-    dlclose(hal_.dev_->common.module->dso);
+    android_unload_sphal_library(hal_.dev_->common.module->dso);
 
     hal_.dev_ = nullptr;
     hal_.debug_report_index_ = -1;
@@ -658,6 +650,7 @@
             case ProcHook::GOOGLE_display_timing:
             case ProcHook::EXTENSION_CORE_1_0:
             case ProcHook::EXTENSION_CORE_1_1:
+            case ProcHook::EXTENSION_CORE_1_2:
             case ProcHook::EXTENSION_COUNT:
                 // Device and meta extensions. If we ever get here it's a bug in
                 // our code. But enumerating them lets us avoid having a default
@@ -711,6 +704,7 @@
             case ProcHook::ANDROID_native_buffer:
             case ProcHook::EXTENSION_CORE_1_0:
             case ProcHook::EXTENSION_CORE_1_1:
+            case ProcHook::EXTENSION_CORE_1_2:
             case ProcHook::EXTENSION_COUNT:
                 // Instance and meta extensions. If we ever get here it's a bug
                 // in our code. But enumerating them lets us avoid having a
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 1aba674..047e774 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -57,6 +57,7 @@
 
         EXTENSION_CORE_1_0,
         EXTENSION_CORE_1_1,
+        EXTENSION_CORE_1_2,
         EXTENSION_COUNT,
         EXTENSION_UNKNOWN,
     };
diff --git a/vulkan/libvulkan/libvulkan.map.txt b/vulkan/libvulkan/libvulkan.map.txt
index 0be66c9..df97d7f 100644
--- a/vulkan/libvulkan/libvulkan.map.txt
+++ b/vulkan/libvulkan/libvulkan.map.txt
@@ -12,6 +12,7 @@
     vkBindImageMemory2; # introduced=28
     vkCmdBeginQuery;
     vkCmdBeginRenderPass;
+    vkCmdBeginRenderPass2; # introduced=31
     vkCmdBindDescriptorSets;
     vkCmdBindIndexBuffer;
     vkCmdBindPipeline;
@@ -31,12 +32,16 @@
     vkCmdDraw;
     vkCmdDrawIndexed;
     vkCmdDrawIndexedIndirect;
+    vkCmdDrawIndexedIndirectCount; # introduced=31
     vkCmdDrawIndirect;
+    vkCmdDrawIndirectCount; # introduced=31
     vkCmdEndQuery;
     vkCmdEndRenderPass;
+    vkCmdEndRenderPass2; # introduced=31
     vkCmdExecuteCommands;
     vkCmdFillBuffer;
     vkCmdNextSubpass;
+    vkCmdNextSubpass2; # introduced=31
     vkCmdPipelineBarrier;
     vkCmdPushConstants;
     vkCmdResetEvent;
@@ -76,6 +81,7 @@
     vkCreatePipelineLayout;
     vkCreateQueryPool;
     vkCreateRenderPass;
+    vkCreateRenderPass2; # introduced=31
     vkCreateSampler;
     vkCreateSamplerYcbcrConversion; # introduced=28
     vkCreateSemaphore;
@@ -119,13 +125,16 @@
     vkFreeDescriptorSets;
     vkFreeMemory;
     vkGetAndroidHardwareBufferPropertiesANDROID; # introduced=28
+    vkGetBufferDeviceAddress; # introduced=31
     vkGetBufferMemoryRequirements;
     vkGetBufferMemoryRequirements2; # introduced=28
+    vkGetBufferOpaqueCaptureAddress; # introduced=31
     vkGetDescriptorSetLayoutSupport; # introduced=28
     vkGetDeviceGroupPeerMemoryFeatures; # introduced=28
     vkGetDeviceGroupPresentCapabilitiesKHR; # introduced=28
     vkGetDeviceGroupSurfacePresentModesKHR; # introduced=28
     vkGetDeviceMemoryCommitment;
+    vkGetDeviceMemoryOpaqueCaptureAddress; # introduced=31
     vkGetDeviceProcAddr;
     vkGetDeviceQueue;
     vkGetDeviceQueue2; # introduced=28
@@ -163,6 +172,7 @@
     vkGetPipelineCacheData;
     vkGetQueryPoolResults;
     vkGetRenderAreaGranularity;
+    vkGetSemaphoreCounterValue; # introduced=31
     vkGetSwapchainImagesKHR;
     vkInvalidateMappedMemoryRanges;
     vkMapMemory;
@@ -176,12 +186,15 @@
     vkResetDescriptorPool;
     vkResetEvent;
     vkResetFences;
+    vkResetQueryPool; # introduced=31
     vkSetEvent;
+    vkSignalSemaphore; # introduced=31
     vkTrimCommandPool; # introduced=28
     vkUnmapMemory;
     vkUpdateDescriptorSets;
     vkUpdateDescriptorSetWithTemplate; # introduced=28
     vkWaitForFences;
+    vkWaitSemaphores; # introduced=31
   local:
     *;
 };
diff --git a/vulkan/nulldrv/null_driver.cpp b/vulkan/nulldrv/null_driver.cpp
index 4647a80..b94233b 100644
--- a/vulkan/nulldrv/null_driver.cpp
+++ b/vulkan/nulldrv/null_driver.cpp
@@ -1123,6 +1123,14 @@
     return VK_SUCCESS;
 }
 
+VkResult CreateRenderPass2(VkDevice device,
+                           const VkRenderPassCreateInfo2*,
+                           const VkAllocationCallbacks* /*allocator*/,
+                           VkRenderPass* pRenderPass) {
+    *pRenderPass = AllocHandle<VkRenderPass>(device, HandleType::kRenderPass);
+    return VK_SUCCESS;
+}
+
 // -----------------------------------------------------------------------------
 // No-op entrypoints
 
@@ -1568,6 +1576,55 @@
 void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) {
 }
 
+void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+}
+
+void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo) {
+}
+
+void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo) {
+}
+
+void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo) {
+}
+
+VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
+VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
+VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+    return VK_SUCCESS;
+}
+
+void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+}
+
+void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride) {
+}
+
+uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+    return 0;
+}
+
+VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+    return (VkDeviceAddress)0;
+}
+
+uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo) {
+    ALOGV("TODO: vk%s", __FUNCTION__);
+    return 0;
+}
+
 #pragma clang diagnostic pop
 // clang-format on
 
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index b8d7d2b..edda12c 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -67,6 +67,7 @@
     {"vkBindImageMemory2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkBindImageMemory2>(BindImageMemory2))},
     {"vkCmdBeginQuery", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginQuery>(CmdBeginQuery))},
     {"vkCmdBeginRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginRenderPass>(CmdBeginRenderPass))},
+    {"vkCmdBeginRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBeginRenderPass2>(CmdBeginRenderPass2))},
     {"vkCmdBindDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindDescriptorSets>(CmdBindDescriptorSets))},
     {"vkCmdBindIndexBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindIndexBuffer>(CmdBindIndexBuffer))},
     {"vkCmdBindPipeline", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdBindPipeline>(CmdBindPipeline))},
@@ -86,12 +87,16 @@
     {"vkCmdDraw", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDraw>(CmdDraw))},
     {"vkCmdDrawIndexed", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexed>(CmdDrawIndexed))},
     {"vkCmdDrawIndexedIndirect", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexedIndirect>(CmdDrawIndexedIndirect))},
+    {"vkCmdDrawIndexedIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndexedIndirectCount>(CmdDrawIndexedIndirectCount))},
     {"vkCmdDrawIndirect", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndirect>(CmdDrawIndirect))},
+    {"vkCmdDrawIndirectCount", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdDrawIndirectCount>(CmdDrawIndirectCount))},
     {"vkCmdEndQuery", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdEndQuery>(CmdEndQuery))},
     {"vkCmdEndRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdEndRenderPass>(CmdEndRenderPass))},
+    {"vkCmdEndRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdEndRenderPass2>(CmdEndRenderPass2))},
     {"vkCmdExecuteCommands", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdExecuteCommands>(CmdExecuteCommands))},
     {"vkCmdFillBuffer", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdFillBuffer>(CmdFillBuffer))},
     {"vkCmdNextSubpass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdNextSubpass>(CmdNextSubpass))},
+    {"vkCmdNextSubpass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdNextSubpass2>(CmdNextSubpass2))},
     {"vkCmdPipelineBarrier", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdPipelineBarrier>(CmdPipelineBarrier))},
     {"vkCmdPushConstants", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdPushConstants>(CmdPushConstants))},
     {"vkCmdResetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCmdResetEvent>(CmdResetEvent))},
@@ -131,6 +136,7 @@
     {"vkCreatePipelineLayout", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreatePipelineLayout>(CreatePipelineLayout))},
     {"vkCreateQueryPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateQueryPool>(CreateQueryPool))},
     {"vkCreateRenderPass", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateRenderPass>(CreateRenderPass))},
+    {"vkCreateRenderPass2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateRenderPass2>(CreateRenderPass2))},
     {"vkCreateSampler", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSampler>(CreateSampler))},
     {"vkCreateSamplerYcbcrConversion", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSamplerYcbcrConversion>(CreateSamplerYcbcrConversion))},
     {"vkCreateSemaphore", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkCreateSemaphore>(CreateSemaphore))},
@@ -172,11 +178,14 @@
     {"vkFreeCommandBuffers", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeCommandBuffers>(FreeCommandBuffers))},
     {"vkFreeDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeDescriptorSets>(FreeDescriptorSets))},
     {"vkFreeMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkFreeMemory>(FreeMemory))},
+    {"vkGetBufferDeviceAddress", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferDeviceAddress>(GetBufferDeviceAddress))},
     {"vkGetBufferMemoryRequirements", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferMemoryRequirements>(GetBufferMemoryRequirements))},
     {"vkGetBufferMemoryRequirements2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferMemoryRequirements2>(GetBufferMemoryRequirements2))},
+    {"vkGetBufferOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetBufferOpaqueCaptureAddress>(GetBufferOpaqueCaptureAddress))},
     {"vkGetDescriptorSetLayoutSupport", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDescriptorSetLayoutSupport>(GetDescriptorSetLayoutSupport))},
     {"vkGetDeviceGroupPeerMemoryFeatures", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceGroupPeerMemoryFeatures>(GetDeviceGroupPeerMemoryFeatures))},
     {"vkGetDeviceMemoryCommitment", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceMemoryCommitment>(GetDeviceMemoryCommitment))},
+    {"vkGetDeviceMemoryOpaqueCaptureAddress", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceMemoryOpaqueCaptureAddress>(GetDeviceMemoryOpaqueCaptureAddress))},
     {"vkGetDeviceProcAddr", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceProcAddr>(GetDeviceProcAddr))},
     {"vkGetDeviceQueue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue>(GetDeviceQueue))},
     {"vkGetDeviceQueue2", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetDeviceQueue2>(GetDeviceQueue2))},
@@ -215,6 +224,7 @@
     {"vkGetPipelineCacheData", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetPipelineCacheData>(GetPipelineCacheData))},
     {"vkGetQueryPoolResults", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetQueryPoolResults>(GetQueryPoolResults))},
     {"vkGetRenderAreaGranularity", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetRenderAreaGranularity>(GetRenderAreaGranularity))},
+    {"vkGetSemaphoreCounterValue", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSemaphoreCounterValue>(GetSemaphoreCounterValue))},
     {"vkGetSwapchainGrallocUsage2ANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsage2ANDROID>(GetSwapchainGrallocUsage2ANDROID))},
     {"vkGetSwapchainGrallocUsageANDROID", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkGetSwapchainGrallocUsageANDROID>(GetSwapchainGrallocUsageANDROID))},
     {"vkInvalidateMappedMemoryRanges", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkInvalidateMappedMemoryRanges>(InvalidateMappedMemoryRanges))},
@@ -229,12 +239,15 @@
     {"vkResetDescriptorPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetDescriptorPool>(ResetDescriptorPool))},
     {"vkResetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetEvent>(ResetEvent))},
     {"vkResetFences", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetFences>(ResetFences))},
+    {"vkResetQueryPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkResetQueryPool>(ResetQueryPool))},
     {"vkSetEvent", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkSetEvent>(SetEvent))},
+    {"vkSignalSemaphore", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkSignalSemaphore>(SignalSemaphore))},
     {"vkTrimCommandPool", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkTrimCommandPool>(TrimCommandPool))},
     {"vkUnmapMemory", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUnmapMemory>(UnmapMemory))},
     {"vkUpdateDescriptorSetWithTemplate", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUpdateDescriptorSetWithTemplate>(UpdateDescriptorSetWithTemplate))},
     {"vkUpdateDescriptorSets", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkUpdateDescriptorSets>(UpdateDescriptorSets))},
     {"vkWaitForFences", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkWaitForFences>(WaitForFences))},
+    {"vkWaitSemaphores", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_vkWaitSemaphores>(WaitSemaphores))},
     // clang-format on
 };
 
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index 0d3f688..e59cae9 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -79,6 +79,7 @@
 VKAPI_ATTR VkResult CreateQueryPool(VkDevice device, const VkQueryPoolCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkQueryPool* pQueryPool);
 VKAPI_ATTR void DestroyQueryPool(VkDevice device, VkQueryPool queryPool, const VkAllocationCallbacks* pAllocator);
 VKAPI_ATTR VkResult GetQueryPoolResults(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, size_t dataSize, void* pData, VkDeviceSize stride, VkQueryResultFlags flags);
+VKAPI_ATTR void ResetQueryPool(VkDevice device, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount);
 VKAPI_ATTR VkResult CreateBuffer(VkDevice device, const VkBufferCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBuffer* pBuffer);
 VKAPI_ATTR void DestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks* pAllocator);
 VKAPI_ATTR VkResult CreateBufferView(VkDevice device, const VkBufferViewCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkBufferView* pView);
@@ -207,6 +208,18 @@
 VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
 VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
 VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
+VKAPI_ATTR VkResult CreateRenderPass2(VkDevice device, const VkRenderPassCreateInfo2* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkRenderPass* pRenderPass);
+VKAPI_ATTR void CmdBeginRenderPass2(VkCommandBuffer commandBuffer, const VkRenderPassBeginInfo* pRenderPassBegin, const VkSubpassBeginInfo* pSubpassBeginInfo);
+VKAPI_ATTR void CmdNextSubpass2(VkCommandBuffer commandBuffer, const VkSubpassBeginInfo* pSubpassBeginInfo, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR void CmdEndRenderPass2(VkCommandBuffer commandBuffer, const VkSubpassEndInfo* pSubpassEndInfo);
+VKAPI_ATTR VkResult GetSemaphoreCounterValue(VkDevice device, VkSemaphore semaphore, uint64_t* pValue);
+VKAPI_ATTR VkResult WaitSemaphores(VkDevice device, const VkSemaphoreWaitInfo* pWaitInfo, uint64_t timeout);
+VKAPI_ATTR VkResult SignalSemaphore(VkDevice device, const VkSemaphoreSignalInfo* pSignalInfo);
+VKAPI_ATTR void CmdDrawIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR void CmdDrawIndexedIndirectCount(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, VkBuffer countBuffer, VkDeviceSize countBufferOffset, uint32_t maxDrawCount, uint32_t stride);
+VKAPI_ATTR uint64_t GetBufferOpaqueCaptureAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR VkDeviceAddress GetBufferDeviceAddress(VkDevice device, const VkBufferDeviceAddressInfo* pInfo);
+VKAPI_ATTR uint64_t GetDeviceMemoryOpaqueCaptureAddress(VkDevice device, const VkDeviceMemoryOpaqueCaptureAddressInfo* pInfo);
 // clang-format on
 
 }  // namespace null_driver
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
index ef021f2..72fd4fb 100644
--- a/vulkan/scripts/generator_common.py
+++ b/vulkan/scripts/generator_common.py
@@ -25,6 +25,7 @@
 _BLOCKED_EXTENSIONS = [
     'VK_EXT_acquire_xlib_display',
     'VK_EXT_direct_mode_display',
+    'VK_EXT_directfb_surface',
     'VK_EXT_display_control',
     'VK_EXT_display_surface_counter',
     'VK_EXT_full_screen_exclusive',
@@ -314,12 +315,12 @@
   else:
     f.write('INIT_PROC(')
 
-  if name in version_dict and version_dict[name] == 'VK_VERSION_1_1':
+  if name in _OPTIONAL_COMMANDS:
     f.write('false, ')
-  elif name in _OPTIONAL_COMMANDS:
-    f.write('false, ')
-  else:
+  elif version_dict[name] == 'VK_VERSION_1_0':
     f.write('true, ')
+  else:
+    f.write('false, ')
 
   if is_instance_dispatched(name):
     f.write('instance, ')
@@ -389,7 +390,7 @@
 
   for exts in root.iter('extensions'):
     for extension in exts:
-      apiversion = ''
+      apiversion = 'VK_VERSION_1_0'
       if extension.tag == 'extension':
         extname = extension.get('name')
         if (extension.get('type') == 'instance' and
@@ -404,8 +405,7 @@
               cmd_name = commands.get('name')
               if cmd_name not in extension_dict:
                 extension_dict[cmd_name] = extname
-                if apiversion:
-                  version_dict[cmd_name] = apiversion
+                version_dict[cmd_name] = apiversion
 
   for feature in root.iter('feature'):
     apiversion = feature.get('name')
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index b0b466c..bfc240e 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -57,9 +57,17 @@
 
 template <typename T> struct EnumTraits;
 template <> struct EnumTraits<VkPhysicalDeviceType> {
-  static uint32_t min() { return VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE; }
-  static uint32_t max() { return VK_PHYSICAL_DEVICE_TYPE_END_RANGE; }
-  static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+  static bool exist(uint32_t e) {
+    switch (e) {
+      case VK_PHYSICAL_DEVICE_TYPE_OTHER:
+      case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
+      case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
+      case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
+      case VK_PHYSICAL_DEVICE_TYPE_CPU:
+        return true;
+    }
+    return false;
+  }
 };
 
 template <> struct EnumTraits<VkFormat> {
@@ -250,6 +258,40 @@
       case VK_FORMAT_ASTC_12x10_SRGB_BLOCK:
       case VK_FORMAT_ASTC_12x12_UNORM_BLOCK:
       case VK_FORMAT_ASTC_12x12_SRGB_BLOCK:
+      case VK_FORMAT_G8B8G8R8_422_UNORM:
+      case VK_FORMAT_B8G8R8G8_422_UNORM:
+      case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
+      case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
+      case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
+      case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
+      case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
+      case VK_FORMAT_R10X6_UNORM_PACK16:
+      case VK_FORMAT_R10X6G10X6_UNORM_2PACK16:
+      case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
+      case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
+      case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
+      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
+      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
+      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
+      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
+      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
+      case VK_FORMAT_R12X4_UNORM_PACK16:
+      case VK_FORMAT_R12X4G12X4_UNORM_2PACK16:
+      case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
+      case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
+      case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
+      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
+      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
+      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
+      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
+      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
+      case VK_FORMAT_G16B16G16R16_422_UNORM:
+      case VK_FORMAT_B16G16R16G16_422_UNORM:
+      case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
+      case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
+      case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
+      case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
+      case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
       case VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG:
       case VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG:
       case VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG:
@@ -258,40 +300,22 @@
       case VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG:
       case VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG:
       case VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG:
-      case VK_FORMAT_G8B8G8R8_422_UNORM_KHR:
-      case VK_FORMAT_B8G8R8G8_422_UNORM_KHR:
-      case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR:
-      case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR:
-      case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR:
-      case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR:
-      case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR:
-      case VK_FORMAT_R10X6_UNORM_PACK16_KHR:
-      case VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR:
-      case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR:
-      case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR:
-      case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR:
-      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR:
-      case VK_FORMAT_R12X4_UNORM_PACK16_KHR:
-      case VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR:
-      case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR:
-      case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR:
-      case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR:
-      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR:
-      case VK_FORMAT_G16B16G16R16_422_UNORM_KHR:
-      case VK_FORMAT_B16G16R16G16_422_UNORM_KHR:
-      case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR:
-      case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR:
-      case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR:
-      case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR:
-      case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR:
+      case VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT:
+      case VK_FORMAT_A4R4G4B4_UNORM_PACK16_EXT:
+      case VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT:
         return true;
     }
     return false;
@@ -300,9 +324,14 @@
 
 template <>
 struct EnumTraits<VkPointClippingBehavior> {
-  static uint32_t min() { return VK_POINT_CLIPPING_BEHAVIOR_BEGIN_RANGE; }
-  static uint32_t max() { return VK_POINT_CLIPPING_BEHAVIOR_END_RANGE; }
-  static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+  static bool exist(uint32_t e) {
+    switch (e) {
+      case VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES:
+      case VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY:
+        return true;
+    }
+    return false;
+  }
 };
 
 template <>
@@ -336,9 +365,26 @@
 
 template <>
 struct EnumTraits<VkDriverIdKHR> {
-  static uint32_t min() { return VK_DRIVER_ID_BEGIN_RANGE_KHR; }
-  static uint32_t max() { return VK_DRIVER_ID_END_RANGE_KHR; }
-  static bool exist(uint32_t e) { return e >= min() && e <= max(); }
+  static bool exist(uint32_t e) {
+    switch (e) {
+      case VK_DRIVER_ID_AMD_PROPRIETARY:
+      case VK_DRIVER_ID_AMD_OPEN_SOURCE:
+      case VK_DRIVER_ID_MESA_RADV:
+      case VK_DRIVER_ID_NVIDIA_PROPRIETARY:
+      case VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS:
+      case VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA:
+      case VK_DRIVER_ID_IMAGINATION_PROPRIETARY:
+      case VK_DRIVER_ID_QUALCOMM_PROPRIETARY:
+      case VK_DRIVER_ID_ARM_PROPRIETARY:
+      case VK_DRIVER_ID_GOOGLE_SWIFTSHADER:
+      case VK_DRIVER_ID_GGP_PROPRIETARY:
+      case VK_DRIVER_ID_BROADCOM_PROPRIETARY:
+      case VK_DRIVER_ID_MESA_LLVMPIPE:
+      case VK_DRIVER_ID_MOLTENVK:
+        return true;
+    }
+    return false;
+  }
 };
 
 // VkSparseImageFormatProperties
diff --git a/vulkan/vkjson/vkjson_instance.cc b/vulkan/vkjson/vkjson_instance.cc
index ace713b..eb0fcc3 100644
--- a/vulkan/vkjson/vkjson_instance.cc
+++ b/vulkan/vkjson/vkjson_instance.cc
@@ -129,7 +129,9 @@
 
   VkFormatProperties format_properties = {};
   for (VkFormat format = VK_FORMAT_R4G4_UNORM_PACK8;
-       format <= VK_FORMAT_END_RANGE;
+       // TODO(http://b/171403054): avoid hard-coding last value in the
+       // contiguous range
+       format <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK;
        format = static_cast<VkFormat>(format + 1)) {
     vkGetPhysicalDeviceFormatProperties(physical_device, format,
                                         &format_properties);
@@ -142,6 +144,8 @@
 
   if (device.properties.apiVersion >= VK_API_VERSION_1_1) {
     for (VkFormat format = VK_FORMAT_G8B8G8R8_422_UNORM;
+         // TODO(http://b/171403054): avoid hard-coding last value in the
+         // contiguous range
          format <= VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM;
          format = static_cast<VkFormat>(format + 1)) {
       vkGetPhysicalDeviceFormatProperties(physical_device, format,