Merge "Added hasSha256SigningCertificate to the PackageManager aidl Interface." into sc-dev
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index 80d14ac..34e9a85 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -112,6 +112,7 @@
     ],
     required: [
         "atrace",
+        "dmabuf_dump",
         "ip",
         "iptables",
         "librank",
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 4a4a510..990aa53 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1846,10 +1846,8 @@
     RunCommand("IOTOP", {"iotop", "-n", "1", "-m", "100"});
 
     // Gather shared memory buffer info if the product implements it
-    struct stat st;
-    if (!stat("/product/bin/dmabuf_dump", &st)) {
-        RunCommand("Dmabuf dump", {"/product/bin/dmabuf_dump"});
-    }
+    RunCommand("Dmabuf dump", {"dmabuf_dump"});
+    RunCommand("Dmabuf per-buffer/per-exporter/per-device stats", {"dmabuf_dump", "-b"});
 
     DumpFile("PSI cpu", "/proc/pressure/cpu");
     DumpFile("PSI memory", "/proc/pressure/memory");
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 3a3df08..01f7d30 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -19,7 +19,7 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <gui/SurfaceComposerClient.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 
 namespace android {
 
@@ -227,15 +227,15 @@
         return false;
     }
 
-    DisplayConfig config;
-    status_t err = mSurfaceComposerClient->getActiveDisplayConfig(dpy, &config);
+    ui::DisplayMode mode;
+    status_t err = mSurfaceComposerClient->getActiveDisplayMode(dpy, &mode);
     if (err != NO_ERROR) {
-        fprintf(stderr, "SurfaceComposer::getActiveDisplayConfig failed: %#x\n", err);
+        fprintf(stderr, "SurfaceComposer::getActiveDisplayMode failed: %#x\n", err);
         return false;
     }
 
-    float scaleX = static_cast<float>(config.resolution.getWidth()) / w;
-    float scaleY = static_cast<float>(config.resolution.getHeight()) / h;
+    float scaleX = static_cast<float>(mode.resolution.getWidth()) / w;
+    float scaleY = static_cast<float>(mode.resolution.getHeight()) / h;
     *scale = scaleX < scaleY ? scaleX : scaleY;
 
     return true;
diff --git a/cmds/idlcli/Android.bp b/cmds/idlcli/Android.bp
index 643b3ca..72ffc94 100644
--- a/cmds/idlcli/Android.bp
+++ b/cmds/idlcli/Android.bp
@@ -15,7 +15,7 @@
 cc_defaults {
     name: "idlcli-defaults",
     shared_libs: [
-        "android.hardware.vibrator-unstable-ndk_platform",
+        "android.hardware.vibrator-V2-ndk_platform",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp
index 96875d5..cbe857a 100644
--- a/cmds/installd/Android.bp
+++ b/cmds/installd/Android.bp
@@ -38,6 +38,9 @@
         "libutils",
         "server_configurable_flags",
     ],
+    export_shared_lib_headers: [
+        "libbinder",
+    ],
 
     product_variables: {
         arc: {
diff --git a/cmds/lshal/DebugCommand.cpp b/cmds/lshal/DebugCommand.cpp
index 72958bd..ccf1ab1 100644
--- a/cmds/lshal/DebugCommand.cpp
+++ b/cmds/lshal/DebugCommand.cpp
@@ -28,7 +28,7 @@
 }
 
 std::string DebugCommand::getSimpleDescription() const {
-    return "Debug a specified HAL.";
+    return "Debug a specified HIDL HAL.";
 }
 
 Status DebugCommand::parseArgs(const Arg &arg) {
@@ -78,7 +78,7 @@
             "debug:\n"
             "    lshal debug [-E] <interface> [options [options [...]]] \n"
             "        Print debug information of a specified interface.\n"
-            "        -E: excludes debug output if HAL is actually a subclass.\n"
+            "        -E: excludes debug output if HIDL HAL is actually a subclass.\n"
             "        <interface>: Format is `android.hardware.foo@1.0::IFoo/default`.\n"
             "            If instance name is missing `default` is used.\n"
             "        options: space separated options to IBase::debug.\n";
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 22268ac..d5110f6 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -81,7 +81,7 @@
     return "list";
 }
 std::string ListCommand::getSimpleDescription() const {
-    return "List HALs.";
+    return "List HIDL HALs.";
 }
 
 std::string ListCommand::parseCmdline(pid_t pid) const {
@@ -295,21 +295,21 @@
     }
 
     mServicesTable.setDescription(
-            "| All binderized services (registered with hwservicemanager)");
+            "| All HIDL binderized services (registered with hwservicemanager)");
     mPassthroughRefTable.setDescription(
-            "| All interfaces that getService() has ever returned as a passthrough interface;\n"
+            "| All HIDL interfaces getService() has ever returned as a passthrough interface;\n"
             "| PIDs / processes shown below might be inaccurate because the process\n"
             "| might have relinquished the interface or might have died.\n"
             "| The Server / Server CMD column can be ignored.\n"
             "| The Clients / Clients CMD column shows all process that have ever dlopen'ed \n"
             "| the library and successfully fetched the passthrough implementation.");
     mImplementationsTable.setDescription(
-            "| All available passthrough implementations (all -impl.so files).\n"
+            "| All available HIDL passthrough implementations (all -impl.so files).\n"
             "| These may return subclasses through their respective HIDL_FETCH_I* functions.");
     mManifestHalsTable.setDescription(
-            "| All HALs that are in VINTF manifest.");
+            "| All HIDL HALs that are in VINTF manifest.");
     mLazyHalsTable.setDescription(
-            "| All HALs that are declared in VINTF manifest:\n"
+            "| All HIDL HALs that are declared in VINTF manifest:\n"
             "|    - as hwbinder HALs but are not registered to hwservicemanager, and\n"
             "|    - as hwbinder/passthrough HALs with no implementation.");
 }
@@ -903,11 +903,11 @@
         thiz->mSelectedColumns.push_back(TableColumnType::VINTF);
         return OK;
     }, "print VINTF info. This column contains a comma-separated list of:\n"
-       "    - DM: if the HAL is in the device manifest\n"
-       "    - DC: if the HAL is in the device compatibility matrix\n"
-       "    - FM: if the HAL is in the framework manifest\n"
-       "    - FC: if the HAL is in the framework compatibility matrix\n"
-       "    - X: if the HAL is in none of the above lists"});
+       "    - DM: if the HIDL HAL is in the device manifest\n"
+       "    - DC: if the HIDL HAL is in the device compatibility matrix\n"
+       "    - FM: if the HIDL HAL is in the framework manifest\n"
+       "    - FC: if the HIDL HAL is in the framework compatibility matrix\n"
+       "    - X: if the HIDL HAL is in none of the above lists"});
     mOptions.push_back({'S', "service-status", no_argument, v++, [](ListCommand* thiz, const char*) {
         thiz->mSelectedColumns.push_back(TableColumnType::SERVICE_STATUS);
         return OK;
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index 99cb93a..bc99f4d 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -59,7 +59,8 @@
 }
 
 void Lshal::usage() {
-    err() << "lshal: List and debug HALs." << std::endl << std::endl
+    err() << "lshal: List and debug HIDL HALs." << std::endl
+          << "   (for AIDL HALs, see `dumpsys`)" << std::endl << std::endl
           << "commands:" << std::endl;
 
     size_t nameMaxLength = 0;
diff --git a/cmds/lshal/WaitCommand.cpp b/cmds/lshal/WaitCommand.cpp
index 65b41b9..437a66a 100644
--- a/cmds/lshal/WaitCommand.cpp
+++ b/cmds/lshal/WaitCommand.cpp
@@ -29,7 +29,7 @@
 }
 
 std::string WaitCommand::getSimpleDescription() const {
-    return "Wait for HAL to start if it is not already started.";
+    return "Wait for HIDL HAL to start if it is not already started.";
 }
 
 Status WaitCommand::parseArgs(const Arg &arg) {
diff --git a/data/etc/android.hardware.keystore.limited_use_key.xml b/data/etc/android.hardware.keystore.limited_use_key.xml
new file mode 100644
index 0000000..5217086
--- /dev/null
+++ b/data/etc/android.hardware.keystore.limited_use_key.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices with KeyMint that can enforce limited use key
+     in hardware with any max usage count (including count equals to 1). -->
+<permissions>
+    <feature name="android.hardware.keystore.limited_use_key" />
+</permissions>
\ No newline at end of file
diff --git a/data/etc/android.hardware.keystore.single_use_key.xml b/data/etc/android.hardware.keystore.single_use_key.xml
new file mode 100644
index 0000000..40e80aa
--- /dev/null
+++ b/data/etc/android.hardware.keystore.single_use_key.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices with KeyMint that only can enforce limited use key
+     in hardware with max usage count equals to 1. -->
+<permissions>
+    <feature name="android.hardware.keystore.single_use_key" />
+</permissions>
\ No newline at end of file
diff --git a/data/etc/android.hardware.telephony.ims.singlereg.xml b/data/etc/android.hardware.telephony.ims.singlereg.xml
new file mode 100644
index 0000000..9a6cec0
--- /dev/null
+++ b/data/etc/android.hardware.telephony.ims.singlereg.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices that have an IMS service that supports all IMS
+     applications using a single IMS registration. -->
+<permissions>
+  <feature name="android.hardware.telephony.ims" />
+  <feature name="android.hardware.telephony.ims.singlereg" />
+</permissions>
diff --git a/include/OWNERS b/include/OWNERS
index db52850..c98e87a 100644
--- a/include/OWNERS
+++ b/include/OWNERS
@@ -1,3 +1,4 @@
+alecmouri@google.com
 alexeykuzmin@google.com
 dangittik@google.com
 jreck@google.com
@@ -8,7 +9,6 @@
 racarr@google.com
 romainguy@android.com
 santoscordon@google.com
-stoza@google.com
 svv@google.com
 
 # For multinetwork.h only.
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index d7f25e1..a70dffd 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -31,18 +31,8 @@
 #include <stddef.h>
 #include <jni.h>
 
-#ifndef __ANDROID__
-    // Value copied from 'bionic/libc/include/android/api-level.h' which is not available on
-    // non Android systems. It is set to 10000 which is same as __ANDROID_API_FUTURE__ value.
-    #ifndef __ANDROID_API__
-        #define __ANDROID_API__ 10000
-    #endif
-
-    // Value copied from 'bionic/libc/include/android/versioning.h' which is not available on
-    // non Android systems
-    #ifndef __INTRODUCED_IN
-        #define __INTRODUCED_IN(api_level)
-    #endif
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
 #endif
 
 #ifdef __cplusplus
@@ -132,8 +122,6 @@
 int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
                           AndroidBitmapInfo* info);
 
-#if __ANDROID_API__ >= 30
-
 /**
  * Given a java bitmap object, return its {@link ADataSpace}.
  *
@@ -145,8 +133,6 @@
  */
 int32_t AndroidBitmap_getDataSpace(JNIEnv* env, jobject jbitmap)  __INTRODUCED_IN(30);
 
-#endif // __ANDROID_API__ >= 30
-
 /**
  * Given a java bitmap object, attempt to lock the pixel address.
  * Locking will ensure that the memory for the pixels will not move
@@ -216,8 +202,6 @@
                                                 const void* data,
                                                 size_t size) __INTRODUCED_IN(30);
 
-#if __ANDROID_API__ >= 30
-
 /**
  *  Compress |pixels| as described by |info|.
  *
@@ -269,8 +253,6 @@
 int AndroidBitmap_getHardwareBuffer(JNIEnv* env, jobject bitmap,
         AHardwareBuffer** outBuffer) __INTRODUCED_IN(30);
 
-#endif // __ANDROID_API__ >= 30
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index e9f559c..8039bb0 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -61,8 +61,6 @@
  */
 typedef void (*AChoreographer_refreshRateCallback)(int64_t vsyncPeriodNanos, void* data);
 
-#if __ANDROID_API__ >= 24
-
 /**
  * Get the AChoreographer instance for the current thread. This must be called
  * on an ALooper thread.
@@ -86,10 +84,6 @@
                                              long delayMillis) __INTRODUCED_IN(24)
         __DEPRECATED_IN(29);
 
-#endif /* __ANDROID_API__ >= 24 */
-
-#if __ANDROID_API__ >= 29
-
 /**
  * Power a callback to be run on the next frame.  The data pointer provided will
  * be passed to the callback function when it's called.
@@ -111,10 +105,6 @@
                                                AChoreographer_frameCallback64 callback, void* data,
                                                uint32_t delayMillis) __INTRODUCED_IN(29);
 
-#endif /* __ANDROID_API__ >= 29 */
-
-#if __ANDROID_API__ >= 30
-
 /**
  * Registers a callback to be run when the display refresh rate changes. The
  * data pointer provided will be passed to the callback function when it's
@@ -160,7 +150,6 @@
 void AChoreographer_unregisterRefreshRateCallback(AChoreographer* choreographer,
                                                   AChoreographer_refreshRateCallback, void* data)
         __INTRODUCED_IN(30);
-#endif /* __ANDROID_API__ >= 30 */
 
 __END_DECLS
 
diff --git a/include/android/configuration.h b/include/android/configuration.h
index ccf3e59..88019ae 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -645,14 +645,12 @@
  */
 void AConfiguration_setScreenLong(AConfiguration* config, int32_t screenLong);
 
-#if __ANDROID_API__ >= 30
 /**
  * Return the current ACONFIGURATION_SCREENROUND_* set in the configuration.
  *
  * Available since API level 30.
  */
 int32_t AConfiguration_getScreenRound(AConfiguration* config) __INTRODUCED_IN(30);
-#endif
 
 /**
  * Set the current screen round in the configuration.
@@ -712,7 +710,6 @@
  */
 void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value);
 
-#if __ANDROID_API__ >= 17
 /**
  * Return the configuration's layout direction, or
  * ACONFIGURATION_LAYOUTDIR_ANY if not set.
@@ -727,7 +724,6 @@
  * Available since API level 17.
  */
 void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value) __INTRODUCED_IN(17);
-#endif /* __ANDROID_API__ >= 17 */
 
 /**
  * Perform a diff between two configurations.  Returns a bit mask of
diff --git a/include/android/font.h b/include/android/font.h
index 1618096..a172618 100644
--- a/include/android/font.h
+++ b/include/android/font.h
@@ -51,8 +51,6 @@
 
 __BEGIN_DECLS
 
-#if __ANDROID_API__ >= 29
-
 enum {
     /** The minimum value fot the font weight value. */
     AFONT_WEIGHT_MIN = 0,
@@ -297,8 +295,6 @@
 float AFont_getAxisValue(const AFont* _Nonnull font, uint32_t axisIndex)
       __INTRODUCED_IN(29);
 
-#endif // __ANDROID_API__ >= 29
-
 __END_DECLS
 
 #endif // ANDROID_FONT_H
diff --git a/include/android/font_matcher.h b/include/android/font_matcher.h
index d4bd892..49e478c 100644
--- a/include/android/font_matcher.h
+++ b/include/android/font_matcher.h
@@ -97,8 +97,6 @@
 
 __BEGIN_DECLS
 
-#if __ANDROID_API__ >= 29
-
 enum {
     /** A family variant value for the system default variant. */
     AFAMILY_VARIANT_DEFAULT = 0,
@@ -217,8 +215,6 @@
         const uint32_t textLength,
         uint32_t* _Nullable runLengthOut) __INTRODUCED_IN(29);
 
-#endif // __ANDROID_API__ >= 29
-
 __END_DECLS
 
 #endif // ANDROID_FONT_MATCHER_H
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
index c7a8939..cac67d4 100644
--- a/include/android/imagedecoder.h
+++ b/include/android/imagedecoder.h
@@ -51,18 +51,8 @@
 #include <android/rect.h>
 #include <stdint.h>
 
-#ifndef __ANDROID__
-    // Value copied from 'bionic/libc/include/android/api-level.h' which is not available on
-    // non Android systems. It is set to 10000 which is same as __ANDROID_API_FUTURE__ value.
-    #ifndef __ANDROID_API__
-        #define __ANDROID_API__ 10000
-    #endif
-
-    // Value copied from 'bionic/libc/include/android/versioning.h' which is not available on
-    // non Android systems
-    #ifndef __INTRODUCED_IN
-        #define __INTRODUCED_IN(api_level)
-    #endif
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
 #endif
 
 #ifdef __cplusplus
@@ -139,8 +129,6 @@
     ANDROID_IMAGE_DECODER_INVALID_STATE = -11,
 };
 
-#if __ANDROID_API__ >= 31
-
 /**
  * Return a constant string value representing the error code.
  *
@@ -155,8 +143,6 @@
  */
 const char* _Nullable AImageDecoder_resultToString(int)__INTRODUCED_IN(31);
 
-#endif // __ANDROID_API__ >= 31
-
 struct AImageDecoder;
 
 /**
@@ -179,8 +165,6 @@
  */
 typedef struct AImageDecoder AImageDecoder;
 
-#if __ANDROID_API__ >= 30
-
 /**
  * Create a new {@link AImageDecoder} from an {@link AAsset}.
  *
@@ -469,8 +453,6 @@
  */
 int AImageDecoder_setCrop(AImageDecoder* _Nonnull decoder, ARect crop) __INTRODUCED_IN(30);
 
-#endif // __ANDROID_API__ >= 30
-
 struct AImageDecoderHeaderInfo;
 /**
  * Opaque handle for representing information about the encoded image.
@@ -483,8 +465,6 @@
  */
 typedef struct AImageDecoderHeaderInfo AImageDecoderHeaderInfo;
 
-#if __ANDROID_API__ >= 30
-
 /**
  * Return an opaque handle for reading header info.
  *
@@ -672,10 +652,6 @@
                               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.
  *
@@ -690,8 +666,6 @@
 bool AImageDecoder_isAnimated(AImageDecoder* _Nonnull decoder)
         __INTRODUCED_IN(31);
 
-#endif // __ANDROID_API__ >= 31
-
 enum {
     /*
      * Reported by {@link AImageDecoder_getRepeatCount} if the
@@ -702,8 +676,6 @@
     ANDROID_IMAGE_DECODER_INFINITE = INT32_MAX,
 };
 
-#if __ANDROID_API__ >= 31
-
 /**
  * Report how many times the animation should repeat.
  *
@@ -793,8 +765,6 @@
 int AImageDecoder_rewind(AImageDecoder* _Nonnull decoder)
         __INTRODUCED_IN(31);
 
-#endif // __ANDROID_API__ >= 31
-
 struct AImageDecoderFrameInfo;
 
 /**
@@ -810,8 +780,6 @@
  */
 typedef struct AImageDecoderFrameInfo AImageDecoderFrameInfo;
 
-#if __ANDROID_API__ >= 31
-
 /**
  * Create an uninitialized AImageDecoderFrameInfo.
  *
@@ -922,8 +890,6 @@
 bool AImageDecoderFrameInfo_hasAlphaWithinBounds(
         const AImageDecoderFrameInfo* _Nonnull info) __INTRODUCED_IN(31);
 
-#endif // __ANDROID_API__ >= 31
-
 /**
  * How a frame is “disposed” before showing the next one.
  *
@@ -947,8 +913,6 @@
     ANDROID_IMAGE_DECODER_DISPOSE_OP_PREVIOUS = 3,
 };
 
-#if __ANDROID_API__ >= 31
-
 /**
  * Return how this frame is “disposed” before showing the next one.
  *
@@ -969,8 +933,6 @@
 int32_t AImageDecoderFrameInfo_getDisposeOp(
         const AImageDecoderFrameInfo* _Nonnull info) __INTRODUCED_IN(31);
 
-#endif // __ANDROID_API__ >= 31
-
 /**
  * How a frame is blended with the previous frame.
  *
@@ -989,8 +951,6 @@
     ANDROID_IMAGE_DECODER_BLEND_OP_SRC_OVER = 2,
 };
 
-#if __ANDROID_API__ >= 31
-
 /**
  * Return how this frame is blended with the previous frame.
  *
@@ -1047,8 +1007,6 @@
         __INTRODUCED_IN(31);
 
 
-#endif // __ANDROID_API__ >= 31
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index c6d1c94..424299d 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -60,8 +60,6 @@
  * on failure with an appropriate errno value set.
  */
 
-#if __ANDROID_API__ >= 23
-
 /**
  * Set the network to be used by the given socket file descriptor.
  *
@@ -111,10 +109,6 @@
         const char *node, const char *service,
         const struct addrinfo *hints, struct addrinfo **res) __INTRODUCED_IN(23);
 
-#endif /* __ANDROID_API__ >= 23 */
-
-#if __ANDROID_API__ >= 29
-
 /**
  * Possible values of the flags argument to android_res_nsend and android_res_nquery.
  * Values are ORed together.
@@ -187,8 +181,6 @@
  */
 void android_res_cancel(int nsend_fd) __INTRODUCED_IN(29);
 
-#endif /* __ANDROID_API__ >= 29 */
-
 __END_DECLS
 
 #endif  // ANDROID_MULTINETWORK_H
diff --git a/include/android/native_window_jni.h b/include/android/native_window_jni.h
index 3a77ffe..071ec79 100644
--- a/include/android/native_window_jni.h
+++ b/include/android/native_window_jni.h
@@ -44,7 +44,6 @@
  */
 ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);
 
-#if __ANDROID_API__ >= 26
 /**
  * Return a Java Surface object derived from the ANativeWindow, for interacting
  * with it through Java code. The returned Java object acquires a reference on
@@ -55,7 +54,6 @@
  * Available since API level 26.
  */
 jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window) __INTRODUCED_IN(26);
-#endif
 
 #ifdef __cplusplus
 };
diff --git a/include/android/sensor.h b/include/android/sensor.h
index eb40779..6447844 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -52,6 +52,13 @@
 #include <math.h>
 #include <stdint.h>
 
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
+#endif
+#if !defined(__DEPRECATED_IN)
+#define __DEPRECATED_IN(__api_level) __attribute__((__deprecated__))
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -553,13 +560,8 @@
  *     ASensorManager* sensorManager = ASensorManager_getInstance();
  *
  */
-#if __ANDROID_API__ >= 26
-__attribute__ ((deprecated)) ASensorManager* ASensorManager_getInstance();
-#else
-ASensorManager* ASensorManager_getInstance();
-#endif
+ASensorManager* ASensorManager_getInstance() __DEPRECATED_IN(26);
 
-#if __ANDROID_API__ >= 26
 /**
  * Get a reference to the sensor manager. ASensorManager is a singleton
  * per package as different packages may have access to different sensors.
@@ -571,7 +573,6 @@
  * Available since API level 26.
  */
 ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName) __INTRODUCED_IN(26);
-#endif
 
 /**
  * Returns the list of available sensors.
@@ -584,7 +585,6 @@
  */
 ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type);
 
-#if __ANDROID_API__ >= 21
 /**
  * Returns the default sensor with the given type and wakeUp properties or NULL if no sensor
  * of this type and wakeUp properties exists.
@@ -592,7 +592,6 @@
  * Available since API level 21.
  */
 ASensor const* ASensorManager_getDefaultSensorEx(ASensorManager* manager, int type, bool wakeUp) __INTRODUCED_IN(21);
-#endif
 
 /**
  * Creates a new sensor event queue and associate it with a looper.
@@ -609,7 +608,6 @@
  */
 int ASensorManager_destroyEventQueue(ASensorManager* manager, ASensorEventQueue* queue);
 
-#if __ANDROID_API__ >= 26
 /**
  * Create direct channel based on shared memory
  *
@@ -706,7 +704,6 @@
  */
 int ASensorManager_configureDirectReport(ASensorManager* manager,
         ASensor const* sensor, int channelId, int rate) __INTRODUCED_IN(26);
-#endif /* __ANDROID_API__ >= 26 */
 
 /*****************************************************************************/
 
@@ -795,7 +792,6 @@
  */
 ssize_t ASensorEventQueue_getEvents(ASensorEventQueue* queue, ASensorEvent* events, size_t count);
 
-#if __ANDROID_API__ >= 29
 /**
  * Request that {@link ASENSOR_TYPE_ADDITIONAL_INFO} events to be delivered on
  * the given {@link ASensorEventQueue}.
@@ -819,7 +815,6 @@
  * \return 0 on success or a negative error code on failure
  */
 int ASensorEventQueue_requestAdditionalInfoEvents(ASensorEventQueue* queue, bool enable) __INTRODUCED_IN(29);
-#endif /* __ANDROID_API__ >= 29 */
 
 /*****************************************************************************/
 
@@ -850,7 +845,6 @@
  */
 int ASensor_getMinDelay(ASensor const* sensor);
 
-#if __ANDROID_API__ >= 21
 /**
  * Returns the maximum size of batches for this sensor. Batches will often be
  * smaller, as the hardware fifo might be used for other sensors.
@@ -886,9 +880,7 @@
  * Available since API level 21.
  */
 bool ASensor_isWakeUpSensor(ASensor const* sensor) __INTRODUCED_IN(21);
-#endif /* __ANDROID_API__ >= 21 */
 
-#if __ANDROID_API__ >= 26
 /**
  * Test if sensor supports a certain type of direct channel.
  *
@@ -914,9 +906,7 @@
  *         does not support direct report.
  */
 int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_IN(26);
-#endif /* __ANDROID_API__ >= 26 */
 
-#if __ANDROID_API__ >= 29
 /**
  * Returns the sensor's handle.
  *
@@ -934,7 +924,6 @@
  * Available since API level 29.
  */
 int ASensor_getHandle(ASensor const* sensor) __INTRODUCED_IN(29);
-#endif /* __ANDROID_API__ >= 29 */
 
 #ifdef __cplusplus
 };
diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h
index 5f74682..7994aa9 100644
--- a/include/android/sharedmem.h
+++ b/include/android/sharedmem.h
@@ -50,8 +50,6 @@
 extern "C" {
 #endif
 
-#if __ANDROID_API__ >= 26
-
 /**
  * Create a shared memory region.
  *
@@ -121,8 +119,6 @@
  */
 int ASharedMemory_setProt(int fd, int prot) __INTRODUCED_IN(26);
 
-#endif // __ANDROID_API__ >= 26
-
 #ifdef __cplusplus
 };
 #endif
diff --git a/include/android/sharedmem_jni.h b/include/android/sharedmem_jni.h
index 13e56e6..bbac785 100644
--- a/include/android/sharedmem_jni.h
+++ b/include/android/sharedmem_jni.h
@@ -52,8 +52,6 @@
 extern "C" {
 #endif
 
-#if __ANDROID_API__ >= 27
-
 /**
  * Returns a dup'd FD from the given Java android.os.SharedMemory object. The returned file
  * descriptor has all the same properties & capabilities as the FD returned from
@@ -72,8 +70,6 @@
  */
 int ASharedMemory_dupFromJava(JNIEnv* env, jobject sharedMemory) __INTRODUCED_IN(27);
 
-#endif // __ANDROID_API__ >= 27
-
 #ifdef __cplusplus
 };
 #endif
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index 7a74248..98fd875 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -35,8 +35,6 @@
 
 __BEGIN_DECLS
 
-#if __ANDROID_API__ >= 29
-
 struct ASurfaceControl;
 
 /**
@@ -409,10 +407,6 @@
                                                  struct AHdrMetadata_cta861_3* metadata)
                                                  __INTRODUCED_IN(29);
 
-#endif // __ANDROID_API__ >= 29
-
-#if __ANDROID_API__ >= 30
-
 /**
  * Same as ASurfaceTransaction_setFrameRateWithSeamlessness(transaction, surface_control,
  * frameRate, compatibility, true).
@@ -425,10 +419,6 @@
                                       ASurfaceControl* surface_control, float frameRate,
                                       int8_t compatibility) __INTRODUCED_IN(30);
 
-#endif // __ANDROID_API__ >= 30
-
-#if __ANDROID_API__ >= 31
-
 /**
  * Sets the intended frame rate for \a surface_control.
  *
@@ -462,7 +452,6 @@
                                       int8_t compatibility, bool shouldBeSeamless)
                                       __INTRODUCED_IN(31);
 
-#endif // __ANDROID_API__ >= 31
 __END_DECLS
 
 #endif // ANDROID_SURFACE_CONTROL_H
diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h
index dde7eaa..b227b32 100644
--- a/include/android/surface_texture.h
+++ b/include/android/surface_texture.h
@@ -59,8 +59,6 @@
  */
 typedef struct ASurfaceTexture ASurfaceTexture;
 
-#if __ANDROID_API__ >= 28
-
 /**
  * Release the reference to the native ASurfaceTexture acquired with
  * ASurfaceTexture_fromSurfaceTexture().
@@ -175,8 +173,6 @@
  */
 int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) __INTRODUCED_IN(28);
 
-#endif /* __ANDROID_API__ >= 28 */
-
 __END_DECLS
 
 #endif /* ANDROID_NATIVE_SURFACE_TEXTURE_H */
diff --git a/include/android/surface_texture_jni.h b/include/android/surface_texture_jni.h
index 2266d54..e40686d 100644
--- a/include/android/surface_texture_jni.h
+++ b/include/android/surface_texture_jni.h
@@ -32,8 +32,6 @@
 
 __BEGIN_DECLS
 
-#if __ANDROID_API__ >= 28
-
 /**
  * Get a reference to the native ASurfaceTexture from the corresponding java object.
  *
@@ -52,8 +50,6 @@
  */
 ASurfaceTexture* ASurfaceTexture_fromSurfaceTexture(JNIEnv* env, jobject surfacetexture) __INTRODUCED_IN(28);
 
-#endif
-
 __END_DECLS
 
 #endif /* ANDROID_NATIVE_SURFACE_TEXTURE_JNI_H */
diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h
index 6fd7d2c..b0bbb95 100644
--- a/include/android/system_fonts.h
+++ b/include/android/system_fonts.h
@@ -87,8 +87,6 @@
 
 __BEGIN_DECLS
 
-#if __ANDROID_API__ >= 29
-
 /**
  * ASystemFontIterator provides access to the system font configuration.
  *
@@ -128,8 +126,6 @@
  */
 AFont* _Nullable ASystemFontIterator_next(ASystemFontIterator* _Nonnull iterator) __INTRODUCED_IN(29);
 
-#endif // __ANDROID_API__ >= 29
-
 __END_DECLS
 
 #endif // ANDROID_SYSTEM_FONTS_H
diff --git a/include/android/trace.h b/include/android/trace.h
index dbad6f6..dcefffb 100644
--- a/include/android/trace.h
+++ b/include/android/trace.h
@@ -40,8 +40,6 @@
 extern "C" {
 #endif
 
-#if __ANDROID_API__ >= 23
-
 /**
  * Returns true if tracing is enabled. Use this to avoid expensive computation only necessary
  * when tracing is enabled.
@@ -72,10 +70,6 @@
  */
 void ATrace_endSection() __INTRODUCED_IN(23);
 
-#endif /* __ANDROID_API__ >= 23 */
-
-#if __ANDROID_API__ >= 29
-
 /**
  * Writes a trace message to indicate that a given section of code has
  * begun. Must be followed by a call to {@link ATrace_endAsyncSection} with the same
@@ -112,8 +106,6 @@
  */
 void ATrace_setCounter(const char* counterName, int64_t counterValue) __INTRODUCED_IN(29);
 
-#endif /* __ANDROID_API__ >= 29 */
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
index 7d1f38f..426e10c 100644
--- a/include/audiomanager/IAudioManager.h
+++ b/include/audiomanager/IAudioManager.h
@@ -39,6 +39,7 @@
         TRACK_RECORDER                        = IBinder::FIRST_CALL_TRANSACTION + 4,
         RECORDER_EVENT                        = IBinder::FIRST_CALL_TRANSACTION + 5,
         RELEASE_RECORDER                      = IBinder::FIRST_CALL_TRANSACTION + 6,
+        PLAYER_SESSION_ID                     = IBinder::FIRST_CALL_TRANSACTION + 7,
     };
 
     DECLARE_META_INTERFACE(AudioManager)
@@ -46,7 +47,8 @@
     // The parcels created by these methods must be kept in sync with the
     // corresponding methods from IAudioService.aidl and objects it imports.
     virtual audio_unique_id_t trackPlayer(player_type_t playerType, audio_usage_t usage,
-                audio_content_type_t content, const sp<IBinder>& player) = 0;
+                audio_content_type_t content, const sp<IBinder>& player,
+                audio_session_t sessionId) = 0;
     /*oneway*/ virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage,
                 audio_content_type_t content)= 0;
     /*oneway*/ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event,
@@ -55,6 +57,7 @@
     virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) = 0;
     /*oneway*/ virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) = 0;
     /*oneway*/ virtual status_t releaseRecorder(audio_unique_id_t riid) = 0;
+    /*oneway*/ virtual status_t playerSessionId(audio_unique_id_t piid, audio_session_t sessionId) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/adbd_auth/include/adbd_auth.h b/libs/adbd_auth/include/adbd_auth.h
index 8f834df..1dcf540 100644
--- a/libs/adbd_auth/include/adbd_auth.h
+++ b/libs/adbd_auth/include/adbd_auth.h
@@ -26,7 +26,6 @@
 #endif
 
 __BEGIN_DECLS
-#if !defined(__ANDROID__) || __ANDROID_API__ >= 30
 
 // The transport type of the device connection.
 enum AdbTransportType : int32_t {
@@ -186,5 +185,4 @@
  */
 bool adbd_auth_supports_feature(AdbdAuthFeature feature);
 
-#endif  //!__ANDROID__ || __ANDROID_API__ >= 30
 __END_DECLS
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 2c0cca1..b585ad2 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -22,14 +22,21 @@
 
     header_libs: [
         "libbase_headers",
+        "libbinder_headers_platform_shared",
         "libcutils_headers",
         "libutils_headers",
     ],
     export_header_lib_headers: [
         "libbase_headers",
+        "libbinder_headers_platform_shared",
         "libcutils_headers",
         "libutils_headers",
     ],
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media",
+        "com.android.media.swcodec",
+    ],
     min_sdk_version: "29",
     target: {
         darwin: {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 5c34069..79a11d2 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -611,6 +611,12 @@
     mPostWriteStrongDerefs.clear();
 }
 
+void IPCThreadState::createTransactionReference(RefBase* ref)
+{
+    ref->incStrong(mProcess.get());
+    mPostWriteStrongDerefs.push(ref);
+}
+
 void IPCThreadState::joinThreadPool(bool isMain)
 {
     LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
diff --git a/libs/binder/IpPrefix.cpp b/libs/binder/IpPrefix.cpp
index 8d62266..4edc493 100644
--- a/libs/binder/IpPrefix.cpp
+++ b/libs/binder/IpPrefix.cpp
@@ -24,12 +24,10 @@
 #include <log/log.h>
 #include <utils/Errors.h>
 
-using android::BAD_TYPE;
 using android::BAD_VALUE;
 using android::NO_ERROR;
 using android::Parcel;
 using android::status_t;
-using android::UNEXPECTED_NULL;
 
 namespace android {
 
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 440c98c..b9d00fe 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2291,7 +2291,7 @@
         ssize_t written = TEMP_FAILURE_RETRY(
             ::write(comm, &message, sizeof(message)));
 
-        if (written == -1 || written != sizeof(message)) {
+        if (written != sizeof(message)) {
             ALOGW("Failed to detach ParcelFileDescriptor written: %zd err: %s",
                 written, strerror(errno));
             return BAD_TYPE;
diff --git a/libs/binder/PersistableBundle.cpp b/libs/binder/PersistableBundle.cpp
index c807cfe..406fee0 100644
--- a/libs/binder/PersistableBundle.cpp
+++ b/libs/binder/PersistableBundle.cpp
@@ -31,7 +31,6 @@
 using android::BAD_VALUE;
 using android::NO_ERROR;
 using android::Parcel;
-using android::sp;
 using android::status_t;
 using android::UNEXPECTED_NULL;
 
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index c8fb448..31f63c8 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -60,6 +60,15 @@
         EXTENSION_TRANSACTION   = B_PACK_CHARS('_', 'E', 'X', 'T'),
         DEBUG_PID_TRANSACTION   = B_PACK_CHARS('_', 'P', 'I', 'D'),
 
+        // See android.os.IBinder.TWEET_TRANSACTION
+        // Most importantly, messages can be anything not exceeding 130 UTF-8
+        // characters, and callees should exclaim "jolly good message old boy!"
+        TWEET_TRANSACTION       = B_PACK_CHARS('_', 'T', 'W', 'T'),
+
+        // See android.os.IBinder.LIKE_TRANSACTION
+        // Improve binder self-esteem.
+        LIKE_TRANSACTION        = B_PACK_CHARS('_', 'L', 'I', 'K'),
+
         // Corresponds to TF_ONE_WAY -- an asynchronous call.
         FLAG_ONEWAY             = 0x00000001,
 
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 0183324..23a0cb0 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -162,6 +162,12 @@
             // This constant needs to be kept in sync with Binder.UNSET_WORKSOURCE from the Java
             // side.
             static const int32_t kUnsetWorkSource = -1;
+
+            // Create a temp reference until commands in queue flushed to driver
+            // Internal only.
+            // @internal
+            void                 createTransactionReference(RefBase* ref);
+
 private:
                                 IPCThreadState();
                                 ~IPCThreadState();
diff --git a/libs/binder/include/binder/ParcelRef.h b/libs/binder/include/binder/ParcelRef.h
new file mode 100644
index 0000000..497da2d
--- /dev/null
+++ b/libs/binder/include/binder/ParcelRef.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+
+#include <binder/Parcel.h>
+#include <utils/RefBase.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+/**
+ * internal use only
+ * @internal
+ */
+class ParcelRef : public Parcel, public RefBase
+{
+public:
+    static sp<ParcelRef> create() {
+        return new ParcelRef();
+    }
+
+private:
+    ParcelRef() = default;
+};
+
+} // namespace android
+
+// ---------------------------------------------------------------------------
\ No newline at end of file
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 82f3882..897c72a 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -129,6 +129,26 @@
     ],
 }
 
+cc_library_headers {
+    name: "libbinder_headers_platform_shared",
+    export_include_dirs: ["include_cpp"],
+    vendor_available: true,
+    host_supported: true,
+    // TODO(b/153609531): remove when no longer needed.
+    native_bridge_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    apex_available: [
+        "//apex_available:platform",
+        "com.android.media",
+        "com.android.media.swcodec",
+    ],
+    min_sdk_version: "29",
+}
+
 ndk_headers {
     name: "libbinder_ndk_headers",
     from: "include_ndk/android",
diff --git a/libs/binder/ndk/include_cpp/android/binder_to_string.h b/libs/binder/ndk/include_cpp/android/binder_to_string.h
new file mode 100644
index 0000000..bd51b11
--- /dev/null
+++ b/libs/binder/ndk/include_cpp/android/binder_to_string.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_to_string.h
+ * @brief Helper for parcelable.
+ */
+
+#pragma once
+
+#include <codecvt>
+#include <locale>
+#include <sstream>
+#include <string>
+#include <type_traits>
+
+#if __has_include(<android/binder_ibinder.h>)
+#include <android/binder_auto_utils.h>
+#include <android/binder_interface_utils.h>
+#include <android/binder_parcelable_utils.h>
+#define HAS_NDK_INTERFACE
+#else
+#include <binder/IBinder.h>
+#include <binder/IInterface.h>
+#include <binder/ParcelFileDescriptor.h>
+#include <binder/ParcelableHolder.h>
+#include <utils/String16.h>
+#include <utils/StrongPointer.h>
+#define HAS_CPP_INTERFACE
+#endif  //_has_include
+
+namespace android {
+namespace internal {
+
+// ToString is a utility to generate string representation for various AIDL-supported types.
+template <typename _T>
+std::string ToString(const _T& t);
+
+namespace details {
+
+// Truthy if _T has toString() method.
+template <typename _T>
+class HasToStringMethod {
+    template <typename _U>
+    static auto _test(int) -> decltype(std::declval<_U>().toString(), std::true_type());
+    template <typename _U>
+    static std::false_type _test(...);
+
+   public:
+    enum { value = decltype(_test<_T>(0))::value };
+};
+
+// Truthy if _T has a overloaded toString(T)
+template <typename _T>
+class HasToStringFunction {
+    template <typename _U>
+    static auto _test(int) -> decltype(toString(std::declval<_U>()), std::true_type());
+    template <typename _U>
+    static std::false_type _test(...);
+
+   public:
+    enum { value = decltype(_test<_T>(0))::value };
+};
+
+// Truthy if _T is like a pointer
+template <typename _T>
+class IsPointerLike {
+    template <typename _U>
+    static auto _test(int) -> decltype(!std::declval<_U>(), *std::declval<_U>(), std::true_type());
+    template <typename _U>
+    static std::false_type _test(...);
+
+   public:
+    enum { value = decltype(_test<_T>(0))::value };
+};
+
+// Truthy if _T is like a container
+template <typename _T>
+class IsIterable {
+    template <typename _U>
+    static auto _test(int)
+            -> decltype(begin(std::declval<_U>()), end(std::declval<_U>()), std::true_type());
+    template <typename _U>
+    static std::false_type _test(...);
+
+   public:
+    enum { value = decltype(_test<_T>(0))::value };
+};
+
+template <typename _T>
+class ToEmptyString {
+    template <typename _U>
+    static std::enable_if_t<
+#ifdef HAS_NDK_INTERFACE
+            std::is_base_of_v<::ndk::ICInterface, _U> || std::is_same_v<::ndk::SpAIBinder, _U> ||
+                    std::is_same_v<::ndk::ScopedFileDescriptor, _U> ||
+                    std::is_same_v<::ndk::AParcelableHolder, _U>
+#else
+            std::is_base_of_v<IInterface, _U> || std::is_same_v<IBinder, _U> ||
+                    std::is_same_v<os::ParcelFileDescriptor, _U> ||
+                    std::is_same_v<os::ParcelableHolder, _U>
+#endif
+            ,
+            std::true_type>
+    _test(int);
+    template <typename _U>
+    static std::false_type _test(...);
+
+   public:
+    enum { value = decltype(_test<_T>(0))::value };
+};
+
+}  // namespace details
+
+template <typename _T>
+std::string ToString(const _T& t) {
+    if constexpr (details::ToEmptyString<_T>::value) {
+        return "";
+    } else if constexpr (std::is_same_v<bool, _T>) {
+        return t ? "true" : "false";
+    } else if constexpr (std::is_same_v<char16_t, _T>) {
+        return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>().to_bytes(t);
+    } else if constexpr (std::is_arithmetic_v<_T>) {
+        return std::to_string(t);
+    } else if constexpr (std::is_same_v<std::string, _T>) {
+        return t;
+#ifdef HAS_CPP_INTERFACE
+    } else if constexpr (std::is_same_v<String16, _T>) {
+        std::stringstream out;
+        out << t;
+        return out.str();
+#endif
+    } else if constexpr (details::HasToStringMethod<_T>::value) {
+        return t.toString();
+    } else if constexpr (details::HasToStringFunction<_T>::value) {
+        return toString(t);
+    } else if constexpr (details::IsIterable<_T>::value) {
+        std::stringstream out;
+        bool first = true;
+        out << "[";
+        for (const auto& e : t) {
+            if (first) {
+                first = false;
+            } else {
+                out << ", ";
+            }
+            // Use explicit type parameter in case deref of iterator has different type
+            // e.g. vector<bool>
+            out << ToString<typename _T::value_type>(e);
+        }
+        out << "]";
+        return out.str();
+    } else if constexpr (details::IsPointerLike<_T>::value) {
+        if (!t) return "(null)";
+        std::stringstream out;
+        out << ToString(*t);
+        return out.str();
+    } else {
+        return "{no toString() implemented}";
+    }
+}
+
+}  // namespace internal
+}  // namespace android
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index bb70588..a44c261 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -41,8 +41,6 @@
  android platform host build, you must use libbinder_ndk_host_user.
 #endif
 
-#if __ANDROID_API__ >= 29
-
 typedef uint32_t binder_flags_t;
 enum {
     /**
@@ -567,10 +565,6 @@
  */
 void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) __INTRODUCED_IN(29);
 
-#endif  //__ANDROID_API__ >= 29
-
-#if __ANDROID_API__ >= 30
-
 /**
  * Gets the extension registered with AIBinder_setExtension.
  *
@@ -640,10 +634,6 @@
  */
 binder_status_t AIBinder_setExtension(AIBinder* binder, AIBinder* ext) __INTRODUCED_IN(30);
 
-#endif  //__ANDROID_API__ >= 30
-
-#if __ANDROID_API__ >= 31
-
 /**
  * Retrieve the class descriptor for the class.
  *
@@ -728,8 +718,6 @@
  */
 bool AIBinder_Weak_lt(const AIBinder_Weak* lhs, const AIBinder_Weak* rhs);
 
-#endif  //__ANDROID_API__ >= 31
-
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
index cd1ff1f..6880d86 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder_jni.h
@@ -31,7 +31,6 @@
 #include <jni.h>
 
 __BEGIN_DECLS
-#if __ANDROID_API__ >= 29
 
 /**
  * Converts an android.os.IBinder object into an AIBinder* object.
@@ -67,7 +66,6 @@
 __attribute__((warn_unused_result)) jobject AIBinder_toJavaBinder(JNIEnv* env, AIBinder* binder)
         __INTRODUCED_IN(29);
 
-#endif  //__ANDROID_API__ >= 29
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index ab67017..527b151 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -36,7 +36,6 @@
 typedef struct AIBinder AIBinder;
 
 __BEGIN_DECLS
-#if __ANDROID_API__ >= 29
 
 /**
  * This object represents a package of data that can be sent between processes. When transacting, an
@@ -1119,7 +1118,6 @@
 
 // @END-PRIMITIVE-READ-WRITE
 
-#endif  //__ANDROID_API__ >= 29
 /**
  * Reset the parcel to the initial status.
  *
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel_jni.h b/libs/binder/ndk/include_ndk/android/binder_parcel_jni.h
index 65e1704..384d4f7 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel_jni.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel_jni.h
@@ -31,7 +31,6 @@
 #include <jni.h>
 
 __BEGIN_DECLS
-#if __ANDROID_API__ >= 30
 
 /**
  * Converts an android.os.Parcel object into an AParcel* object.
@@ -50,7 +49,6 @@
 __attribute__((warn_unused_result)) AParcel* AParcel_fromJavaParcel(JNIEnv* env, jobject parcel)
         __INTRODUCED_IN(30);
 
-#endif  //__ANDROID_API__ >= 30
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index 3a55f94..05b25e7 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -31,7 +31,6 @@
 #include <sys/cdefs.h>
 
 __BEGIN_DECLS
-#if __ANDROID_API__ >= 29
 
 enum {
     STATUS_OK = 0,
@@ -275,7 +274,6 @@
  */
 void AStatus_delete(AStatus* status) __INTRODUCED_IN(29);
 
-#endif  //__ANDROID_API__ >= 29
 __END_DECLS
 
 /** @} */
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 988f7f3..259417a 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -220,3 +220,15 @@
     test_suites: ["device-tests"],
     require_root: true,
 }
+
+cc_benchmark {
+    name: "binderParcelBenchmark",
+    defaults: ["binder_test_defaults"],
+    srcs: ["binderParcelBenchmark.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "liblog",
+        "libutils",
+    ],
+}
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index a5261e5..e2193fa 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -21,6 +21,7 @@
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <thread>
 
 #include <gtest/gtest.h>
 
@@ -28,6 +29,7 @@
 #include <binder/IBinder.h>
 #include <binder/IPCThreadState.h>
 #include <binder/IServiceManager.h>
+#include <binder/ParcelRef.h>
 
 #include <private/binder/binder_module.h>
 #include <linux/sched.h>
@@ -916,6 +918,36 @@
     }
 }
 
+TEST_F(BinderLibTest, ParcelAllocatedOnAnotherThread) {
+    sp<IBinder> server = addServer();
+    ASSERT_TRUE(server != nullptr);
+
+    Parcel data;
+    sp<ParcelRef> reply = ParcelRef::create();
+
+    // when we have a Parcel which is deleted on another thread, if it gets
+    // deleted, it will tell the kernel this, and it will drop strong references
+    // to binder, so that we can't BR_ACQUIRE would fail
+    IPCThreadState::self()->createTransactionReference(reply.get());
+    ASSERT_EQ(NO_ERROR, server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION,
+                                         data,
+                                         reply.get()));
+
+    // we have sp to binder, but it is not actually acquired by kernel, the
+    // transaction is sitting on an out buffer
+    sp<IBinder> binder = reply->readStrongBinder();
+
+    std::thread([&] {
+        // without the transaction reference, this would cause the Parcel to be
+        // deallocated before the first thread flushes BR_ACQUIRE
+        reply = nullptr;
+        IPCThreadState::self()->flushCommands();
+    }).join();
+
+    ASSERT_NE(nullptr, binder);
+    ASSERT_EQ(NO_ERROR, binder->pingBinder());
+}
+
 TEST_F(BinderLibTest, CheckNoHeaderMappedInUser) {
     status_t ret;
     Parcel data, reply;
diff --git a/libs/binder/tests/binderParcelBenchmark.cpp b/libs/binder/tests/binderParcelBenchmark.cpp
new file mode 100644
index 0000000..ec69c36
--- /dev/null
+++ b/libs/binder/tests/binderParcelBenchmark.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Parcel.h>
+#include <benchmark/benchmark.h>
+
+// Usage: atest binderParcelBenchmark
+
+// For static assert(false) we need a template version to avoid early failure.
+// See: https://stackoverflow.com/questions/51523965/template-dependent-false
+template <typename T>
+constexpr bool dependent_false_v = false;
+
+template <template <typename ...> class V, typename T, typename... Args>
+void writeVector(android::Parcel &p, const V<T, Args...> &v) {
+    if constexpr (std::is_same_v<T, bool>) {
+        p.writeBoolVector(v);
+    } else if constexpr (std::is_same_v<T, uint8_t>) {
+        p.writeByteVector(v);
+    } else if constexpr (std::is_same_v<T, char16_t>) {
+        p.writeCharVector(v);
+    } else if constexpr (std::is_same_v<T, int32_t>) {
+        p.writeInt32Vector(v);
+    } else if constexpr (std::is_same_v<T, int64_t>) {
+        p.writeInt64Vector(v);
+    } else {
+        static_assert(dependent_false_v<V<T>>);
+    }
+}
+
+template <template <typename ...> class V, typename T, typename... Args>
+void readVector(android::Parcel &p, V<T, Args...> *v) {
+    if constexpr (std::is_same_v<T, bool>) {
+        p.readBoolVector(v);
+    } else if constexpr (std::is_same_v<T, uint8_t>) {
+        p.readByteVector(v);
+    } else if constexpr (std::is_same_v<T, char16_t>) {
+        p.readCharVector(v);
+    } else if constexpr (std::is_same_v<T, int32_t>) {
+        p.readInt32Vector(v);
+    } else if constexpr (std::is_same_v<T, int64_t>) {
+        p.readInt64Vector(v);
+    } else {
+        static_assert(dependent_false_v<V<T>>);
+    }
+}
+
+// Construct a series of args { 1 << 0, 1 << 1, ..., 1 << 10 }
+static void VectorArgs(benchmark::internal::Benchmark* b) {
+    for (int i = 0; i < 10; ++i) {
+        b->Args({1 << i});
+    }
+}
+
+template <typename T>
+static void BM_ParcelVector(benchmark::State& state) {
+    const size_t elements = state.range(0);
+
+    std::vector<T> v1(elements);
+    std::vector<T> v2(elements);
+    android::Parcel p;
+    while (state.KeepRunning()) {
+        p.setDataPosition(0);
+        writeVector(p, v1);
+
+        p.setDataPosition(0);
+        readVector(p, &v2);
+
+        benchmark::DoNotOptimize(v2[0]);
+        benchmark::ClobberMemory();
+    }
+    state.SetComplexityN(elements);
+}
+
+/*
+  Parcel vector write than read.
+  The read and write vectors are fixed, no resizing required.
+
+  Results on Crosshatch Pixel 3XL
+
+  #BM_BoolVector/1         40 ns      40 ns     17261011
+  #BM_BoolVector/2         46 ns      46 ns     15029619
+  #BM_BoolVector/4         65 ns      64 ns     10888021
+  #BM_BoolVector/8        114 ns     114 ns      6130937
+  #BM_BoolVector/16       179 ns     179 ns      3902462
+  #BM_BoolVector/32       328 ns     327 ns      2138812
+  #BM_BoolVector/64       600 ns     598 ns      1169414
+  #BM_BoolVector/128     1168 ns    1165 ns       601281
+  #BM_BoolVector/256     2288 ns    2281 ns       305737
+  #BM_BoolVector/512     4535 ns    4521 ns       154668
+  #BM_ByteVector/1         53 ns      52 ns     13212196
+  #BM_ByteVector/2         53 ns      53 ns     13194050
+  #BM_ByteVector/4         50 ns      50 ns     13768037
+  #BM_ByteVector/8         50 ns      50 ns     13890210
+  #BM_ByteVector/16        50 ns      50 ns     13897305
+  #BM_ByteVector/32        51 ns      51 ns     13679862
+  #BM_ByteVector/64        54 ns      53 ns     12988544
+  #BM_ByteVector/128       64 ns      64 ns     10921227
+  #BM_ByteVector/256       82 ns      81 ns      8542549
+  #BM_ByteVector/512      118 ns     118 ns      5862931
+  #BM_CharVector/1         32 ns      32 ns     21783579
+  #BM_CharVector/2         38 ns      38 ns     18200971
+  #BM_CharVector/4         53 ns      53 ns     13111785
+  #BM_CharVector/8         80 ns      80 ns      8698331
+  #BM_CharVector/16       159 ns     159 ns      4390738
+  #BM_CharVector/32       263 ns     262 ns      2667310
+  #BM_CharVector/64       486 ns     485 ns      1441118
+  #BM_CharVector/128      937 ns     934 ns       749006
+  #BM_CharVector/256     1848 ns    1843 ns       379537
+  #BM_CharVector/512     3650 ns    3639 ns       191713
+  #BM_Int32Vector/1        31 ns      31 ns     22104147
+  #BM_Int32Vector/2        38 ns      38 ns     18075471
+  #BM_Int32Vector/4        53 ns      52 ns     13249969
+  #BM_Int32Vector/8        80 ns      80 ns      8719798
+  #BM_Int32Vector/16      161 ns     160 ns      4350096
+  #BM_Int32Vector/32      271 ns     270 ns      2591896
+  #BM_Int32Vector/64      499 ns     498 ns      1406201
+  #BM_Int32Vector/128     948 ns     945 ns       740052
+  #BM_Int32Vector/256    1855 ns    1849 ns       379127
+  #BM_Int32Vector/512    3665 ns    3653 ns       191533
+  #BM_Int64Vector/1        31 ns      31 ns     22388370
+  #BM_Int64Vector/2        38 ns      38 ns     18300347
+  #BM_Int64Vector/4        53 ns      53 ns     13137818
+  #BM_Int64Vector/8        81 ns      81 ns      8599613
+  #BM_Int64Vector/16      167 ns     166 ns      4195953
+  #BM_Int64Vector/32      280 ns     280 ns      2499271
+  #BM_Int64Vector/64      523 ns     522 ns      1341380
+  #BM_Int64Vector/128     991 ns     988 ns       707437
+  #BM_Int64Vector/256    1940 ns    1934 ns       361704
+  #BM_Int64Vector/512    3843 ns    3831 ns       183204
+*/
+
+static void BM_BoolVector(benchmark::State& state) {
+    BM_ParcelVector<bool>(state);
+}
+
+static void BM_ByteVector(benchmark::State& state) {
+    BM_ParcelVector<uint8_t>(state);
+}
+
+static void BM_CharVector(benchmark::State& state) {
+    BM_ParcelVector<char16_t>(state);
+}
+
+static void BM_Int32Vector(benchmark::State& state) {
+    BM_ParcelVector<int32_t>(state);
+}
+
+static void BM_Int64Vector(benchmark::State& state) {
+    BM_ParcelVector<int64_t>(state);
+}
+
+BENCHMARK(BM_BoolVector)->Apply(VectorArgs);
+BENCHMARK(BM_ByteVector)->Apply(VectorArgs);
+BENCHMARK(BM_CharVector)->Apply(VectorArgs);
+BENCHMARK(BM_Int32Vector)->Apply(VectorArgs);
+BENCHMARK(BM_Int64Vector)->Apply(VectorArgs);
+
+BENCHMARK_MAIN();
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 462f0db..7e9bb7d 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -155,10 +155,14 @@
     return true;
 }
 
-static bool attachTracepointProgram(const std::string &eventType, const std::string &eventName) {
+static int retrieveProgramFd(const std::string &eventType, const std::string &eventName) {
     std::string path = StringPrintf(BPF_FS_PATH "prog_time_in_state_tracepoint_%s_%s",
                                     eventType.c_str(), eventName.c_str());
-    int prog_fd = retrieveProgram(path.c_str());
+    return retrieveProgram(path.c_str());
+}
+
+static bool attachTracepointProgram(const std::string &eventType, const std::string &eventName) {
+    int prog_fd = retrieveProgramFd(eventType, eventName);
     if (prog_fd < 0) return false;
     return bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) >= 0;
 }
@@ -174,6 +178,17 @@
     return {};
 }
 
+// Check if tracking is expected to work without activating it.
+bool isTrackingUidTimesSupported() {
+    auto freqs = getCpuFreqs();
+    if (!freqs || freqs->empty()) return false;
+    if (gTracking) return true;
+    if (retrieveProgramFd("sched", "sched_switch") < 0) return false;
+    if (retrieveProgramFd("power", "cpu_frequency") < 0) return false;
+    if (retrieveProgramFd("sched", "sched_process_free") < 0) return false;
+    return true;
+}
+
 // Start tracking and aggregating data to be reported by getUidCpuFreqTimes and getUidsCpuFreqTimes.
 // Returns true on success, false otherwise.
 // Tracking is active only once a live process has successfully called this function; if the calling
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index 46de669..4145374 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -22,6 +22,7 @@
 namespace android {
 namespace bpf {
 
+bool isTrackingUidTimesSupported();
 bool startTrackingUidTimes();
 std::optional<std::vector<std::vector<uint64_t>>> getTotalCpuFreqTimes();
 std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid);
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index d25b2e9..2112b10 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -40,6 +40,11 @@
 
 using std::vector;
 
+TEST(TimeInStateTest, IsTrackingSupported) {
+    isTrackingUidTimesSupported();
+    SUCCEED();
+}
+
 TEST(TimeInStateTest, TotalTimeInState) {
     auto times = getTotalCpuFreqTimes();
     ASSERT_TRUE(times.has_value());
diff --git a/libs/gralloc/types/Android.bp b/libs/gralloc/types/Android.bp
index 243d7f1..dd0ae30 100644
--- a/libs/gralloc/types/Android.bp
+++ b/libs/gralloc/types/Android.bp
@@ -43,14 +43,14 @@
     ],
 
     shared_libs: [
-        "android.hardware.graphics.common-unstable-ndk_platform",
+        "android.hardware.graphics.common-V2-ndk_platform",
         "android.hardware.graphics.mapper@4.0",
         "libhidlbase",
         "liblog",
     ],
 
     export_shared_lib_headers: [
-        "android.hardware.graphics.common-unstable-ndk_platform",
+        "android.hardware.graphics.common-V2-ndk_platform",
         "android.hardware.graphics.mapper@4.0",
         "libhidlbase",
     ],
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index c62d9ad..1e6fc2b 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -133,8 +133,10 @@
     if (enableTripleBuffering) {
         mProducer->setMaxDequeuedBufferCount(2);
     }
-    mBufferItemConsumer =
-        new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER, 1, false);
+    mBufferItemConsumer = new BLASTBufferItemConsumer(mConsumer,
+                                                      GraphicBuffer::USAGE_HW_COMPOSER |
+                                                              GraphicBuffer::USAGE_HW_TEXTURE,
+                                                      1, false);
     static int32_t id = 0;
     auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id);
     id++;
@@ -142,7 +144,7 @@
     mBufferItemConsumer->setFrameAvailableListener(this);
     mBufferItemConsumer->setBufferFreedListener(this);
     mBufferItemConsumer->setDefaultBufferSize(mSize.width, mSize.height);
-    mBufferItemConsumer->setDefaultBufferFormat(format);
+    mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
 
     mTransformHint = mSurfaceControl->getTransformHint();
     mBufferItemConsumer->setTransformHint(mTransformHint);
@@ -175,7 +177,7 @@
     std::unique_lock _lock{mMutex};
     if (mFormat != format) {
         mFormat = format;
-        mBufferItemConsumer->setDefaultBufferFormat(format);
+        mBufferItemConsumer->setDefaultBufferFormat(convertBufferFormat(format));
     }
 
     SurfaceComposerClient::Transaction t;
@@ -683,4 +685,18 @@
     *outConsumer = consumer;
 }
 
+PixelFormat BLASTBufferQueue::convertBufferFormat(PixelFormat& format) {
+    PixelFormat convertedFormat = format;
+    switch (format) {
+        case PIXEL_FORMAT_TRANSPARENT:
+        case PIXEL_FORMAT_TRANSLUCENT:
+            convertedFormat = PIXEL_FORMAT_RGBA_8888;
+            break;
+        case PIXEL_FORMAT_OPAQUE:
+            convertedFormat = PIXEL_FORMAT_RGBX_8888;
+            break;
+    }
+    return convertedFormat;
+}
+
 } // namespace android
diff --git a/libs/gui/DisplayEventDispatcher.cpp b/libs/gui/DisplayEventDispatcher.cpp
index 2ad484a..9cd3f63 100644
--- a/libs/gui/DisplayEventDispatcher.cpp
+++ b/libs/gui/DisplayEventDispatcher.cpp
@@ -36,9 +36,7 @@
 DisplayEventDispatcher::DisplayEventDispatcher(
         const sp<Looper>& looper, ISurfaceComposer::VsyncSource vsyncSource,
         ISurfaceComposer::EventRegistrationFlags eventRegistration)
-      : mLooper(looper),
-        mReceiver(vsyncSource, eventRegistration),
-        mVsyncState(VsyncState::Unregistered) {
+      : mLooper(looper), mReceiver(vsyncSource, eventRegistration), mWaitingForVsync(false) {
     ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
 }
 
@@ -68,37 +66,26 @@
 }
 
 status_t DisplayEventDispatcher::scheduleVsync() {
-    switch (mVsyncState) {
-        case VsyncState::Unregistered: {
-            ALOGV("dispatcher %p ~ Scheduling vsync.", this);
+    if (!mWaitingForVsync) {
+        ALOGV("dispatcher %p ~ Scheduling vsync.", this);
 
-            // Drain all pending events.
-            nsecs_t vsyncTimestamp;
-            PhysicalDisplayId vsyncDisplayId;
-            uint32_t vsyncCount;
-            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)));
-            }
+        // Drain all pending events.
+        nsecs_t vsyncTimestamp;
+        PhysicalDisplayId vsyncDisplayId;
+        uint32_t vsyncCount;
+        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)));
+        }
 
-            status_t status = mReceiver.setVsyncRate(1);
-            if (status) {
-                ALOGW("Failed to set vsync rate, status=%d", status);
-                return status;
-            }
+        status_t status = mReceiver.requestNextVsync();
+        if (status) {
+            ALOGW("Failed to request next vsync, status=%d", status);
+            return status;
+        }
 
-            mVsyncState = VsyncState::RegisteredAndWaitingForVsync;
-            break;
-        }
-        case VsyncState::Registered: {
-            mVsyncState = VsyncState::RegisteredAndWaitingForVsync;
-            break;
-        }
-        case VsyncState::RegisteredAndWaitingForVsync: {
-            break;
-        }
+        mWaitingForVsync = true;
     }
     return OK;
 }
@@ -136,23 +123,8 @@
               ", displayId=%s, count=%d, vsyncId=%" PRId64,
               this, ns2ms(vsyncTimestamp), to_string(vsyncDisplayId).c_str(), vsyncCount,
               vsyncEventData.id);
-        switch (mVsyncState) {
-            case VsyncState::Unregistered:
-                ALOGW("Received unexpected VSYNC event");
-                break;
-            case VsyncState::RegisteredAndWaitingForVsync:
-                mVsyncState = VsyncState::Registered;
-                dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
-                break;
-            case VsyncState::Registered:
-                status_t status = mReceiver.setVsyncRate(0);
-                if (status) {
-                    ALOGW("Failed to reset vsync rate, status=%d", status);
-                    return status;
-                }
-                mVsyncState = VsyncState::Unregistered;
-                break;
-        }
+        mWaitingForVsync = false;
+        dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount, vsyncEventData);
     }
 
     return 1; // keep the callback
@@ -184,9 +156,9 @@
                 case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
                     dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
                     break;
-                case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
-                    dispatchConfigChanged(ev.header.timestamp, ev.header.displayId,
-                                          ev.config.configId, ev.config.vsyncPeriod);
+                case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE:
+                    dispatchModeChanged(ev.header.timestamp, ev.header.displayId,
+                                        ev.modeChange.modeId, ev.modeChange.vsyncPeriod);
                     break;
                 case DisplayEventReceiver::DISPLAY_EVENT_NULL:
                     dispatchNullEvent(ev.header.timestamp, ev.header.displayId);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index f68f3e1..762746c 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -36,8 +36,8 @@
 
 #include <system/graphics.h>
 
-#include <ui/DisplayConfig.h>
 #include <ui/DisplayInfo.h>
+#include <ui/DisplayMode.h>
 #include <ui/DisplayStatInfo.h>
 #include <ui/DisplayState.h>
 #include <ui/HdrCapabilities.h>
@@ -333,20 +333,19 @@
         return reply.read(*info);
     }
 
-    status_t getDisplayConfigs(const sp<IBinder>& display,
-                               Vector<DisplayConfig>* configs) override {
+    status_t getDisplayModes(const sp<IBinder>& display, Vector<ui::DisplayMode>* modes) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
-        remote()->transact(BnSurfaceComposer::GET_DISPLAY_CONFIGS, data, &reply);
+        remote()->transact(BnSurfaceComposer::GET_DISPLAY_MODES, data, &reply);
         const status_t result = reply.readInt32();
         if (result == NO_ERROR) {
-            const size_t numConfigs = reply.readUint32();
-            configs->clear();
-            configs->resize(numConfigs);
-            for (size_t c = 0; c < numConfigs; ++c) {
-                memcpy(&(configs->editItemAt(c)), reply.readInplace(sizeof(DisplayConfig)),
-                       sizeof(DisplayConfig));
+            const size_t numModes = reply.readUint32();
+            modes->clear();
+            modes->resize(numModes);
+            for (size_t i = 0; i < numModes; i++) {
+                memcpy(&(modes->editItemAt(i)), reply.readInplace(sizeof(ui::DisplayMode)),
+                       sizeof(ui::DisplayMode));
             }
         }
         return result;
@@ -366,11 +365,11 @@
         return result;
     }
 
-    int getActiveConfig(const sp<IBinder>& display) override {
+    int getActiveDisplayModeId(const sp<IBinder>& display) override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
-        remote()->transact(BnSurfaceComposer::GET_ACTIVE_CONFIG, data, &reply);
+        remote()->transact(BnSurfaceComposer::GET_ACTIVE_DISPLAY_MODE, data, &reply);
         return reply.readInt32();
     }
 
@@ -882,71 +881,70 @@
         return error;
     }
 
-    status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, int32_t defaultConfig,
-                                          bool allowGroupSwitching, float primaryRefreshRateMin,
-                                          float primaryRefreshRateMax,
-                                          float appRequestRefreshRateMin,
-                                          float appRequestRefreshRateMax) override {
+    status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, size_t defaultMode,
+                                        bool allowGroupSwitching, float primaryRefreshRateMin,
+                                        float primaryRefreshRateMax, float appRequestRefreshRateMin,
+                                        float appRequestRefreshRateMax) override {
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayConfigSpecs: failed to writeInterfaceToken: %d", result);
+            ALOGE("setDesiredDisplayModeSpecs: failed to writeInterfaceToken: %d", result);
             return result;
         }
         result = data.writeStrongBinder(displayToken);
         if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayConfigSpecs: failed to write display token: %d", result);
+            ALOGE("setDesiredDisplayModeSpecs: failed to write display token: %d", result);
             return result;
         }
-        result = data.writeInt32(defaultConfig);
+        result = data.writeInt32(defaultMode);
         if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayConfigSpecs failed to write defaultConfig: %d", result);
+            ALOGE("setDesiredDisplayModeSpecs failed to write defaultMode: %d", result);
             return result;
         }
         result = data.writeBool(allowGroupSwitching);
         if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayConfigSpecs failed to write allowGroupSwitching: %d", result);
+            ALOGE("setDesiredDisplayModeSpecs failed to write allowGroupSwitching: %d", result);
             return result;
         }
         result = data.writeFloat(primaryRefreshRateMin);
         if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMin: %d", result);
+            ALOGE("setDesiredDisplayModeSpecs failed to write primaryRefreshRateMin: %d", result);
             return result;
         }
         result = data.writeFloat(primaryRefreshRateMax);
         if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayConfigSpecs failed to write primaryRefreshRateMax: %d", result);
+            ALOGE("setDesiredDisplayModeSpecs failed to write primaryRefreshRateMax: %d", result);
             return result;
         }
         result = data.writeFloat(appRequestRefreshRateMin);
         if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMin: %d",
+            ALOGE("setDesiredDisplayModeSpecs failed to write appRequestRefreshRateMin: %d",
                   result);
             return result;
         }
         result = data.writeFloat(appRequestRefreshRateMax);
         if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayConfigSpecs failed to write appRequestRefreshRateMax: %d",
+            ALOGE("setDesiredDisplayModeSpecs failed to write appRequestRefreshRateMax: %d",
                   result);
             return result;
         }
 
-        result = remote()->transact(BnSurfaceComposer::SET_DESIRED_DISPLAY_CONFIG_SPECS, data,
-                                    &reply);
+        result =
+                remote()->transact(BnSurfaceComposer::SET_DESIRED_DISPLAY_MODE_SPECS, data, &reply);
         if (result != NO_ERROR) {
-            ALOGE("setDesiredDisplayConfigSpecs failed to transact: %d", result);
+            ALOGE("setDesiredDisplayModeSpecs failed to transact: %d", result);
             return result;
         }
         return reply.readInt32();
     }
 
-    status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                          int32_t* outDefaultConfig, bool* outAllowGroupSwitching,
-                                          float* outPrimaryRefreshRateMin,
-                                          float* outPrimaryRefreshRateMax,
-                                          float* outAppRequestRefreshRateMin,
-                                          float* outAppRequestRefreshRateMax) override {
-        if (!outDefaultConfig || !outAllowGroupSwitching || !outPrimaryRefreshRateMin ||
+    status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, size_t* outDefaultMode,
+                                        bool* outAllowGroupSwitching,
+                                        float* outPrimaryRefreshRateMin,
+                                        float* outPrimaryRefreshRateMax,
+                                        float* outAppRequestRefreshRateMin,
+                                        float* outAppRequestRefreshRateMax) override {
+        if (!outDefaultMode || !outAllowGroupSwitching || !outPrimaryRefreshRateMin ||
             !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin ||
             !outAppRequestRefreshRateMax) {
             return BAD_VALUE;
@@ -954,50 +952,55 @@
         Parcel data, reply;
         status_t result = data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to writeInterfaceToken: %d", result);
+            ALOGE("getDesiredDisplayModeSpecs failed to writeInterfaceToken: %d", result);
             return result;
         }
         result = data.writeStrongBinder(displayToken);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to writeStrongBinder: %d", result);
+            ALOGE("getDesiredDisplayModeSpecs failed to writeStrongBinder: %d", result);
             return result;
         }
-        result = remote()->transact(BnSurfaceComposer::GET_DESIRED_DISPLAY_CONFIG_SPECS, data,
-                                    &reply);
+        result =
+                remote()->transact(BnSurfaceComposer::GET_DESIRED_DISPLAY_MODE_SPECS, data, &reply);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to transact: %d", result);
+            ALOGE("getDesiredDisplayModeSpecs failed to transact: %d", result);
             return result;
         }
-        result = reply.readInt32(outDefaultConfig);
+        int32_t defaultMode;
+        result = reply.readInt32(&defaultMode);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to read defaultConfig: %d", result);
+            ALOGE("getDesiredDisplayModeSpecs failed to read defaultMode: %d", result);
             return result;
         }
+        if (defaultMode < 0) {
+            ALOGE("%s: defaultMode must be non-negative but it was %d", __func__, defaultMode);
+            return BAD_VALUE;
+        }
+        *outDefaultMode = static_cast<size_t>(defaultMode);
+
         result = reply.readBool(outAllowGroupSwitching);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to read allowGroupSwitching: %d", result);
+            ALOGE("getDesiredDisplayModeSpecs failed to read allowGroupSwitching: %d", result);
             return result;
         }
         result = reply.readFloat(outPrimaryRefreshRateMin);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMin: %d", result);
+            ALOGE("getDesiredDisplayModeSpecs failed to read primaryRefreshRateMin: %d", result);
             return result;
         }
         result = reply.readFloat(outPrimaryRefreshRateMax);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to read primaryRefreshRateMax: %d", result);
+            ALOGE("getDesiredDisplayModeSpecs failed to read primaryRefreshRateMax: %d", result);
             return result;
         }
         result = reply.readFloat(outAppRequestRefreshRateMin);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMin: %d",
-                  result);
+            ALOGE("getDesiredDisplayModeSpecs failed to read appRequestRefreshRateMin: %d", result);
             return result;
         }
         result = reply.readFloat(outAppRequestRefreshRateMax);
         if (result != NO_ERROR) {
-            ALOGE("getDesiredDisplayConfigSpecs failed to read appRequestRefreshRateMax: %d",
-                  result);
+            ALOGE("getDesiredDisplayModeSpecs failed to read appRequestRefreshRateMax: %d", result);
             return result;
         }
         return reply.readInt32();
@@ -1232,6 +1235,18 @@
         }
         return reply.readInt32();
     }
+
+    status_t getExtraBufferCount(int* extraBuffers) const override {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        status_t err = remote()->transact(BnSurfaceComposer::GET_EXTRA_BUFFER_COUNT, data, &reply);
+        if (err != NO_ERROR) {
+            ALOGE("getExtraBufferCount failed to read data:  %s (%d)", strerror(-err), err);
+            return err;
+        }
+
+        return reply.readInt32(extraBuffers);
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -1430,17 +1445,17 @@
             if (result != NO_ERROR) return result;
             return reply->write(info);
         }
-        case GET_DISPLAY_CONFIGS: {
+        case GET_DISPLAY_MODES: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
-            Vector<DisplayConfig> configs;
+            Vector<ui::DisplayMode> modes;
             const sp<IBinder> display = data.readStrongBinder();
-            const status_t result = getDisplayConfigs(display, &configs);
+            const status_t result = getDisplayModes(display, &modes);
             reply->writeInt32(result);
             if (result == NO_ERROR) {
-                reply->writeUint32(static_cast<uint32_t>(configs.size()));
-                for (size_t c = 0; c < configs.size(); ++c) {
-                    memcpy(reply->writeInplace(sizeof(DisplayConfig)), &configs[c],
-                           sizeof(DisplayConfig));
+                reply->writeUint32(static_cast<uint32_t>(modes.size()));
+                for (size_t i = 0; i < modes.size(); i++) {
+                    memcpy(reply->writeInplace(sizeof(ui::DisplayMode)), &modes[i],
+                           sizeof(ui::DisplayMode));
                 }
             }
             return NO_ERROR;
@@ -1457,10 +1472,10 @@
             }
             return NO_ERROR;
         }
-        case GET_ACTIVE_CONFIG: {
+        case GET_ACTIVE_DISPLAY_MODE: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> display = data.readStrongBinder();
-            int id = getActiveConfig(display);
+            int id = getActiveDisplayModeId(display);
             reply->writeInt32(id);
             return NO_ERROR;
         }
@@ -1844,56 +1859,59 @@
             }
             return removeRegionSamplingListener(listener);
         }
-        case SET_DESIRED_DISPLAY_CONFIG_SPECS: {
+        case SET_DESIRED_DISPLAY_MODE_SPECS: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> displayToken = data.readStrongBinder();
-            int32_t defaultConfig;
-            status_t result = data.readInt32(&defaultConfig);
+            int32_t defaultMode;
+            status_t result = data.readInt32(&defaultMode);
             if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayConfigSpecs: failed to read defaultConfig: %d", result);
+                ALOGE("setDesiredDisplayModeSpecs: failed to read defaultMode: %d", result);
                 return result;
             }
+            if (defaultMode < 0) {
+                ALOGE("%s: defaultMode must be non-negative but it was %d", __func__, defaultMode);
+                return BAD_VALUE;
+            }
             bool allowGroupSwitching;
             result = data.readBool(&allowGroupSwitching);
             if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayConfigSpecs: failed to read allowGroupSwitching: %d",
-                      result);
+                ALOGE("setDesiredDisplayModeSpecs: failed to read allowGroupSwitching: %d", result);
                 return result;
             }
             float primaryRefreshRateMin;
             result = data.readFloat(&primaryRefreshRateMin);
             if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayConfigSpecs: failed to read primaryRefreshRateMin: %d",
+                ALOGE("setDesiredDisplayModeSpecs: failed to read primaryRefreshRateMin: %d",
                       result);
                 return result;
             }
             float primaryRefreshRateMax;
             result = data.readFloat(&primaryRefreshRateMax);
             if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayConfigSpecs: failed to read primaryRefreshRateMax: %d",
+                ALOGE("setDesiredDisplayModeSpecs: failed to read primaryRefreshRateMax: %d",
                       result);
                 return result;
             }
             float appRequestRefreshRateMin;
             result = data.readFloat(&appRequestRefreshRateMin);
             if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayConfigSpecs: failed to read appRequestRefreshRateMin: %d",
+                ALOGE("setDesiredDisplayModeSpecs: failed to read appRequestRefreshRateMin: %d",
                       result);
                 return result;
             }
             float appRequestRefreshRateMax;
             result = data.readFloat(&appRequestRefreshRateMax);
             if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayConfigSpecs: failed to read appRequestRefreshRateMax: %d",
+                ALOGE("setDesiredDisplayModeSpecs: failed to read appRequestRefreshRateMax: %d",
                       result);
                 return result;
             }
-            result = setDesiredDisplayConfigSpecs(displayToken, defaultConfig, allowGroupSwitching,
-                                                  primaryRefreshRateMin, primaryRefreshRateMax,
-                                                  appRequestRefreshRateMin,
-                                                  appRequestRefreshRateMax);
+            result = setDesiredDisplayModeSpecs(displayToken, static_cast<size_t>(defaultMode),
+                                                allowGroupSwitching, primaryRefreshRateMin,
+                                                primaryRefreshRateMax, appRequestRefreshRateMin,
+                                                appRequestRefreshRateMax);
             if (result != NO_ERROR) {
-                ALOGE("setDesiredDisplayConfigSpecs: failed to call setDesiredDisplayConfigSpecs: "
+                ALOGE("setDesiredDisplayModeSpecs: failed to call setDesiredDisplayModeSpecs: "
                       "%d",
                       result);
                 return result;
@@ -1901,10 +1919,10 @@
             reply->writeInt32(result);
             return result;
         }
-        case GET_DESIRED_DISPLAY_CONFIG_SPECS: {
+        case GET_DESIRED_DISPLAY_MODE_SPECS: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             sp<IBinder> displayToken = data.readStrongBinder();
-            int32_t defaultConfig;
+            size_t defaultMode;
             bool allowGroupSwitching;
             float primaryRefreshRateMin;
             float primaryRefreshRateMax;
@@ -1912,49 +1930,49 @@
             float appRequestRefreshRateMax;
 
             status_t result =
-                    getDesiredDisplayConfigSpecs(displayToken, &defaultConfig, &allowGroupSwitching,
-                                                 &primaryRefreshRateMin, &primaryRefreshRateMax,
-                                                 &appRequestRefreshRateMin,
-                                                 &appRequestRefreshRateMax);
+                    getDesiredDisplayModeSpecs(displayToken, &defaultMode, &allowGroupSwitching,
+                                               &primaryRefreshRateMin, &primaryRefreshRateMax,
+                                               &appRequestRefreshRateMin,
+                                               &appRequestRefreshRateMax);
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to get getDesiredDisplayConfigSpecs: "
+                ALOGE("getDesiredDisplayModeSpecs: failed to get getDesiredDisplayModeSpecs: "
                       "%d",
                       result);
                 return result;
             }
 
-            result = reply->writeInt32(defaultConfig);
+            result = reply->writeInt32(static_cast<int32_t>(defaultMode));
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to write defaultConfig: %d", result);
+                ALOGE("getDesiredDisplayModeSpecs: failed to write defaultMode: %d", result);
                 return result;
             }
             result = reply->writeBool(allowGroupSwitching);
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to write allowGroupSwitching: %d",
+                ALOGE("getDesiredDisplayModeSpecs: failed to write allowGroupSwitching: %d",
                       result);
                 return result;
             }
             result = reply->writeFloat(primaryRefreshRateMin);
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMin: %d",
+                ALOGE("getDesiredDisplayModeSpecs: failed to write primaryRefreshRateMin: %d",
                       result);
                 return result;
             }
             result = reply->writeFloat(primaryRefreshRateMax);
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to write primaryRefreshRateMax: %d",
+                ALOGE("getDesiredDisplayModeSpecs: failed to write primaryRefreshRateMax: %d",
                       result);
                 return result;
             }
             result = reply->writeFloat(appRequestRefreshRateMin);
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMin: %d",
+                ALOGE("getDesiredDisplayModeSpecs: failed to write appRequestRefreshRateMin: %d",
                       result);
                 return result;
             }
             result = reply->writeFloat(appRequestRefreshRateMax);
             if (result != NO_ERROR) {
-                ALOGE("getDesiredDisplayConfigSpecs: failed to write appRequestRefreshRateMax: %d",
+                ALOGE("getDesiredDisplayModeSpecs: failed to write appRequestRefreshRateMax: %d",
                       result);
                 return result;
             }
@@ -2101,6 +2119,16 @@
             SAFE_PARCEL(reply->writeInt32, priority);
             return NO_ERROR;
         }
+        case GET_EXTRA_BUFFER_COUNT: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            int extraBuffers = 0;
+            int err = getExtraBufferCount(&extraBuffers);
+            if (err != NO_ERROR) {
+                return err;
+            }
+            SAFE_PARCEL(reply->writeInt32, extraBuffers);
+            return NO_ERROR;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index fff3305..f053372 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -167,6 +167,9 @@
         SAFE_PARCEL(output.writeInt32, region.right);
         SAFE_PARCEL(output.writeInt32, region.bottom);
     }
+
+    SAFE_PARCEL(output.write, stretchEffect);
+
     return NO_ERROR;
 }
 
@@ -290,6 +293,9 @@
         SAFE_PARCEL(input.readInt32, &region.bottom);
         blurRegions.push_back(region);
     }
+
+    SAFE_PARCEL(input.read, stretchEffect);
+
     return NO_ERROR;
 }
 
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index 1667fb0..45c958e 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -1,5 +1,4 @@
 adyabr@google.com
-akrulec@google.com
 alecmouri@google.com
 chaviw@google.com
 chrisforbes@google.com
@@ -7,7 +6,6 @@
 lpy@google.com
 mathias@google.com
 racarr@google.com
-stoza@google.com
 vishnun@google.com
 
 per-file EndToEndNativeInputTest.cpp = svv@google.com
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 59ad8d2..07fc069 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -1499,6 +1499,9 @@
     case NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO:
         res = dispatchSetFrameTimelineInfo(args);
         break;
+    case NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT:
+        res = dispatchGetExtraBufferCount(args);
+        break;
     default:
         res = NAME_NOT_FOUND;
         break;
@@ -1815,6 +1818,14 @@
     return setFrameTimelineInfo({frameTimelineVsyncId, inputEventId});
 }
 
+int Surface::dispatchGetExtraBufferCount(va_list args) {
+    ATRACE_CALL();
+    auto extraBuffers = static_cast<int*>(va_arg(args, int*));
+
+    ALOGV("Surface::dispatchGetExtraBufferCount");
+    return getExtraBufferCount(extraBuffers);
+}
+
 bool Surface::transformToDisplayInverse() {
     return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
             NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
@@ -2584,4 +2595,8 @@
     return composerService()->setFrameTimelineInfo(mGraphicBufferProducer, frameTimelineInfo);
 }
 
+status_t Surface::getExtraBufferCount(int* extraBuffers) const {
+    return composerService()->getExtraBufferCount(extraBuffers);
+}
+
 }; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 550803d..27fb2a8 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -39,7 +39,7 @@
 #include <gui/LayerState.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 
 #ifndef NO_INPUT
 #include <input/InputWindow.h>
@@ -1569,6 +1569,23 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setStretchEffect(
+        const sp<SurfaceControl>& sc, float left, float top, float right, float bottom, float vecX,
+        float vecY, float maxAmount) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+
+    s->what |= layer_state_t::eStretchChanged;
+    s->stretchEffect = StretchEffect{.area = {left, top, right, bottom},
+                                     .vectorX = vecX,
+                                     .vectorY = vecY,
+                                     .maxAmount = maxAmount};
+    return *this;
+}
+
 // ---------------------------------------------------------------------------
 
 DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
@@ -1802,52 +1819,51 @@
     return ComposerService::getComposerService()->getDisplayInfo(display, info);
 }
 
-status_t SurfaceComposerClient::getDisplayConfigs(const sp<IBinder>& display,
-                                                  Vector<DisplayConfig>* configs) {
-    return ComposerService::getComposerService()->getDisplayConfigs(display, configs);
+status_t SurfaceComposerClient::getDisplayModes(const sp<IBinder>& display,
+                                                Vector<ui::DisplayMode>* modes) {
+    return ComposerService::getComposerService()->getDisplayModes(display, modes);
 }
 
-status_t SurfaceComposerClient::getActiveDisplayConfig(const sp<IBinder>& display,
-                                                       DisplayConfig* config) {
-    Vector<DisplayConfig> configs;
-    status_t result = getDisplayConfigs(display, &configs);
+status_t SurfaceComposerClient::getActiveDisplayMode(const sp<IBinder>& display,
+                                                     ui::DisplayMode* mode) {
+    Vector<ui::DisplayMode> modes;
+    status_t result = getDisplayModes(display, &modes);
     if (result != NO_ERROR) {
         return result;
     }
 
-    int activeId = getActiveConfig(display);
+    int activeId = getActiveDisplayModeId(display);
     if (activeId < 0) {
-        ALOGE("No active configuration found");
+        ALOGE("No active mode found");
         return NAME_NOT_FOUND;
     }
 
-    *config = configs[static_cast<size_t>(activeId)];
+    *mode = modes[static_cast<size_t>(activeId)];
     return NO_ERROR;
 }
 
-int SurfaceComposerClient::getActiveConfig(const sp<IBinder>& display) {
-    return ComposerService::getComposerService()->getActiveConfig(display);
+int SurfaceComposerClient::getActiveDisplayModeId(const sp<IBinder>& display) {
+    return ComposerService::getComposerService()->getActiveDisplayModeId(display);
 }
 
-status_t SurfaceComposerClient::setDesiredDisplayConfigSpecs(
-        const sp<IBinder>& displayToken, int32_t defaultConfig, bool allowGroupSwitching,
+status_t SurfaceComposerClient::setDesiredDisplayModeSpecs(
+        const sp<IBinder>& displayToken, size_t defaultMode, bool allowGroupSwitching,
         float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin,
         float appRequestRefreshRateMax) {
     return ComposerService::getComposerService()
-            ->setDesiredDisplayConfigSpecs(displayToken, defaultConfig, allowGroupSwitching,
-                                           primaryRefreshRateMin, primaryRefreshRateMax,
-                                           appRequestRefreshRateMin, appRequestRefreshRateMax);
+            ->setDesiredDisplayModeSpecs(displayToken, defaultMode, allowGroupSwitching,
+                                         primaryRefreshRateMin, primaryRefreshRateMax,
+                                         appRequestRefreshRateMin, appRequestRefreshRateMax);
 }
 
-status_t SurfaceComposerClient::getDesiredDisplayConfigSpecs(
-        const sp<IBinder>& displayToken, int32_t* outDefaultConfig, bool* outAllowGroupSwitching,
+status_t SurfaceComposerClient::getDesiredDisplayModeSpecs(
+        const sp<IBinder>& displayToken, size_t* outDefaultMode, bool* outAllowGroupSwitching,
         float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax,
         float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) {
     return ComposerService::getComposerService()
-            ->getDesiredDisplayConfigSpecs(displayToken, outDefaultConfig, outAllowGroupSwitching,
-                                           outPrimaryRefreshRateMin, outPrimaryRefreshRateMax,
-                                           outAppRequestRefreshRateMin,
-                                           outAppRequestRefreshRateMax);
+            ->getDesiredDisplayModeSpecs(displayToken, outDefaultMode, outAllowGroupSwitching,
+                                         outPrimaryRefreshRateMin, outPrimaryRefreshRateMax,
+                                         outAppRequestRefreshRateMin, outAppRequestRefreshRateMax);
 }
 
 status_t SurfaceComposerClient::getDisplayColorModes(const sp<IBinder>& display,
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index fa3efe1..bccb71b 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -110,6 +110,7 @@
     // Return true if we need to reject the buffer based on the scaling mode and the buffer size.
     bool rejectBuffer(const BufferItem& item) REQUIRES(mMutex);
     bool maxBuffersAcquired(bool includeExtraAcquire) const REQUIRES(mMutex);
+    static PixelFormat convertBufferFormat(PixelFormat& format);
 
     std::string mName;
     sp<SurfaceControl> mSurfaceControl;
diff --git a/libs/gui/include/gui/DisplayEventDispatcher.h b/libs/gui/include/gui/DisplayEventDispatcher.h
index 4175a49..d74c2ba 100644
--- a/libs/gui/include/gui/DisplayEventDispatcher.h
+++ b/libs/gui/include/gui/DisplayEventDispatcher.h
@@ -52,20 +52,7 @@
 private:
     sp<Looper> mLooper;
     DisplayEventReceiver mReceiver;
-    // The state of vsync event registration and whether the client is expecting
-    // an event or not.
-    enum class VsyncState {
-        // The dispatcher is not registered for vsync events.
-        Unregistered,
-        // The dispatcher is registered to receive vsync events but should not dispatch it to the
-        // client as the client is not expecting a vsync event.
-        Registered,
-
-        // The dispatcher is registered to receive vsync events and supposed to dispatch it to
-        // the client.
-        RegisteredAndWaitingForVsync,
-    };
-    VsyncState mVsyncState;
+    bool mWaitingForVsync;
 
     std::vector<FrameRateOverride> mFrameRateOverrides;
 
@@ -73,8 +60,8 @@
                                VsyncEventData vsyncEventData) = 0;
     virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
                                  bool connected) = 0;
-    virtual void dispatchConfigChanged(nsecs_t timestamp, PhysicalDisplayId displayId,
-                                       int32_t configId, nsecs_t vsyncPeriod) = 0;
+    virtual void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
+                                     nsecs_t vsyncPeriod) = 0;
     // AChoreographer-specific hook for processing null-events so that looper
     // can be properly poked.
     virtual void dispatchNullEvent(nsecs_t timestamp, PhysicalDisplayId displayId) = 0;
diff --git a/libs/gui/include/gui/DisplayEventReceiver.h b/libs/gui/include/gui/DisplayEventReceiver.h
index 3191fc9..7179a20 100644
--- a/libs/gui/include/gui/DisplayEventReceiver.h
+++ b/libs/gui/include/gui/DisplayEventReceiver.h
@@ -52,7 +52,7 @@
     enum {
         DISPLAY_EVENT_VSYNC = fourcc('v', 's', 'y', 'n'),
         DISPLAY_EVENT_HOTPLUG = fourcc('p', 'l', 'u', 'g'),
-        DISPLAY_EVENT_CONFIG_CHANGED = fourcc('c', 'o', 'n', 'f'),
+        DISPLAY_EVENT_MODE_CHANGE = fourcc('m', 'o', 'd', 'e'),
         DISPLAY_EVENT_NULL = fourcc('n', 'u', 'l', 'l'),
         DISPLAY_EVENT_FRAME_RATE_OVERRIDE = fourcc('r', 'a', 't', 'e'),
         DISPLAY_EVENT_FRAME_RATE_OVERRIDE_FLUSH = fourcc('f', 'l', 's', 'h'),
@@ -82,8 +82,8 @@
             bool connected;
         };
 
-        struct Config {
-            int32_t configId;
+        struct ModeChange {
+            int32_t modeId;
             nsecs_t vsyncPeriod __attribute__((aligned(8)));
         };
 
@@ -96,7 +96,7 @@
         union {
             VSync vsync;
             Hotplug hotplug;
-            Config config;
+            ModeChange modeChange;
             FrameRateOverride frameRateOverride;
         };
     };
@@ -106,7 +106,7 @@
      * DisplayEventReceiver creates and registers an event connection with
      * SurfaceFlinger. VSync events are disabled by default. Call setVSyncRate
      * or requestNextVsync to receive them.
-     * To receive ConfigChanged and/or FrameRateOverrides events specify this in
+     * To receive ModeChanged and/or FrameRateOverrides events specify this in
      * the constructor. Other events start being delivered immediately.
      */
     explicit DisplayEventReceiver(
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 81ff6b0..292838e 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -54,7 +54,6 @@
 struct client_cache_t;
 struct ComposerState;
 struct DisplayCaptureArgs;
-struct DisplayConfig;
 struct DisplayInfo;
 struct DisplayStatInfo;
 struct DisplayState;
@@ -73,6 +72,7 @@
 
 namespace ui {
 
+struct DisplayMode;
 struct DisplayState;
 
 } // namespace ui
@@ -112,7 +112,7 @@
     };
 
     enum class EventRegistration {
-        configChanged = 1 << 0,
+        modeChanged = 1 << 0,
         frameRateOverride = 1 << 1,
     };
 
@@ -207,15 +207,15 @@
     virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo*) = 0;
 
     /**
-     * Get configurations supported by given physical display.
+     * Get modes supported by given physical display.
      */
-    virtual status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>*) = 0;
+    virtual status_t getDisplayModes(const sp<IBinder>& display, Vector<ui::DisplayMode>*) = 0;
 
     /**
-     * Get the index into configurations returned by getDisplayConfigs,
-     * corresponding to the active configuration.
+     * Get the index into modes returned by getDisplayModes,
+     * corresponding to the active mode.
      */
-    virtual int getActiveConfig(const sp<IBinder>& display) = 0;
+    virtual int getActiveDisplayModeId(const sp<IBinder>& display) = 0;
 
     virtual status_t getDisplayColorModes(const sp<IBinder>& display,
             Vector<ui::ColorMode>* outColorModes) = 0;
@@ -386,34 +386,31 @@
     /* Sets the refresh rate boundaries for the display.
      *
      * 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
+     * modes we'll consider when switching refresh rates. Unless we get an explicit signal from an
      * app, we should stay within this range.
      *
-     * The app request refresh rate range allows us to consider more display configs when switching
+     * The app request refresh rate range allows us to consider more display modes when switching
      * refresh rates. Although we should generally stay within the primary range, specific
      * considerations, such as layer frame rate settings specified via the setFrameRate() api, may
      * cause us to go outside the primary range. We never go outside the app request range. The app
      * request range will be greater than or equal to the primary refresh rate range, never smaller.
      *
-     * defaultConfig is used to narrow the list of display configs SurfaceFlinger will consider
-     * switching between. Only configs with a config group and resolution matching defaultConfig
-     * will be considered for switching. The defaultConfig index corresponds to the list of configs
-     * returned from getDisplayConfigs().
+     * defaultMode is used to narrow the list of display modes SurfaceFlinger will consider
+     * switching between. Only modes with a mode group and resolution matching defaultMode
+     * will be considered for switching. The defaultMode index corresponds to the list of modes
+     * returned from getDisplayModes().
      */
-    virtual status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                  int32_t defaultConfig, bool allowGroupSwitching,
-                                                  float primaryRefreshRateMin,
-                                                  float primaryRefreshRateMax,
-                                                  float appRequestRefreshRateMin,
-                                                  float appRequestRefreshRateMax) = 0;
+    virtual status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, size_t defaultMode,
+                                                bool allowGroupSwitching,
+                                                float primaryRefreshRateMin,
+                                                float primaryRefreshRateMax,
+                                                float appRequestRefreshRateMin,
+                                                float appRequestRefreshRateMax) = 0;
 
-    virtual status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                  int32_t* outDefaultConfig,
-                                                  bool* outAllowGroupSwitching,
-                                                  float* outPrimaryRefreshRateMin,
-                                                  float* outPrimaryRefreshRateMax,
-                                                  float* outAppRequestRefreshRateMin,
-                                                  float* outAppRequestRefreshRateMax) = 0;
+    virtual status_t getDesiredDisplayModeSpecs(
+            const sp<IBinder>& displayToken, size_t* outDefaultMode, bool* outAllowGroupSwitching,
+            float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax,
+            float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) = 0;
     /*
      * Gets whether brightness operations are supported on a display.
      *
@@ -508,6 +505,24 @@
      * Gets priority of the RenderEngine in SurfaceFlinger.
      */
     virtual int getGPUContextPriority() = 0;
+
+    /**
+     * Gets the extra buffers a client would need to allocate if it passes
+     * the Choreographer#getVsyncId with its buffers.
+     *
+     * When Choreographer#getVsyncId is passed to SurfaceFlinger, it is used
+     * as an indication of when to latch the buffer. SurfaceFlinger will make
+     * sure that it will give the app at least the time configured as the
+     * 'appDuration' before trying to latch the buffer.
+     *
+     * The total buffers needed for a given configuration is basically the
+     * numbers of vsyncs a single buffer is used across the stack. For the default
+     * configuration a buffer is held ~1 vsync by the app, ~1 vsync by SurfaceFlinger
+     * and 1 vsync by the display. The extra buffers are calculated as the
+     * number of additional buffers on top of the 3 buffers already allocated
+     * by the app.
+     */
+    virtual status_t getExtraBufferCount(int* extraBuffers) const = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -527,8 +542,8 @@
         SET_TRANSACTION_STATE,
         AUTHENTICATE_SURFACE,
         GET_SUPPORTED_FRAME_TIMESTAMPS,
-        GET_DISPLAY_CONFIGS,
-        GET_ACTIVE_CONFIG,
+        GET_DISPLAY_MODES,
+        GET_ACTIVE_DISPLAY_MODE,
         GET_DISPLAY_STATE,
         CAPTURE_DISPLAY,
         CAPTURE_LAYERS,
@@ -554,8 +569,8 @@
         GET_PHYSICAL_DISPLAY_IDS,
         ADD_REGION_SAMPLING_LISTENER,
         REMOVE_REGION_SAMPLING_LISTENER,
-        SET_DESIRED_DISPLAY_CONFIG_SPECS,
-        GET_DESIRED_DISPLAY_CONFIG_SPECS,
+        SET_DESIRED_DISPLAY_MODE_SPECS,
+        GET_DESIRED_DISPLAY_MODE_SPECS,
         GET_DISPLAY_BRIGHTNESS_SUPPORT,
         SET_DISPLAY_BRIGHTNESS,
         CAPTURE_DISPLAY_BY_ID,
@@ -570,6 +585,7 @@
         SET_FRAME_TIMELINE_INFO,
         ADD_TRANSACTION_TRACE_LISTENER,
         GET_GPU_CONTEXT_PRIORITY,
+        GET_EXTRA_BUFFER_COUNT,
         // Always append new enum to the end.
     };
 
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index 2f9a0c0..b273805 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -56,6 +56,7 @@
 #include <ui/Rect.h>
 #include <ui/Region.h>
 #include <ui/Rotation.h>
+#include <ui/StretchEffect.h>
 #include <ui/Transform.h>
 #include <utils/Errors.h>
 
@@ -135,6 +136,7 @@
         eFrameTimelineInfoChanged = 0x800'00000000,
         eBlurRegionsChanged = 0x1000'00000000,
         eAutoRefreshChanged = 0x2000'00000000,
+        eStretchChanged = 0x4000'00000000,
     };
 
     layer_state_t();
@@ -244,6 +246,9 @@
     // can and not wait for a frame to become available. This is only relevant
     // in shared buffer mode.
     bool autoRefresh;
+
+    // Stretch effect to be applied to this layer
+    StretchEffect stretchEffect;
 };
 
 struct ComposerState {
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index b6b5c7c..5881221 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -189,6 +189,7 @@
 
     virtual status_t setFrameRate(float frameRate, int8_t compatibility, bool shouldBeSeamless);
     virtual status_t setFrameTimelineInfo(const FrameTimelineInfo& info);
+    virtual status_t getExtraBufferCount(int* extraBuffers) const;
 
 protected:
     virtual ~Surface();
@@ -275,6 +276,7 @@
     int dispatchAddQueryInterceptor(va_list args);
     int dispatchGetLastQueuedBuffer(va_list args);
     int dispatchSetFrameTimelineInfo(va_list args);
+    int dispatchGetExtraBufferCount(va_list args);
     bool transformToDisplayInverse();
 
 protected:
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index e7abfe6..e89f3a7 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -110,30 +110,29 @@
     // Get immutable information about given physical display.
     static status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo*);
 
-    // Get configurations supported by given physical display.
-    static status_t getDisplayConfigs(const sp<IBinder>& display, Vector<DisplayConfig>*);
+    // Get modes supported by given physical display.
+    static status_t getDisplayModes(const sp<IBinder>& display, Vector<ui::DisplayMode>*);
 
-    // Get the ID of the active DisplayConfig, as getDisplayConfigs index.
-    static int getActiveConfig(const sp<IBinder>& display);
+    // Get the ID of the active DisplayMode, as getDisplayModes index.
+    static int getActiveDisplayModeId(const sp<IBinder>& display);
 
-    // Shorthand for getDisplayConfigs element at getActiveConfig index.
-    static status_t getActiveDisplayConfig(const sp<IBinder>& display, DisplayConfig*);
+    // Shorthand for getDisplayModes element at getActiveDisplayModeId index.
+    static status_t getActiveDisplayMode(const sp<IBinder>& display, ui::DisplayMode*);
 
     // Sets the refresh rate boundaries for the display.
-    static status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                                 int32_t defaultConfig, bool allowGroupSwitching,
-                                                 float primaryRefreshRateMin,
-                                                 float primaryRefreshRateMax,
-                                                 float appRequestRefreshRateMin,
-                                                 float appRequestRefreshRateMax);
+    static status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, size_t defaultMode,
+                                               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,
-                                                 float* outAppRequestRefreshRateMax);
+    static status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+                                               size_t* outDefaultMode, bool* outAllowGroupSwitching,
+                                               float* outPrimaryRefreshRateMin,
+                                               float* outPrimaryRefreshRateMax,
+                                               float* outAppRequestRefreshRateMin,
+                                               float* outAppRequestRefreshRateMax);
 
     // Gets the list of supported color modes for the given display
     static status_t getDisplayColorModes(const sp<IBinder>& display,
@@ -551,6 +550,10 @@
         // transactions from blocking each other.
         Transaction& setApplyToken(const sp<IBinder>& token);
 
+        Transaction& setStretchEffect(const sp<SurfaceControl>& sc, float left, float top,
+                                      float right, float bottom, float vecX, float vecY,
+                                      float maxAmount);
+
         status_t setDisplaySurface(const sp<IBinder>& token,
                 const sp<IGraphicBufferProducer>& bufferProducer);
 
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 70e656d..5447b76 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -28,7 +28,7 @@
 #include <gui/SurfaceComposerClient.h>
 #include <gui/SyncScreenCaptureListener.h>
 #include <private/gui/ComposerService.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/GraphicTypes.h>
 #include <ui/Transform.h>
@@ -107,9 +107,9 @@
         t.apply();
         t.clear();
 
-        DisplayConfig config;
-        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplayToken, &config));
-        const ui::Size& resolution = config.resolution;
+        ui::DisplayMode mode;
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(mDisplayToken, &mode));
+        const ui::Size& resolution = mode.resolution;
         mDisplayWidth = resolution.getWidth();
         mDisplayHeight = resolution.getHeight();
 
diff --git a/libs/gui/tests/DisplayEventStructLayout_test.cpp b/libs/gui/tests/DisplayEventStructLayout_test.cpp
index c5093e2..7dbba31 100644
--- a/libs/gui/tests/DisplayEventStructLayout_test.cpp
+++ b/libs/gui/tests/DisplayEventStructLayout_test.cpp
@@ -25,7 +25,7 @@
 TEST(DisplayEventStructLayoutTest, TestEventAlignment) {
     CHECK_OFFSET(DisplayEventReceiver::Event, vsync, 24);
     CHECK_OFFSET(DisplayEventReceiver::Event, hotplug, 24);
-    CHECK_OFFSET(DisplayEventReceiver::Event, config, 24);
+    CHECK_OFFSET(DisplayEventReceiver::Event, modeChange, 24);
 
     CHECK_OFFSET(DisplayEventReceiver::Event::Header, type, 0);
     CHECK_OFFSET(DisplayEventReceiver::Event::Header, displayId, 8);
@@ -38,8 +38,8 @@
 
     CHECK_OFFSET(DisplayEventReceiver::Event::Hotplug, connected, 0);
 
-    CHECK_OFFSET(DisplayEventReceiver::Event::Config, configId, 0);
-    CHECK_OFFSET(DisplayEventReceiver::Event::Config, vsyncPeriod, 8);
+    CHECK_OFFSET(DisplayEventReceiver::Event::ModeChange, modeId, 0);
+    CHECK_OFFSET(DisplayEventReceiver::Event::ModeChange, vsyncPeriod, 8);
 
     CHECK_OFFSET(DisplayEventReceiver::Event::FrameRateOverride, uid, 0);
     CHECK_OFFSET(DisplayEventReceiver::Event::FrameRateOverride, frameRateHz, 8);
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 31cbbdc..d65a40b 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -41,7 +41,7 @@
 #include <input/InputTransport.h>
 #include <input/InputWindow.h>
 
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
 
@@ -272,13 +272,13 @@
         const auto display = mComposerClient->getInternalDisplayToken();
         ASSERT_NE(display, nullptr);
 
-        DisplayConfig config;
-        ASSERT_EQ(NO_ERROR, mComposerClient->getActiveDisplayConfig(display, &config));
+        ui::DisplayMode mode;
+        ASSERT_EQ(NO_ERROR, mComposerClient->getActiveDisplayMode(display, &mode));
 
         // After a new buffer is queued, SurfaceFlinger is notified and will
         // latch the new buffer on next vsync.  Let's heuristically wait for 3
         // vsyncs.
-        mBufferPostDelay = static_cast<int32_t>(1e6 / config.refreshRate) * 3;
+        mBufferPostDelay = static_cast<int32_t>(1e6 / mode.refreshRate) * 3;
     }
 
     void TearDown() {
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 3f7a5b1..43909ac 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -737,7 +737,7 @@
     status_t getDisplayInfo(const sp<IBinder>& /*display*/, DisplayInfo*) override {
         return NO_ERROR;
     }
-    status_t getDisplayConfigs(const sp<IBinder>& /*display*/, Vector<DisplayConfig>*) override {
+    status_t getDisplayModes(const sp<IBinder>& /*display*/, Vector<ui::DisplayMode>*) override {
         return NO_ERROR;
     }
     status_t getDisplayState(const sp<IBinder>& /*display*/, ui::DisplayState*) override {
@@ -745,7 +745,7 @@
     }
     status_t getDisplayStats(const sp<IBinder>& /*display*/,
             DisplayStatInfo* /*stats*/) override { return NO_ERROR; }
-    int getActiveConfig(const sp<IBinder>& /*display*/) override { return 0; }
+    int getActiveDisplayModeId(const sp<IBinder>& /*display*/) override { return 0; }
     status_t getDisplayColorModes(const sp<IBinder>& /*display*/,
             Vector<ColorMode>* /*outColorModes*/) override {
         return NO_ERROR;
@@ -843,21 +843,21 @@
             const sp<IRegionSamplingListener>& /*listener*/) override {
         return NO_ERROR;
     }
-    status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
-                                          int32_t /*defaultConfig*/, bool /*allowGroupSwitching*/,
-                                          float /*primaryRefreshRateMin*/,
-                                          float /*primaryRefreshRateMax*/,
-                                          float /*appRequestRefreshRateMin*/,
-                                          float /*appRequestRefreshRateMax*/) {
+    status_t setDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/, size_t /*defaultMode*/,
+                                        bool /*allowGroupSwitching*/,
+                                        float /*primaryRefreshRateMin*/,
+                                        float /*primaryRefreshRateMax*/,
+                                        float /*appRequestRefreshRateMin*/,
+                                        float /*appRequestRefreshRateMax*/) {
         return NO_ERROR;
     }
-    status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& /*displayToken*/,
-                                          int32_t* /*outDefaultConfig*/,
-                                          bool* /*outAllowGroupSwitching*/,
-                                          float* /*outPrimaryRefreshRateMin*/,
-                                          float* /*outPrimaryRefreshRateMax*/,
-                                          float* /*outAppRequestRefreshRateMin*/,
-                                          float* /*outAppRequestRefreshRateMax*/) override {
+    status_t getDesiredDisplayModeSpecs(const sp<IBinder>& /*displayToken*/,
+                                        size_t* /*outDefaultMode*/,
+                                        bool* /*outAllowGroupSwitching*/,
+                                        float* /*outPrimaryRefreshRateMin*/,
+                                        float* /*outPrimaryRefreshRateMax*/,
+                                        float* /*outAppRequestRefreshRateMin*/,
+                                        float* /*outAppRequestRefreshRateMax*/) override {
         return NO_ERROR;
     };
     status_t notifyPowerBoost(int32_t /*boostId*/) override { return NO_ERROR; }
@@ -889,6 +889,8 @@
 
     int getGPUContextPriority() override { return 0; };
 
+    status_t getExtraBufferCount(int* /*extraBuffers*/) const override { return NO_ERROR; }
+
 protected:
     IBinder* onAsBinder() override { return nullptr; }
 
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index 6d91916..dc2dd29 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -21,7 +21,7 @@
 #include <gui/DisplayEventDispatcher.h>
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
-#include <nativehelper/JNIHelp.h>
+#include <jni.h>
 #include <private/android/choreographer.h>
 #include <utils/Looper.h>
 #include <utils/Timers.h>
@@ -138,8 +138,8 @@
     void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
                        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;
+    void dispatchModeChanged(nsecs_t timestamp, PhysicalDisplayId displayId, int32_t modeId,
+                             nsecs_t vsyncPeriod) override;
     void dispatchNullEvent(nsecs_t, PhysicalDisplayId) override;
     void dispatchFrameRateOverrides(nsecs_t timestamp, PhysicalDisplayId displayId,
                                     std::vector<FrameRateOverride> overrides) override;
@@ -382,8 +382,8 @@
             this, to_string(displayId).c_str(), toString(connected));
 }
 
-void Choreographer::dispatchConfigChanged(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t) {
-    LOG_ALWAYS_FATAL("dispatchConfigChanged was called but was never registered");
+void Choreographer::dispatchModeChanged(nsecs_t, PhysicalDisplayId, int32_t, nsecs_t) {
+    LOG_ALWAYS_FATAL("dispatchModeChanged was called but was never registered");
 }
 
 void Choreographer::dispatchFrameRateOverrides(nsecs_t, PhysicalDisplayId,
diff --git a/libs/nativedisplay/ADisplay.cpp b/libs/nativedisplay/ADisplay.cpp
index 277635c..c595aa6 100644
--- a/libs/nativedisplay/ADisplay.cpp
+++ b/libs/nativedisplay/ADisplay.cpp
@@ -16,8 +16,8 @@
 
 #include <apex/display.h>
 #include <gui/SurfaceComposerClient.h>
-#include <ui/DisplayConfig.h>
 #include <ui/DisplayInfo.h>
+#include <ui/DisplayMode.h>
 #include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
 
@@ -134,8 +134,8 @@
         return NO_INIT;
     }
 
-    std::vector<DisplayConfigImpl> configsPerDisplay[size];
-    int numConfigs = 0;
+    std::vector<DisplayConfigImpl> modesPerDisplay[size];
+    int numModes = 0;
     for (int i = 0; i < size; ++i) {
         const sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(ids[i]);
 
@@ -145,23 +145,23 @@
             return status;
         }
 
-        Vector<DisplayConfig> configs;
-        if (const status_t status = SurfaceComposerClient::getDisplayConfigs(token, &configs);
+        Vector<ui::DisplayMode> modes;
+        if (const status_t status = SurfaceComposerClient::getDisplayModes(token, &modes);
             status != OK) {
             return status;
         }
-        if (configs.empty()) {
+        if (modes.empty()) {
             return NO_INIT;
         }
 
-        numConfigs += configs.size();
-        configsPerDisplay[i].reserve(configs.size());
-        for (int j = 0; j < configs.size(); ++j) {
-            const DisplayConfig& config = configs[j];
-            configsPerDisplay[i].emplace_back(
-                    DisplayConfigImpl{config.resolution.getWidth(), config.resolution.getHeight(),
-                                      info.density, config.refreshRate, config.sfVsyncOffset,
-                                      config.appVsyncOffset});
+        numModes += modes.size();
+        modesPerDisplay[i].reserve(modes.size());
+        for (int j = 0; j < modes.size(); ++j) {
+            const ui::DisplayMode& mode = modes[j];
+            modesPerDisplay[i].emplace_back(
+                    DisplayConfigImpl{mode.resolution.getWidth(), mode.resolution.getHeight(),
+                                      info.density, mode.refreshRate, mode.sfVsyncOffset,
+                                      mode.appVsyncOffset});
         }
     }
 
@@ -192,7 +192,7 @@
     // contiguous block of DisplayConfigImpls specific to that display.
     DisplayImpl** const impls = reinterpret_cast<DisplayImpl**>(
             malloc((sizeof(DisplayImpl) + sizeof(DisplayImpl*)) * size +
-                   sizeof(DisplayConfigImpl) * numConfigs));
+                   sizeof(DisplayConfigImpl) * numModes));
     DisplayImpl* const displayData = reinterpret_cast<DisplayImpl*>(impls + size);
     DisplayConfigImpl* configData = reinterpret_cast<DisplayConfigImpl*>(displayData + size);
 
@@ -200,7 +200,7 @@
         const PhysicalDisplayId id = ids[i];
         const ADisplayType type = (internalId == id) ? ADisplayType::DISPLAY_TYPE_INTERNAL
                                                      : ADisplayType::DISPLAY_TYPE_EXTERNAL;
-        const std::vector<DisplayConfigImpl>& configs = configsPerDisplay[i];
+        const std::vector<DisplayConfigImpl>& configs = modesPerDisplay[i];
         memcpy(configData, configs.data(), sizeof(DisplayConfigImpl) * configs.size());
 
         displayData[i] = DisplayImpl{id,
@@ -257,7 +257,7 @@
     CHECK_NOT_NULL(display);
 
     sp<IBinder> token = getToken(display);
-    const int index = SurfaceComposerClient::getActiveConfig(token);
+    const int index = SurfaceComposerClient::getActiveDisplayModeId(token);
     if (index < 0) {
         return index;
     }
diff --git a/libs/nativedisplay/Android.bp b/libs/nativedisplay/Android.bp
index f56b3a2..6574ae6 100644
--- a/libs/nativedisplay/Android.bp
+++ b/libs/nativedisplay/Android.bp
@@ -53,15 +53,13 @@
         "libcutils",
         "libEGL",
         "libGLESv2",
-        "libnativehelper",
     ],
 
-    export_shared_lib_headers: [
-        "libnativehelper",
-    ],
+    export_header_lib_headers: ["jni_headers"],
 
     header_libs: [
+        "jni_headers",
         "libnativedisplay_headers",
+        "libnativehelper_header_only",
     ],
-
 }
diff --git a/libs/nativedisplay/include-private/private/android/choreographer.h b/libs/nativedisplay/include-private/private/android/choreographer.h
index d3a4a66..0f4fd45 100644
--- a/libs/nativedisplay/include-private/private/android/choreographer.h
+++ b/libs/nativedisplay/include-private/private/android/choreographer.h
@@ -18,7 +18,7 @@
 
 #include <apex/choreographer.h>
 #include <inttypes.h>
-#include <nativehelper/JNIHelp.h>
+#include <jni.h>
 
 namespace android {
 
diff --git a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
index f371667..85fe42f 100644
--- a/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
+++ b/libs/nativedisplay/include/surfacetexture/surface_texture_platform.h
@@ -19,7 +19,7 @@
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
-#include <nativehelper/JNIHelp.h>
+#include <jni.h>
 #include <system/graphics.h>
 
 // This file provides a facade API on top of SurfaceTexture, which avoids using
diff --git a/libs/nativedisplay/surfacetexture/surface_texture.cpp b/libs/nativedisplay/surfacetexture/surface_texture.cpp
index ebe4484..c214ab7 100644
--- a/libs/nativedisplay/surfacetexture/surface_texture.cpp
+++ b/libs/nativedisplay/surfacetexture/surface_texture.cpp
@@ -29,8 +29,7 @@
 #include <mutex>
 
 #include <jni.h>
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/scoped_local_ref.h>
 
 struct ASurfaceTexture {
     android::sp<android::SurfaceTexture> consumer;
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 4fcca9e..20a1f74 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -334,8 +334,6 @@
 
 // clang-format on
 
-#if __ANDROID_API__ >= 26
-
 /**
  * Allocates a buffer that matches the passed AHardwareBuffer_Desc.
  *
@@ -478,10 +476,6 @@
                                              AHardwareBuffer* _Nullable* _Nonnull outBuffer)
         __INTRODUCED_IN(26);
 
-#endif // __ANDROID_API__ >= 26
-
-#if __ANDROID_API__ >= 29
-
 /**
  * Lock a potentially multi-planar AHardwareBuffer for direct CPU access.
  *
@@ -551,10 +545,6 @@
                                    int32_t* _Nonnull outBytesPerPixel,
                                    int32_t* _Nonnull outBytesPerStride) __INTRODUCED_IN(29);
 
-#endif // __ANDROID_API__ >= 29
-
-#if __ANDROID_API__ >= 31
-
 /**
  * Get the system wide unique id for an AHardwareBuffer.
  *
@@ -566,8 +556,6 @@
 int AHardwareBuffer_getId(const AHardwareBuffer* _Nonnull buffer, uint64_t* _Nonnull outId)
         __INTRODUCED_IN(31);
 
-#endif // __ANDROID_API__ >= 31
-
 __END_DECLS
 
 #endif // ANDROID_HARDWARE_BUFFER_H
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index deea59b..285f2fb 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -186,8 +186,6 @@
  */
 int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);
 
-#if __ANDROID_API__ >= 26
-
 /**
  * Set a transform that will be applied to future buffers posted to the window.
  *
@@ -198,10 +196,6 @@
  */
 int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transform) __INTRODUCED_IN(26);
 
-#endif // __ANDROID_API__ >= 26
-
-#if __ANDROID_API__ >= 28
-
 /**
  * All buffers queued after this call will be associated with the dataSpace
  * parameter specified.
@@ -230,10 +224,6 @@
  */
 int32_t ANativeWindow_getBuffersDataSpace(ANativeWindow* window) __INTRODUCED_IN(28);
 
-#endif // __ANDROID_API__ >= 28
-
-#if __ANDROID_API__ >= 30
-
 /** Compatibility value for ANativeWindow_setFrameRate. */
 enum ANativeWindow_FrameRateCompatibility {
     /**
@@ -275,11 +265,7 @@
  *
  * Available since API level 30.
  */
-void ANativeWindow_tryAllocateBuffers(ANativeWindow* window);
-
-#endif // __ANDROID_API__ >= 30
-
-#if __ANDROID_API__ >= 31
+void ANativeWindow_tryAllocateBuffers(ANativeWindow* window) __INTRODUCED_IN(30);
 
 /**
  * Sets the intended frame rate for this window.
@@ -322,8 +308,6 @@
 int32_t ANativeWindow_setFrameRateWithSeamlessness(ANativeWindow* window, float frameRate,
         int8_t compatibility, bool shouldBeSeamless) __INTRODUCED_IN(31);
 
-#endif // __ANDROID_API__ >= 31
-
 #ifdef __cplusplus
 };
 #endif
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index ffe4412..7aa2cf4 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -256,6 +256,7 @@
     NATIVE_WINDOW_GET_LAST_QUEUED_BUFFER          = 46,    /* private */
     NATIVE_WINDOW_SET_QUERY_INTERCEPTOR           = 47,    /* private */
     NATIVE_WINDOW_SET_FRAME_TIMELINE_INFO         = 48,    /* private */
+    NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT          = 49,    /* private */
     // clang-format on
 };
 
@@ -1030,6 +1031,11 @@
                            frameTimelineVsyncId, inputEventId);
 }
 
+static inline int native_window_get_extra_buffer_count(
+    struct ANativeWindow* window, int* extraBuffers) {
+    return window->perform(window, NATIVE_WINDOW_GET_EXTRA_BUFFER_COUNT, extraBuffers);
+}
+
 // ------------------------------------------------------------------------------------------------
 // Candidates for APEX visibility
 // These functions are planned to be made stable for APEX modules, but have not
diff --git a/libs/renderengine/OWNERS b/libs/renderengine/OWNERS
index b44456b..08cf2de 100644
--- a/libs/renderengine/OWNERS
+++ b/libs/renderengine/OWNERS
@@ -1,4 +1,3 @@
 alecmouri@google.com
 jreck@google.com
 lpy@google.com
-stoza@google.com
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 3a727c9..7661233 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -28,6 +28,7 @@
 #include <ui/GraphicTypes.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
+#include <ui/StretchEffect.h>
 #include <ui/Transform.h>
 
 namespace android {
@@ -155,6 +156,8 @@
 
     std::vector<BlurRegion> blurRegions;
 
+    StretchEffect stretchEffect;
+
     // Name associated with the layer for debugging purposes.
     std::string name;
 };
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 79505ba..1eb8da9 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -33,9 +33,11 @@
 #include <SkRegion.h>
 #include <SkShadowUtils.h>
 #include <SkSurface.h>
+#include <android-base/stringprintf.h>
 #include <gl/GrGLInterface.h>
 #include <sync/sync.h>
 #include <ui/BlurRegion.h>
+#include <ui/DebugUtils.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/Trace.h>
 
@@ -59,6 +61,8 @@
 namespace renderengine {
 namespace skia {
 
+using base::StringAppendF;
+
 static status_t selectConfigForAttribute(EGLDisplay dpy, EGLint const* attrs, EGLint attribute,
                                          EGLint wanted, EGLConfig* outConfig) {
     EGLint numConfigs = -1, n = 0;
@@ -487,6 +491,9 @@
                                                               const LayerSettings* layer,
                                                               const DisplaySettings& display,
                                                               bool undoPremultipliedAlpha) {
+    if (layer->stretchEffect.hasEffect()) {
+        // TODO: Implement
+    }
     if (mUseColorManagement &&
         needsLinearEffect(layer->colorTransform, layer->sourceDataspace, display.outputDataspace)) {
         LinearEffect effect = LinearEffect{.inputDataspace = layer->sourceDataspace,
@@ -1075,6 +1082,53 @@
     return value;
 }
 
+void SkiaGLRenderEngine::dump(std::string& result) {
+    const gl::GLExtensions& extensions = gl::GLExtensions::getInstance();
+
+    StringAppendF(&result, "\n ------------RE-----------------\n");
+    StringAppendF(&result, "EGL implementation : %s\n", extensions.getEGLVersion());
+    StringAppendF(&result, "%s\n", extensions.getEGLExtensions());
+    StringAppendF(&result, "GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
+                  extensions.getVersion());
+    StringAppendF(&result, "%s\n", extensions.getExtensions());
+    StringAppendF(&result, "RenderEngine supports protected context: %d\n",
+                  supportsProtectedContent());
+    StringAppendF(&result, "RenderEngine is in protected context: %d\n", mInProtectedContext);
+
+    {
+        std::lock_guard<std::mutex> lock(mRenderingMutex);
+        StringAppendF(&result, "RenderEngine texture cache size: %zu\n", mTextureCache.size());
+        StringAppendF(&result, "Dumping buffer ids...\n");
+        // TODO(178539829): It would be nice to know which layer these are coming from and what
+        // the texture sizes are.
+        for (const auto& [id, unused] : mTextureCache) {
+            StringAppendF(&result, "- 0x%" PRIx64 "\n", id);
+        }
+        StringAppendF(&result, "\n");
+        StringAppendF(&result, "RenderEngine protected texture cache size: %zu\n",
+                      mProtectedTextureCache.size());
+        StringAppendF(&result, "Dumping buffer ids...\n");
+        for (const auto& [id, unused] : mProtectedTextureCache) {
+            StringAppendF(&result, "- 0x%" PRIx64 "\n", id);
+        }
+        StringAppendF(&result, "\n");
+        StringAppendF(&result, "RenderEngine runtime effects: %zu\n", mRuntimeEffects.size());
+        for (const auto& [linearEffect, unused] : mRuntimeEffects) {
+            StringAppendF(&result, "- inputDataspace: %s\n",
+                          dataspaceDetails(
+                                  static_cast<android_dataspace>(linearEffect.inputDataspace))
+                                  .c_str());
+            StringAppendF(&result, "- outputDataspace: %s\n",
+                          dataspaceDetails(
+                                  static_cast<android_dataspace>(linearEffect.outputDataspace))
+                                  .c_str());
+            StringAppendF(&result, "undoPremultipliedAlpha: %s\n",
+                          linearEffect.undoPremultipliedAlpha ? "true" : "false");
+        }
+    }
+    StringAppendF(&result, "\n");
+}
+
 } // namespace skia
 } // namespace renderengine
 } // namespace android
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 3294de8..810fc2a 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -63,7 +63,7 @@
     bool useProtectedContext(bool useProtectedContext) override;
 
 protected:
-    void dump(std::string& /*result*/) override{};
+    void dump(std::string& result) override;
     size_t getMaxTextureSize() const override;
     size_t getMaxViewportDims() const override;
 
diff --git a/libs/renderengine/skia/debug/record.sh b/libs/renderengine/skia/debug/record.sh
new file mode 100755
index 0000000..bc406d9
--- /dev/null
+++ b/libs/renderengine/skia/debug/record.sh
@@ -0,0 +1,106 @@
+# This script captures MSKP files from RenderEngine in a connected device.
+# this only functions when RenderEngine uses the Skia backend.
+# it triggers code in SkiaCapture.cpp.
+
+# for a newly flashed device, perform first time steps with
+# record.sh rootandsetup
+
+# record all frames that RenderEngine handles over the span of 2 seconds.
+# record.sh 2000
+
+if [ -z "$1" ]; then
+    printf 'Usage:\n    record.sh rootandsetup\n'
+    printf '    record.sh MILLISECONDS\n\n'
+    exit 1
+elif [ "$1" == "rootandsetup" ]; then
+  # first time use requires these changes
+  adb root
+  adb shell setenforce 0
+  adb shell setprop debug.renderengine.backend "skiagl"
+  adb shell stop
+  adb shell start
+  exit 1;
+fi
+
+# name of the newest file in /data/user/ before starting
+oldname=$(adb shell ls -cr /data/user/ | head -n 1)
+
+# record frames for some number of milliseconds.
+adb shell setprop debug.renderengine.capture_skia_ms $1
+
+# give the device time to both record, and starting writing the file.
+# Total time needed to write the file depends on how much data was recorded.
+# the loop at the end waits for this.
+sleep $(($1 / 1000 + 2));
+
+# There is no guarantee that at least one frame passed through renderengine during that time
+# but as far as I know it always at least writes a 0-byte file with a new name, unless it crashes
+# the process it is recording.
+# /data/user/re_skiacapture_56204430551705.mskp
+
+# list the files here from newest to oldest, keep only the name of the newest.
+name=$(adb shell ls -cr /data/user/ | head -n 1)
+remote_path=/data/user/$name
+
+if [[ $oldname = $name ]]; then
+  echo "No new file written, probably no RenderEngine activity during recording period."
+  exit 1
+fi
+
+# return the size of a file in bytes
+adb_filesize() {
+    adb shell "wc -c \"$1\"" 2> /dev/null | awk '{print $1}'
+}
+
+mskp_size=$(adb_filesize "/data/user/$name")
+if [[ $mskp_size = "0" ]]; then
+  echo "Empty file, probably no RenderEngine activity during recording period."
+  exit 1
+fi
+
+spin() {
+    case "$spin" in
+         1) printf '\b|';;
+         2) printf '\b\\';;
+         3) printf '\b-';;
+         *) printf '\b/';;
+    esac
+    spin=$(( ( ${spin:-0} + 1 ) % 4 ))
+    sleep $1
+}
+
+printf "MSKP captured, Waiting for file serialization to finish.\n"
+
+local_path=~/Downloads/$name
+
+# wait for the file size to stop changing
+
+timeout=$(( $(date +%s) + 300))
+last_size='0' # output of last size check command
+unstable=true # false once the file size stops changing
+counter=0 # used to perform size check only 1/sec though we update spinner 20/sec
+# loop until the file size is unchanged for 1 second.
+while [ $unstable != 0 ] ; do
+    spin 0.05
+    counter=$(( $counter+1 ))
+    if ! (( $counter % 20)) ; then
+        new_size=$(adb_filesize "$remote_path")
+        unstable=$(($new_size != $last_size))
+        last_size=$new_size
+    fi
+    if [ $(date +%s) -gt $timeout ] ; then
+        printf '\bTimed out.\n'
+        exit 3
+    fi
+done
+printf '\b'
+
+printf "MSKP file serialized: %s\n" $(echo $last_size | numfmt --to=iec)
+
+adb pull "$remote_path" "$local_path"
+if ! [ -f "$local_path" ] ; then
+    printf "something went wrong with `adb pull`."
+    exit 4
+fi
+adb shell rm "$remote_path"
+printf 'SKP saved to %s\n\n' "$local_path"
\ No newline at end of file
diff --git a/libs/sensorprivacy/SensorPrivacyManager.cpp b/libs/sensorprivacy/SensorPrivacyManager.cpp
index 7bddee6..4714469 100644
--- a/libs/sensorprivacy/SensorPrivacyManager.cpp
+++ b/libs/sensorprivacy/SensorPrivacyManager.cpp
@@ -64,13 +64,15 @@
     }
 }
 
-void SensorPrivacyManager::addIndividualSensorPrivacyListener(int userId, int sensor,
+status_t SensorPrivacyManager::addIndividualSensorPrivacyListener(int userId, int sensor,
         const sp<hardware::ISensorPrivacyListener>& listener)
 {
     sp<hardware::ISensorPrivacyManager> service = getService();
     if (service != nullptr) {
-        service->addIndividualSensorPrivacyListener(userId, sensor, listener);
+        return service->addIndividualSensorPrivacyListener(userId, sensor, listener)
+                .transactionError();
     }
+    return UNEXPECTED_NULL;
 }
 
 void SensorPrivacyManager::removeSensorPrivacyListener(
@@ -106,6 +108,19 @@
     return false;
 }
 
+status_t SensorPrivacyManager::isIndividualSensorPrivacyEnabled(int userId, int sensor,
+        bool &returnVal)
+{
+    sp<hardware::ISensorPrivacyManager> service = getService();
+    if (service != nullptr) {
+        binder::Status res = service->isIndividualSensorPrivacyEnabled(userId, sensor, &returnVal);
+        return res.transactionError();
+    }
+    // if the SensorPrivacyManager is not available then assume sensor privacy is disabled
+    returnVal = false;
+    return UNKNOWN_ERROR;
+}
+
 status_t SensorPrivacyManager::linkToDeath(const sp<IBinder::DeathRecipient>& recipient)
 {
     sp<hardware::ISensorPrivacyManager> service = getService();
diff --git a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
index bd7c726..12778e1 100644
--- a/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
+++ b/libs/sensorprivacy/include/sensorprivacy/SensorPrivacyManager.h
@@ -36,11 +36,12 @@
     SensorPrivacyManager();
 
     void addSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
-    void addIndividualSensorPrivacyListener(int userId, int sensor,
+    status_t addIndividualSensorPrivacyListener(int userId, int sensor,
             const sp<hardware::ISensorPrivacyListener>& listener);
     void removeSensorPrivacyListener(const sp<hardware::ISensorPrivacyListener>& listener);
     bool isSensorPrivacyEnabled();
     bool isIndividualSensorPrivacyEnabled(int userId, int sensor);
+    status_t isIndividualSensorPrivacyEnabled(int userId, int sensor, bool &result);
 
     status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient);
     status_t unlinkToDeath(const sp<IBinder::DeathRecipient>& recipient);
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 7c68aaa..714ee3e 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-unstable-ndk_platform",
+        "android.hardware.graphics.common-V2-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-unstable-ndk_platform",
+        "android.hardware.graphics.common-V2-ndk_platform",
         "android.hardware.graphics.mapper@4.0",
         "libgralloctypes",
     ],
diff --git a/libs/ui/OWNERS b/libs/ui/OWNERS
index b1317b1..5110a6c 100644
--- a/libs/ui/OWNERS
+++ b/libs/ui/OWNERS
@@ -4,4 +4,3 @@
 lpy@google.com
 mathias@google.com
 romainguy@google.com
-stoza@google.com
diff --git a/libs/ui/PublicFormat.cpp b/libs/ui/PublicFormat.cpp
index a6595cf..78e82da 100644
--- a/libs/ui/PublicFormat.cpp
+++ b/libs/ui/PublicFormat.cpp
@@ -100,6 +100,7 @@
         case HAL_PIXEL_FORMAT_RAW12:
         case HAL_PIXEL_FORMAT_YCbCr_420_888:
         case HAL_PIXEL_FORMAT_YV12:
+        case HAL_PIXEL_FORMAT_YCBCR_P010:
             // Enums overlap in both name and value
             return static_cast<PublicFormat>(format);
         case HAL_PIXEL_FORMAT_RAW16:
diff --git a/libs/ui/include/ui/DisplayConfig.h b/libs/ui/include/ui/DisplayMode.h
similarity index 81%
rename from libs/ui/include/ui/DisplayConfig.h
rename to libs/ui/include/ui/DisplayMode.h
index d6fbaab..145d7ef 100644
--- a/libs/ui/include/ui/DisplayConfig.h
+++ b/libs/ui/include/ui/DisplayMode.h
@@ -21,10 +21,10 @@
 #include <ui/Size.h>
 #include <utils/Timers.h>
 
-namespace android {
+namespace android::ui {
 
-// Configuration supported by physical display.
-struct DisplayConfig {
+// Mode supported by physical display.
+struct DisplayMode {
     ui::Size resolution;
     float xDpi = 0;
     float yDpi = 0;
@@ -33,9 +33,9 @@
     nsecs_t appVsyncOffset = 0;
     nsecs_t sfVsyncOffset = 0;
     nsecs_t presentationDeadline = 0;
-    int configGroup = -1;
+    int group = -1;
 };
 
-static_assert(std::is_trivially_copyable_v<DisplayConfig>);
+static_assert(std::is_trivially_copyable_v<DisplayMode>);
 
-} // namespace android
+} // namespace android::ui
diff --git a/libs/ui/include/ui/PublicFormat.h b/libs/ui/include/ui/PublicFormat.h
index 22274a2..aa58805 100644
--- a/libs/ui/include/ui/PublicFormat.h
+++ b/libs/ui/include/ui/PublicFormat.h
@@ -54,6 +54,7 @@
     YV12 = 0x32315659,
     Y8 = 0x20203859,
     Y16 = 0x20363159, // @hide
+    YCBCR_P010 = 0x36,
     DEPTH16 = 0x44363159,
     DEPTH_JPEG = 0x69656963,
     HEIC = 0x48454946,
diff --git a/libs/ui/include/ui/StretchEffect.h b/libs/ui/include/ui/StretchEffect.h
new file mode 100644
index 0000000..1d2460c
--- /dev/null
+++ b/libs/ui/include/ui/StretchEffect.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <utils/Flattenable.h>
+#include "FloatRect.h"
+
+#include <type_traits>
+
+namespace android {
+
+struct StretchEffect : public LightFlattenablePod<StretchEffect> {
+    FloatRect area = {0, 0, 0, 0};
+    float vectorX = 0;
+    float vectorY = 0;
+    float maxAmount = 0;
+
+    bool operator==(const StretchEffect& other) const {
+        return area == other.area && vectorX == other.vectorX && vectorY == other.vectorY &&
+                maxAmount == other.maxAmount;
+    }
+
+    static bool isZero(float value) {
+        constexpr float NON_ZERO_EPSILON = 0.001f;
+        return fabsf(value) <= NON_ZERO_EPSILON;
+    }
+
+    bool isNoOp() const { return isZero(vectorX) && isZero(vectorY); }
+
+    bool hasEffect() const { return !isNoOp(); }
+
+    void sanitize() {
+        // If the area is empty, or the max amount is zero, then reset back to defaults
+        if (area.bottom >= area.top || area.left >= area.right || isZero(maxAmount)) {
+            *this = StretchEffect{};
+        }
+    }
+};
+
+static_assert(std::is_trivially_copyable<StretchEffect>::value,
+              "StretchEffect must be trivially copyable to be flattenable");
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/DisplayConfig.h b/libs/ui/include_vndk/ui/DisplayConfig.h
deleted file mode 120000
index 1450319..0000000
--- a/libs/ui/include_vndk/ui/DisplayConfig.h
+++ /dev/null
@@ -1 +0,0 @@
-../../include/ui/DisplayConfig.h
\ No newline at end of file
diff --git a/libs/ui/include_vndk/ui/DisplayMode.h b/libs/ui/include_vndk/ui/DisplayMode.h
new file mode 120000
index 0000000..c87754a
--- /dev/null
+++ b/libs/ui/include_vndk/ui/DisplayMode.h
@@ -0,0 +1 @@
+../../include/ui/DisplayMode.h
\ No newline at end of file
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index dfb9c92..fd4522e 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -21,7 +21,7 @@
 #include <gui/ISurfaceComposer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 #include <ui/DisplayState.h>
 
 using namespace android;
@@ -42,10 +42,10 @@
         return;
     }
 
-    DisplayConfig displayConfig;
-    err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
+    ui::DisplayMode displayMode;
+    err = SurfaceComposerClient::getActiveDisplayMode(displayToken, &displayMode);
     if (err != NO_ERROR) {
-        fprintf(stderr, "ERROR: unable to get active display config\n");
+        fprintf(stderr, "ERROR: unable to get active display mode\n");
         return;
     }
 
@@ -56,7 +56,7 @@
         return;
     }
 
-    const ui::Size& resolution = displayConfig.resolution;
+    const ui::Size& resolution = displayMode.resolution;
     auto width = resolution.getWidth();
     auto height = resolution.getHeight();
 
diff --git a/services/audiomanager/IAudioManager.cpp b/services/audiomanager/IAudioManager.cpp
index 0d17265..ae1bb1a 100644
--- a/services/audiomanager/IAudioManager.cpp
+++ b/services/audiomanager/IAudioManager.cpp
@@ -36,7 +36,7 @@
     }
 
     virtual audio_unique_id_t trackPlayer(player_type_t playerType, audio_usage_t usage,
-            audio_content_type_t content, const sp<IBinder>& player) {
+            audio_content_type_t content, const sp<IBinder>& player, audio_session_t sessionId) {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
         data.writeInt32(1); // non-null PlayerIdCard parcelable
@@ -54,6 +54,8 @@
         data.writeInt32(-1977 /*ATTR_PARCEL_IS_NULL_BUNDLE*/); // no bundle
         //   write IPlayer
         data.writeStrongBinder(player);
+        //   write session Id
+        data.writeInt32((int32_t)sessionId);
         // get new PIId in reply
         const status_t res = remote()->transact(TRACK_PLAYER, data, &reply, 0);
         if (res != OK || reply.readExceptionCode() != 0) {
@@ -131,6 +133,14 @@
         data.writeInt32((int32_t) riid);
         return remote()->transact(RELEASE_RECORDER, data, &reply, IBinder::FLAG_ONEWAY);
     }
+
+    virtual status_t playerSessionId(audio_unique_id_t piid, audio_session_t sessionId) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
+        data.writeInt32((int32_t) piid);
+        data.writeInt32((int32_t) sessionId);
+        return remote()->transact(PLAYER_SESSION_ID, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioManager, "android.media.IAudioService");
diff --git a/services/automotive/display/AutomotiveDisplayProxyService.cpp b/services/automotive/display/AutomotiveDisplayProxyService.cpp
index 321bb83..d6fc695 100644
--- a/services/automotive/display/AutomotiveDisplayProxyService.cpp
+++ b/services/automotive/display/AutomotiveDisplayProxyService.cpp
@@ -41,10 +41,10 @@
         }
 
         // Get the resolution from stored display state.
-        DisplayConfig displayConfig = {};
-        auto err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
+        ui::DisplayMode displayMode = {};
+        auto err = SurfaceComposerClient::getActiveDisplayMode(displayToken, &displayMode);
         if (err != NO_ERROR) {
-            ALOGE("Failed to get display configuration of %lX.  "
+            ALOGE("Failed to get display mode of %lX.  "
                   "This display will be ignored.", (unsigned long)id);
             return nullptr;
         }
@@ -57,8 +57,8 @@
             return nullptr;
         }
 
-        auto displayWidth  = displayConfig.resolution.getWidth();
-        auto displayHeight = displayConfig.resolution.getHeight();
+        auto displayWidth  = displayMode.resolution.getWidth();
+        auto displayHeight = displayMode.resolution.getHeight();
         if ((displayState.orientation != ui::ROTATION_0) &&
             (displayState.orientation != ui::ROTATION_180)) {
             std::swap(displayWidth, displayHeight);
@@ -161,10 +161,10 @@
     if (displayToken == nullptr) {
         ALOGE("Given display id, 0x%lX, is invalid.", (unsigned long)id);
     } else {
-        DisplayConfig displayConfig = {};
-        auto err = SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
+        ui::DisplayMode displayMode = {};
+        auto err = SurfaceComposerClient::getActiveDisplayMode(displayToken, &displayMode);
         if (err != NO_ERROR) {
-            ALOGW("Failed to get display configuration of %lX.  "
+            ALOGW("Failed to get display mode of %lX.  "
                   "This display will be ignored.", (unsigned long)id);
         }
 
@@ -175,7 +175,7 @@
                   "This display will be ignored.", (unsigned long)id);
         }
 
-        activeConfig.setToExternal((uint8_t*)&displayConfig, sizeof(DisplayConfig));
+        activeConfig.setToExternal((uint8_t*)&displayMode, sizeof(ui::DisplayMode));
         activeState.setToExternal((uint8_t*)&displayState, sizeof(DisplayState));
     }
 
diff --git a/services/automotive/display/include/AutomotiveDisplayProxyService.h b/services/automotive/display/include/AutomotiveDisplayProxyService.h
index e2fc0d2..4482b9b 100644
--- a/services/automotive/display/include/AutomotiveDisplayProxyService.h
+++ b/services/automotive/display/include/AutomotiveDisplayProxyService.h
@@ -20,7 +20,7 @@
 #include <gui/ISurfaceComposer.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 #include <ui/DisplayState.h>
 #include <tuple>
 #include <vector>
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index f5f0400..a9cbd5a 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -396,6 +396,11 @@
     mListener->notifySensor(args);
 }
 
+void InputClassifier::notifyVibratorState(const NotifyVibratorStateArgs* args) {
+    // pass through
+    mListener->notifyVibratorState(args);
+}
+
 void InputClassifier::notifySwitch(const NotifySwitchArgs* args) {
     // pass through
     mListener->notifySwitch(args);
diff --git a/services/inputflinger/InputClassifier.h b/services/inputflinger/InputClassifier.h
index bf10920..1eef020 100644
--- a/services/inputflinger/InputClassifier.h
+++ b/services/inputflinger/InputClassifier.h
@@ -230,6 +230,7 @@
     virtual void notifyMotion(const NotifyMotionArgs* args) override;
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
     virtual void notifySensor(const NotifySensorArgs* args) override;
+    virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
     void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 4be49b1..4b1f350 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -246,6 +246,24 @@
     listener->notifySensor(this);
 }
 
+// --- NotifyVibratorStateArgs ---
+
+NotifyVibratorStateArgs::NotifyVibratorStateArgs(int32_t id, nsecs_t eventTime, int32_t deviceId,
+                                                 bool isOn)
+      : NotifyArgs(id, eventTime), deviceId(deviceId), isOn(isOn) {}
+
+NotifyVibratorStateArgs::NotifyVibratorStateArgs(const NotifyVibratorStateArgs& other)
+      : NotifyArgs(other.id, other.eventTime), deviceId(other.deviceId), isOn(other.isOn) {}
+
+bool NotifyVibratorStateArgs::operator==(const NotifyVibratorStateArgs rhs) const {
+    return id == rhs.id && eventTime == rhs.eventTime && deviceId == rhs.deviceId &&
+            isOn == rhs.isOn;
+}
+
+void NotifyVibratorStateArgs::notify(const sp<InputListenerInterface>& listener) const {
+    listener->notifyVibratorState(this);
+}
+
 // --- NotifyDeviceResetArgs ---
 
 NotifyDeviceResetArgs::NotifyDeviceResetArgs(int32_t id, nsecs_t eventTime, int32_t deviceId)
@@ -326,6 +344,11 @@
     mArgsQueue.push_back(new NotifySensorArgs(*args));
 }
 
+void QueuedInputListener::notifyVibratorState(const NotifyVibratorStateArgs* args) {
+    traceEvent(__func__, args->id);
+    mArgsQueue.push_back(new NotifyVibratorStateArgs(*args));
+}
+
 void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) {
     traceEvent(__func__, args->id);
     mArgsQueue.push_back(new NotifyDeviceResetArgs(*args));
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 887bdd4..d6b7259 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -79,6 +79,8 @@
     void notifySensorAccuracy(int32_t deviceId, InputDeviceSensorType sensorType,
                               InputDeviceSensorAccuracy accuracy) override {}
 
+    void notifyVibratorState(int32_t deviceId, bool isOn) override {}
+
     void notifyUntrustedTouch(const std::string& obscuringPackage) override {}
 
     void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 0495d68..2909939 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -1247,9 +1247,10 @@
         nsecs_t currentTime, const std::shared_ptr<PointerCaptureChangedEntry>& entry,
         DropReason& dropReason) {
     const bool haveWindowWithPointerCapture = mWindowTokenWithPointerCapture != nullptr;
-    if (entry->pointerCaptureEnabled == haveWindowWithPointerCapture) {
-        LOG_ALWAYS_FATAL_IF(mFocusedWindowRequestedPointerCapture,
-                            "The Pointer Capture state has already been dispatched to the window.");
+    if (entry->pointerCaptureEnabled && haveWindowWithPointerCapture) {
+        LOG_ALWAYS_FATAL("Pointer Capture has already been enabled for the window.");
+    }
+    if (!entry->pointerCaptureEnabled && !haveWindowWithPointerCapture) {
         // Pointer capture was already forcefully disabled because of focus change.
         dropReason = DropReason::NOT_DROPPED;
         return;
@@ -3747,6 +3748,14 @@
     }
 }
 
+void InputDispatcher::notifyVibratorState(const NotifyVibratorStateArgs* args) {
+#if DEBUG_INBOUND_EVENT_DETAILS
+    ALOGD("notifyVibratorState - eventTime=%" PRId64 ", device=%d,  isOn=%d", args->eventTime,
+          args->deviceId, args->isOn);
+#endif
+    mPolicy->notifyVibratorState(args->deviceId, args->isOn);
+}
+
 bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) {
     return mInputFilterEnabled;
 }
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 02f5b87..c93d74e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -96,6 +96,7 @@
     virtual void notifyMotion(const NotifyMotionArgs* args) override;
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
     virtual void notifySensor(const NotifySensorArgs* args) override;
+    virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
     virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index b976129..909ce54 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -84,6 +84,7 @@
                                    const std::vector<float>& values) = 0;
     virtual void notifySensorAccuracy(int32_t deviceId, InputDeviceSensorType sensorType,
                                       InputDeviceSensorAccuracy accuracy) = 0;
+    virtual void notifyVibratorState(int32_t deviceId, bool isOn) = 0;
 
     /* Notifies the system that an untrusted touch occurred. */
     virtual void notifyUntrustedTouch(const std::string& obscuringPackage) = 0;
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index 11f726d..094bc0c 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -223,6 +223,24 @@
     virtual void notify(const sp<InputListenerInterface>& listener) const;
 };
 
+/* Describes a vibrator state event. */
+struct NotifyVibratorStateArgs : public NotifyArgs {
+    int32_t deviceId;
+    bool isOn;
+
+    inline NotifyVibratorStateArgs() {}
+
+    NotifyVibratorStateArgs(int32_t id, nsecs_t eventTIme, int32_t deviceId, bool isOn);
+
+    NotifyVibratorStateArgs(const NotifyVibratorStateArgs& other);
+
+    bool operator==(const NotifyVibratorStateArgs rhs) const;
+
+    virtual ~NotifyVibratorStateArgs() {}
+
+    virtual void notify(const sp<InputListenerInterface>& listener) const;
+};
+
 /*
  * The interface used by the InputReader to notify the InputListener about input events.
  */
@@ -237,6 +255,7 @@
     virtual void notifyMotion(const NotifyMotionArgs* args) = 0;
     virtual void notifySwitch(const NotifySwitchArgs* args) = 0;
     virtual void notifySensor(const NotifySensorArgs* args) = 0;
+    virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) = 0;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0;
     virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) = 0;
 };
@@ -259,6 +278,7 @@
     virtual void notifySwitch(const NotifySwitchArgs* args) override;
     virtual void notifySensor(const NotifySensorArgs* args) override;
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) override;
+    void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
     void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
     void flush();
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index de5d0e6..c044393 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -928,6 +928,11 @@
     mReader->mQueuedListener->notifySensor(&args);
 }
 
+void InputReader::ContextImpl::notifyVibratorState(nsecs_t when, int32_t deviceId, bool isOn) {
+    NotifyVibratorStateArgs args(mIdGenerator.nextId(), when, deviceId, isOn);
+    mReader->mQueuedListener->notifyVibratorState(&args);
+}
+
 void InputReader::ContextImpl::notifySwitch(nsecs_t eventTime, uint32_t switchValues,
                                             uint32_t switchMask) {
     NotifySwitchArgs args(mIdGenerator.nextId(), eventTime, 0 /*policyFlags*/, switchValues,
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index e2558bc..5f78149 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -152,6 +152,7 @@
         void notifySensor(nsecs_t when, int32_t deviceId, InputDeviceSensorType sensorType,
                           InputDeviceSensorAccuracy accuracy, bool accuracyChanged,
                           nsecs_t timestamp, std::vector<float> values) override;
+        void notifyVibratorState(nsecs_t when, int32_t deviceId, bool isOn) override;
         void notifyDeviceReset(nsecs_t when, int32_t deviceId) override;
         void notifyPointerCaptureChanged(nsecs_t when, bool hasCapture) override;
 
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index edab312..e6ea523 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -80,6 +80,7 @@
     virtual void notifySensor(nsecs_t when, int32_t deviceId, InputDeviceSensorType sensorType,
                               InputDeviceSensorAccuracy accuracy, bool accuracyChanged,
                               nsecs_t timestamp, std::vector<float> values) = 0;
+    virtual void notifyVibratorState(nsecs_t when, int32_t deviceId, bool isOn) = 0;
     virtual void notifyDeviceReset(nsecs_t when, int32_t deviceId) = 0;
     virtual void notifyPointerCaptureChanged(nsecs_t when, bool hasCapture) = 0;
 };
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
index f25e59a..2e4ab45 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
@@ -52,6 +52,8 @@
     mToken = token;
     mIndex = -1;
 
+    // Request InputReader to notify InputManagerService for vibration started.
+    getContext()->notifyVibratorState(systemTime(), getDeviceId(), true);
     nextStep();
 }
 
@@ -84,6 +86,9 @@
 }
 
 void VibratorInputMapper::nextStep() {
+#if DEBUG_VIBRATOR
+    ALOGD("nextStep: index=%d, vibrate deviceId=%d", (int)mIndex, getDeviceId());
+#endif
     mIndex += 1;
     if (size_t(mIndex) >= mSequence.pattern.size()) {
         if (mRepeat < 0) {
@@ -124,6 +129,9 @@
     ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId());
 #endif
     getDeviceContext().cancelVibrate();
+
+    // Request InputReader to notify InputManagerService for vibration complete.
+    getContext()->notifyVibratorState(systemTime(), getDeviceId(), false);
 }
 
 void VibratorInputMapper::dump(std::string& dump) {
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index c7e05eb..01945db 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -331,6 +331,8 @@
     void notifySensorAccuracy(int deviceId, InputDeviceSensorType sensorType,
                               InputDeviceSensorAccuracy accuracy) override {}
 
+    void notifyVibratorState(int32_t deviceId, bool isOn) override {}
+
     void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) override {
         *outConfig = mConfig;
     }
@@ -4215,4 +4217,27 @@
     mWindow->assertNoEvents();
 }
 
+TEST_F(InputDispatcherPointerCaptureTests, OutOfOrderRequests) {
+    requestAndVerifyPointerCapture(mWindow, true);
+
+    // The first window loses focus.
+    setFocusedWindow(mSecondWindow);
+    mFakePolicy->waitForSetPointerCapture(false);
+    mWindow->consumeCaptureEvent(false);
+
+    // Request Pointer Capture from the second window before the notification from InputReader
+    // arrives.
+    mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
+    mFakePolicy->waitForSetPointerCapture(true);
+
+    // InputReader notifies Pointer Capture was disabled (because of the focus change).
+    notifyPointerCaptureChanged(false);
+
+    // InputReader notifies Pointer Capture was enabled (because of mSecondWindow's request).
+    notifyPointerCaptureChanged(true);
+
+    mSecondWindow->consumeFocusEvent(true);
+    mSecondWindow->consumeCaptureEvent(true);
+}
+
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 0e88312..409c62a 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -409,7 +409,7 @@
 
     KeyedVector<int32_t, Device*> mDevices;
     std::vector<std::string> mExcludedDevices;
-    List<RawEvent> mEvents GUARDED_BY(mLock);
+    std::vector<RawEvent> mEvents GUARDED_BY(mLock);
     std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames;
     std::vector<int32_t> mVibrators = {0, 1};
 
@@ -722,16 +722,15 @@
         mExcludedDevices = devices;
     }
 
-    size_t getEvents(int, RawEvent* buffer, size_t) override {
-        std::scoped_lock<std::mutex> lock(mLock);
-        if (mEvents.empty()) {
-            return 0;
-        }
+    size_t getEvents(int, RawEvent* buffer, size_t bufferSize) override {
+        std::scoped_lock lock(mLock);
 
-        *buffer = *mEvents.begin();
-        mEvents.erase(mEvents.begin());
+        const size_t filledSize = std::min(mEvents.size(), bufferSize);
+        std::copy(mEvents.begin(), mEvents.begin() + filledSize, buffer);
+
+        mEvents.erase(mEvents.begin(), mEvents.begin() + filledSize);
         mEventsCondition.notify_all();
-        return 1;
+        return filledSize;
     }
 
     std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override {
@@ -2678,6 +2677,7 @@
 
 TEST_F(VibratorInputMapperTest, Vibrate) {
     constexpr uint8_t DEFAULT_AMPLITUDE = 192;
+    constexpr int32_t VIBRATION_TOKEN = 100;
     VibratorInputMapper& mapper = addMapperAndConfigure<VibratorInputMapper>();
 
     VibrationElement pattern(2);
@@ -2695,8 +2695,23 @@
     std::vector<uint8_t> amplitudes = {DEFAULT_AMPLITUDE, DEFAULT_AMPLITUDE / 2};
 
     ASSERT_FALSE(mapper.isVibrating());
-    mapper.vibrate(sequence, -1 /* repeat */, 0 /* token */);
+    // Start vibrating
+    mapper.vibrate(sequence, -1 /* repeat */, VIBRATION_TOKEN);
     ASSERT_TRUE(mapper.isVibrating());
+    // Verify vibrator state listener was notified.
+    mReader->loopOnce();
+    NotifyVibratorStateArgs args;
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyVibratorStateWasCalled(&args));
+    ASSERT_EQ(DEVICE_ID, args.deviceId);
+    ASSERT_TRUE(args.isOn);
+    // Stop vibrating
+    mapper.cancelVibrate(VIBRATION_TOKEN);
+    ASSERT_FALSE(mapper.isVibrating());
+    // Verify vibrator state listener was notified.
+    mReader->loopOnce();
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyVibratorStateWasCalled(&args));
+    ASSERT_EQ(DEVICE_ID, args.deviceId);
+    ASSERT_FALSE(args.isOn);
 }
 
 // --- SensorInputMapperTest ---
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index 295c6e3..fb7de97 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -86,6 +86,12 @@
                                            "Expected notifySensor() to have been called."));
 }
 
+void TestInputListener::assertNotifyVibratorStateWasCalled(NotifyVibratorStateArgs* outEventArgs) {
+    ASSERT_NO_FATAL_FAILURE(assertCalled<NotifyVibratorStateArgs>(outEventArgs,
+                                                                  "Expected notifyVibratorState() "
+                                                                  "to have been called."));
+}
+
 void TestInputListener::assertNotifyCaptureWasCalled(
         NotifyPointerCaptureChangedArgs* outEventArgs) {
     ASSERT_NO_FATAL_FAILURE(
@@ -165,4 +171,8 @@
     notify<NotifySensorArgs>(args);
 }
 
+void TestInputListener::notifyVibratorState(const NotifyVibratorStateArgs* args) {
+    notify<NotifyVibratorStateArgs>(args);
+}
+
 } // namespace android
diff --git a/services/inputflinger/tests/TestInputListener.h b/services/inputflinger/tests/TestInputListener.h
index e54350a..0ffcaaa 100644
--- a/services/inputflinger/tests/TestInputListener.h
+++ b/services/inputflinger/tests/TestInputListener.h
@@ -56,6 +56,7 @@
 
     void assertNotifyCaptureWasCalled(NotifyPointerCaptureChangedArgs* outEventArgs = nullptr);
     void assertNotifySensorWasCalled(NotifySensorArgs* outEventArgs = nullptr);
+    void assertNotifyVibratorStateWasCalled(NotifyVibratorStateArgs* outEventArgs = nullptr);
 
 private:
     template <class NotifyArgsType>
@@ -79,6 +80,8 @@
 
     virtual void notifySensor(const NotifySensorArgs* args) override;
 
+    virtual void notifyVibratorState(const NotifyVibratorStateArgs* args) override;
+
     virtual void notifyPointerCaptureChanged(const NotifyPointerCaptureChangedArgs* args) override;
 
     std::mutex mLock;
@@ -92,6 +95,7 @@
                std::vector<NotifyMotionArgs>,                //
                std::vector<NotifySwitchArgs>,                //
                std::vector<NotifySensorArgs>,                //
+               std::vector<NotifyVibratorStateArgs>,         //
                std::vector<NotifyPointerCaptureChangedArgs>> //
             mQueues GUARDED_BY(mLock);
 };
diff --git a/services/powermanager/Android.bp b/services/powermanager/Android.bp
index b5e6ae9..68f4f28 100644
--- a/services/powermanager/Android.bp
+++ b/services/powermanager/Android.bp
@@ -29,7 +29,7 @@
         "libutils",
         "android.hardware.power@1.0",
         "android.hardware.power@1.1",
-        "android.hardware.power-cpp",
+        "android.hardware.power-V1-cpp",
     ],
 
     cflags: [
diff --git a/services/powermanager/benchmarks/Android.bp b/services/powermanager/benchmarks/Android.bp
index 4c5d508..ad93a65 100644
--- a/services/powermanager/benchmarks/Android.bp
+++ b/services/powermanager/benchmarks/Android.bp
@@ -29,7 +29,7 @@
         "libutils",
         "android.hardware.power@1.0",
         "android.hardware.power@1.1",
-        "android.hardware.power-cpp",
+        "android.hardware.power-V1-cpp",
     ],
     static_libs: [
         "libtestUtil",
diff --git a/services/powermanager/tests/Android.bp b/services/powermanager/tests/Android.bp
index 49abc11..0f5037e 100644
--- a/services/powermanager/tests/Android.bp
+++ b/services/powermanager/tests/Android.bp
@@ -37,7 +37,7 @@
         "libutils",
         "android.hardware.power@1.0",
         "android.hardware.power@1.1",
-        "android.hardware.power-cpp",
+        "android.hardware.power-V1-cpp",
     ],
     static_libs: [
         "libgmock",
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index a7cd258..8d1258a 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -36,7 +36,7 @@
         "android.hardware.graphics.composer@2.4",
         "android.hardware.power@1.0",
         "android.hardware.power@1.3",
-        "android.hardware.power-cpp",
+        "android.hardware.power-V1-cpp",
         "libbase",
         "libbinder",
         "libcutils",
@@ -173,7 +173,7 @@
         "SurfaceFlingerDefaultFactory.cpp",
         "SurfaceInterceptor.cpp",
         "SurfaceTracing.cpp",
-        "TransactionCompletedThread.cpp",
+        "TransactionCallbackInvoker.cpp",
     ],
 }
 
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 39ae2fd..ec81ff7 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -377,7 +377,7 @@
                displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
         // The HWC doesn't support present fences, so use the refresh
         // timestamp instead.
-        const nsecs_t actualPresentTime = mFlinger->getHwComposer().getRefreshTimestamp(*displayId);
+        const nsecs_t actualPresentTime = display->getRefreshTimestamp();
         mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime);
         mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber,
                                                actualPresentTime,
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 5219787..3615a02 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -282,8 +282,7 @@
             mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
             mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
             if (mQueueItems[0].surfaceFrame) {
-                mQueueItems[0].surfaceFrame->setPresentState(PresentState::Dropped);
-                mFlinger->mFrameTimeline->addSurfaceFrame(mQueueItems[0].surfaceFrame);
+                addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame);
             }
             mQueueItems.erase(mQueueItems.begin());
             mQueuedFrames--;
@@ -298,8 +297,7 @@
             Mutex::Autolock lock(mQueueItemLock);
             for (auto& [item, surfaceFrame] : mQueueItems) {
                 if (surfaceFrame) {
-                    surfaceFrame->setPresentState(PresentState::Dropped);
-                    mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame);
+                    addSurfaceFrameDroppedForBuffer(surfaceFrame);
                 }
             }
             mQueueItems.clear();
@@ -329,8 +327,7 @@
             mConsumer->mergeSurfaceDamage(mQueueItems[0].item.mSurfaceDamage);
             mFlinger->mTimeStats->removeTimeRecord(layerId, mQueueItems[0].item.mFrameNumber);
             if (mQueueItems[0].surfaceFrame) {
-                mQueueItems[0].surfaceFrame->setPresentState(PresentState::Dropped);
-                mFlinger->mFrameTimeline->addSurfaceFrame(mQueueItems[0].surfaceFrame);
+                addSurfaceFrameDroppedForBuffer(mQueueItems[0].surfaceFrame);
             }
             mQueueItems.erase(mQueueItems.begin());
             mQueuedFrames--;
@@ -342,11 +339,9 @@
                                                FrameTracer::FrameEvent::LATCH);
 
         if (mQueueItems[0].surfaceFrame) {
-            mQueueItems[0].surfaceFrame->setAcquireFenceTime(
-                    mQueueItems[0].item.mFenceTime->getSignalTime());
-            mQueueItems[0].surfaceFrame->setPresentState(PresentState::Presented, mLastLatchTime);
-            mFlinger->mFrameTimeline->addSurfaceFrame(mQueueItems[0].surfaceFrame);
-            mLastLatchTime = latchTime;
+            addSurfaceFramePresentedForBuffer(mQueueItems[0].surfaceFrame,
+                                              mQueueItems[0].item.mFenceTime->getSignalTime(),
+                                              latchTime);
         }
         mQueueItems.erase(mQueueItems.begin());
     }
@@ -444,10 +439,7 @@
             }
         }
 
-        auto surfaceFrame =
-                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineInfo, mOwnerPid,
-                                                                     mOwnerUid, mName, mName);
-        surfaceFrame->setActualQueueTime(systemTime());
+        auto surfaceFrame = createSurfaceFrameForBuffer(mFrameTimelineInfo, systemTime(), mName);
 
         mQueueItems.push_back({item, surfaceFrame});
         mQueuedFrames++;
@@ -483,10 +475,7 @@
             return;
         }
 
-        auto surfaceFrame =
-                mFlinger->mFrameTimeline->createSurfaceFrameForToken(mFrameTimelineInfo, mOwnerPid,
-                                                                     mOwnerUid, mName, mName);
-        surfaceFrame->setActualQueueTime(systemTime());
+        auto surfaceFrame = createSurfaceFrameForBuffer(mFrameTimelineInfo, systemTime(), mName);
         mQueueItems[mQueueItems.size() - 1].item = item;
         mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame);
 
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 41ff012..0ea02e1 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -149,11 +149,6 @@
     // a buffer to correlate the buffer with the vsync id. Can only be accessed
     // with the SF state lock held.
     FrameTimelineInfo mFrameTimelineInfo;
-
-    // Keeps track of the time SF latched the last buffer from this layer.
-    // Used in buffer stuffing analysis in FrameTimeline.
-    // TODO(b/176106798): Find a way to do this for BLASTBufferQueue as well.
-    nsecs_t mLastLatchTime = 0;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 3dc62e3..cf87f62 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -28,6 +28,7 @@
 
 #include <limits>
 
+#include <FrameTimeline/FrameTimeline.h>
 #include <compositionengine/LayerFECompositionState.h>
 #include <gui/BufferQueue.h>
 #include <private/gui/SyncFeatures.h>
@@ -38,6 +39,7 @@
 
 namespace android {
 
+using PresentState = frametimeline::SurfaceFrame::PresentState;
 // clang-format off
 const std::array<float, 16> BufferStateLayer::IDENTITY_MATRIX{
         1, 0, 0, 0,
@@ -188,7 +190,7 @@
                 JankData(surfaceFrame->getToken(), surfaceFrame->getJankType().value()));
     }
 
-    mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
+    mFlinger->getTransactionCallbackInvoker().finalizePendingCallbackHandles(
             mDrawingState.callbackHandles, jankData);
 
     mDrawingState.callbackHandles = {};
@@ -335,7 +337,8 @@
 bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence,
                                  nsecs_t postTime, nsecs_t desiredPresentTime, bool isAutoTimestamp,
                                  const client_cache_t& clientCacheId, uint64_t frameNumber,
-                                 std::optional<nsecs_t> /* dequeueTime */) {
+                                 std::optional<nsecs_t> /* dequeueTime */,
+                                 const FrameTimelineInfo& info) {
     ATRACE_CALL();
 
     if (mCurrentState.buffer) {
@@ -345,6 +348,10 @@
             // before swapping to drawing state, then the first buffer will be
             // dropped and we should decrement the pending buffer count.
             decrementPendingBufferCount();
+            if (mCurrentState.bufferSurfaceFrameTX != nullptr) {
+                addSurfaceFrameDroppedForBuffer(mCurrentState.bufferSurfaceFrameTX);
+                mCurrentState.bufferSurfaceFrameTX.reset();
+            }
         }
     }
 
@@ -365,6 +372,11 @@
                                              LayerHistory::LayerUpdateType::Buffer);
 
     addFrameEvent(acquireFence, postTime, isAutoTimestamp ? 0 : desiredPresentTime);
+
+    if (info.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
+        setFrameTimelineVsyncForBufferTransaction(info, postTime);
+    }
+
     return true;
 }
 
@@ -443,14 +455,14 @@
 
             // Notify the transaction completed thread that there is a pending latched callback
             // handle
-            mFlinger->getTransactionCompletedThread().registerPendingCallbackHandle(handle);
+            mFlinger->getTransactionCallbackInvoker().registerPendingCallbackHandle(handle);
 
             // Store so latched time and release fence can be set
             mCurrentState.callbackHandles.push_back(handle);
 
         } else { // If this layer will NOT need to be relatched and presented this frame
             // Notify the transaction completed thread this handle is done
-            mFlinger->getTransactionCompletedThread().registerUnpresentedCallbackHandle(handle);
+            mFlinger->getTransactionCallbackInvoker().registerUnpresentedCallbackHandle(handle);
         }
     }
 
@@ -620,6 +632,17 @@
                                           std::make_shared<FenceTime>(mDrawingState.acquireFence));
     mFlinger->mTimeStats->setLatchTime(layerId, mDrawingState.frameNumber, latchTime);
 
+    auto& bufferSurfaceFrame = mDrawingState.bufferSurfaceFrameTX;
+    if (bufferSurfaceFrame != nullptr &&
+        bufferSurfaceFrame->getPresentState() != PresentState::Presented) {
+        // Update only if the bufferSurfaceFrame wasn't already presented. A Presented
+        // bufferSurfaceFrame could be seen here if a pending state was applied successfully and we
+        // are processing the next state.
+        addSurfaceFramePresentedForBuffer(bufferSurfaceFrame,
+                                          mDrawingState.acquireFence->getSignalTime(), latchTime);
+        bufferSurfaceFrame.reset();
+    }
+
     mCurrentStateModified = false;
 
     return NO_ERROR;
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index b93d567..ea832a2 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -72,7 +72,7 @@
     bool setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence>& acquireFence, nsecs_t postTime,
                    nsecs_t desiredPresentTime, bool isAutoTimestamp,
                    const client_cache_t& clientCacheId, uint64_t frameNumber,
-                   std::optional<nsecs_t> dequeueTime) override;
+                   std::optional<nsecs_t> dequeueTime, const FrameTimelineInfo& info) override;
     bool setAcquireFence(const sp<Fence>& fence) override;
     bool setDataspace(ui::Dataspace dataspace) override;
     bool setHdrMetadata(const HdrMetadata& hdrMetadata) override;
@@ -124,6 +124,8 @@
 
 private:
     friend class SlotGenerationTest;
+    friend class TransactionSurfaceFrameTest;
+
     inline void tracePendingBufferCount();
 
     bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
index 6559ed8..4502eee 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplaySurface.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include <ui/Size.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 #include <utils/StrongPointer.h>
@@ -71,7 +72,7 @@
 
     virtual void dumpAsString(String8& result) const = 0;
 
-    virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0;
+    virtual void resizeBuffers(const ui::Size&) = 0;
 
     virtual const sp<Fence>& getClientTargetAcquireFence() const = 0;
 };
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index c445d5b..8402149 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -34,6 +34,7 @@
 #include <gui/BufferQueue.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/GraphicTypes.h>
+#include <ui/StretchEffect.h>
 
 #include "DisplayHardware/Hal.h"
 
@@ -123,6 +124,8 @@
     // List of regions that require blur
     std::vector<BlurRegion> blurRegions;
 
+    StretchEffect stretchEffect;
+
     /*
      * Geometry state
      */
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
index 31b5f95..168e433 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplaySurface.h
@@ -18,6 +18,7 @@
 
 #include <compositionengine/DisplaySurface.h>
 #include <gmock/gmock.h>
+#include <ui/Size.h>
 #include <utils/String8.h>
 
 namespace android::compositionengine::mock {
@@ -32,7 +33,7 @@
     MOCK_METHOD0(advanceFrame, status_t());
     MOCK_METHOD0(onFrameCommitted, void());
     MOCK_CONST_METHOD1(dumpAsString, void(String8& result));
-    MOCK_METHOD2(resizeBuffers, void(uint32_t, uint32_t));
+    MOCK_METHOD1(resizeBuffers, void(const ui::Size&));
     MOCK_CONST_METHOD0(getClientTargetAcquireFence, const sp<Fence>&());
 };
 
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 4f99495..3907ac5 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -989,9 +989,16 @@
                    });
 
     const nsecs_t renderEngineStart = systemTime();
+    // Only use the framebuffer cache when rendering to an internal display
+    // TODO(b/173560331): This is only to help mitigate memory leaks from virtual displays because
+    // right now we don't have a concrete eviction policy for output buffers: GLESRenderEngine
+    // bounds its framebuffer cache but Skia RenderEngine has no current policy. The best fix is
+    // probably to encapsulate the output buffer into a structure that dispatches resource cleanup
+    // over to RenderEngine, in which case this flag can be removed from the drawLayers interface.
+    const bool useFramebufferCache = outputState.layerStackInternal;
     status_t status =
             renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayerPointers, buf,
-                                    /*useFramebufferCache=*/true, std::move(fd), &readyFence);
+                                    useFramebufferCache, std::move(fd), &readyFence);
 
     if (status != NO_ERROR && mClientCompositionRequestCache) {
         // If rendering was not successful, remove the request from the cache.
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index b47f7fd..3bef77d 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -96,8 +96,7 @@
 }
 
 void RenderSurface::setDisplaySize(const ui::Size& size) {
-    mDisplaySurface->resizeBuffers(static_cast<uint32_t>(size.width),
-                                   static_cast<uint32_t>(size.height));
+    mDisplaySurface->resizeBuffers(size);
     mSize = size;
 }
 
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 3133e90..ab00385 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -85,16 +85,15 @@
     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));
     MOCK_CONST_METHOD1(isConnected, bool(PhysicalDisplayId));
-    MOCK_CONST_METHOD1(getModes, DisplayModes(PhysicalDisplayId));
-    MOCK_CONST_METHOD1(getActiveMode, DisplayModePtr(PhysicalDisplayId));
+    MOCK_CONST_METHOD1(getModes, std::vector<HWComposer::HWCDisplayMode>(PhysicalDisplayId));
+    MOCK_CONST_METHOD1(getActiveMode, std::optional<hal::HWConfigId>(PhysicalDisplayId));
     MOCK_CONST_METHOD1(getColorModes, std::vector<ui::ColorMode>(PhysicalDisplayId));
     MOCK_METHOD3(setActiveColorMode, status_t(PhysicalDisplayId, ui::ColorMode, ui::RenderIntent));
     MOCK_CONST_METHOD0(isUsingVrComposer, bool());
     MOCK_CONST_METHOD1(getDisplayConnectionType, DisplayConnectionType(PhysicalDisplayId));
     MOCK_CONST_METHOD1(isVsyncPeriodSwitchSupported, bool(PhysicalDisplayId));
-    MOCK_CONST_METHOD1(getDisplayVsyncPeriod, nsecs_t(PhysicalDisplayId));
+    MOCK_CONST_METHOD2(getDisplayVsyncPeriod, status_t(PhysicalDisplayId, nsecs_t*));
     MOCK_METHOD4(setActiveModeWithConstraints,
                  status_t(PhysicalDisplayId, hal::HWConfigId,
                           const hal::VsyncPeriodChangeConstraints&,
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 376bac8..c4ae3a7 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3003,7 +3003,7 @@
             .WillRepeatedly(Return());
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, IsEmpty(), _, true, _, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, IsEmpty(), _, false, _, _))
             .WillRepeatedly(Return(NO_ERROR));
 
     verify().execute().expectAFenceWasReturned();
@@ -3030,6 +3030,36 @@
                     }));
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
+            .WillRepeatedly(Return(NO_ERROR));
+
+    verify().execute().expectAFenceWasReturned();
+}
+
+TEST_F(OutputComposeSurfacesTest,
+       buildsAndRendersRequestListAndCachesFramebufferForInternalLayers) {
+    LayerFE::LayerSettings r1;
+    LayerFE::LayerSettings r2;
+
+    r1.geometry.boundaries = FloatRect{1, 2, 3, 4};
+    r2.geometry.boundaries = FloatRect{5, 6, 7, 8};
+    const constexpr uint32_t kInternalLayerStack = 1234;
+    mOutput.setLayerStackFilter(kInternalLayerStack, true);
+
+    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), _))
+            .WillRepeatedly(
+                    Invoke([&](const Region&,
+                               std::vector<LayerFE::LayerSettings>& clientCompositionLayers) {
+                        clientCompositionLayers.emplace_back(r2);
+                    }));
+
+    EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
     EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
             .WillRepeatedly(Return(NO_ERROR));
 
@@ -3054,7 +3084,7 @@
             .WillRepeatedly(Return());
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
             .Times(2)
             .WillOnce(Return(NO_ERROR));
 
@@ -3083,7 +3113,7 @@
             .WillRepeatedly(Return());
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
             .WillOnce(Return(NO_ERROR));
     EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false));
 
@@ -3115,7 +3145,7 @@
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_))
             .WillOnce(Return(mOutputBuffer))
             .WillOnce(Return(otherOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
             .WillRepeatedly(Return(NO_ERROR));
 
     verify().execute().expectAFenceWasReturned();
@@ -3145,9 +3175,9 @@
             .WillRepeatedly(Return());
 
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, true, _, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r2)), _, false, _, _))
             .WillOnce(Return(NO_ERROR));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r3)), _, true, _, _))
+    EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(Pointee(r1), Pointee(r3)), _, false, _, _))
             .WillOnce(Return(NO_ERROR));
 
     verify().execute().expectAFenceWasReturned();
@@ -3197,7 +3227,7 @@
     struct ExpectDisplaySettingsState
           : public CallOrderStateMachineHelper<TestType, ExpectDisplaySettingsState> {
         auto thenExpectDisplaySettingsUsed(renderengine::DisplaySettings settings) {
-            EXPECT_CALL(getInstance()->mRenderEngine, drawLayers(settings, _, _, true, _, _))
+            EXPECT_CALL(getInstance()->mRenderEngine, drawLayers(settings, _, _, false, _, _))
                     .WillOnce(Return(NO_ERROR));
             return nextState<ExecuteState>();
         }
@@ -3296,7 +3326,7 @@
         EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
                 .WillRepeatedly(Return());
         EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-        EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, true, _, _))
+        EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _))
                 .WillRepeatedly(Return(NO_ERROR));
     }
 
@@ -3349,7 +3379,7 @@
     EXPECT_CALL(*mRenderSurface, setProtected(true));
     // Must happen after setting the protected content state.
     EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillRepeatedly(Return(mOutputBuffer));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, true, _, _)).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _)).WillOnce(Return(NO_ERROR));
 
     mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
 }
@@ -3419,7 +3449,7 @@
     InSequence seq;
 
     EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true));
-    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, true, _, _)).WillOnce(Return(NO_ERROR));
+    EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _)).WillOnce(Return(NO_ERROR));
 
     mOutput.composeSurfaces(kDebugRegion, kDefaultRefreshArgs);
 }
@@ -3434,7 +3464,7 @@
         EXPECT_CALL(mLayer.outputLayer, writeStateToHWC(false));
         EXPECT_CALL(mOutput, generateClientCompositionRequests(_, _, kDefaultOutputDataspace))
                 .WillOnce(Return(std::vector<LayerFE::LayerSettings>{}));
-        EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, true, _, _)).WillOnce(Return(NO_ERROR));
+        EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, false, _, _)).WillOnce(Return(NO_ERROR));
         EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u));
         EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
                 .WillRepeatedly(Return(&mLayer.outputLayer));
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index cd39733..5ef5d7b 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -119,9 +119,10 @@
  */
 
 TEST_F(RenderSurfaceTest, setDisplaySizeAppliesChange) {
-    EXPECT_CALL(*mDisplaySurface, resizeBuffers(640, 480)).Times(1);
+    const ui::Size size(640, 480);
+    EXPECT_CALL(*mDisplaySurface, resizeBuffers(size)).Times(1);
 
-    mSurface.setDisplaySize(ui::Size(640, 480));
+    mSurface.setDisplaySize(size);
 }
 
 /*
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b4a3ed1..c751f22 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -179,6 +179,31 @@
     return nullptr;
 }
 
+nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const {
+    const auto physicalId = getPhysicalId();
+    if (!mHwComposer.isConnected(physicalId)) {
+        return 0;
+    }
+
+    nsecs_t vsyncPeriod;
+    const auto status = mHwComposer.getDisplayVsyncPeriod(physicalId, &vsyncPeriod);
+    if (status == NO_ERROR) {
+        return vsyncPeriod;
+    }
+
+    return getActiveMode()->getFps().getPeriodNsecs();
+}
+
+nsecs_t DisplayDevice::getRefreshTimestamp() const {
+    const nsecs_t now = systemTime(CLOCK_MONOTONIC);
+    const auto vsyncPeriodNanos = getVsyncPeriodFromHWC();
+    return now - ((now - mLastHwVsync) % vsyncPeriodNanos);
+}
+
+void DisplayDevice::onVsync(nsecs_t timestamp) {
+    mLastHwVsync = timestamp;
+}
+
 ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
     return mCompositionDisplay->getState().dataspace;
 }
@@ -240,7 +265,8 @@
     StringAppendF(&result, "+ %s\n", getDebugName().c_str());
     StringAppendF(&result, "   powerMode=%s (%d)\n", to_string(mPowerMode).c_str(),
                   static_cast<int32_t>(mPowerMode));
-    StringAppendF(&result, "   activeMode=%s\n", to_string(*getActiveMode()).c_str());
+    StringAppendF(&result, "   activeMode=%s\n",
+                  mSupportedModes.size() ? to_string(*getActiveMode()).c_str() : "none");
 
     result.append("   supportedModes=\n");
 
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 6f07964..b4db933 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -176,6 +176,10 @@
     // set-top boxes after a hotplug reconnect.
     DisplayModePtr getMode(DisplayModeId) const;
 
+    void onVsync(nsecs_t timestamp);
+    nsecs_t getVsyncPeriodFromHWC() const;
+    nsecs_t getRefreshTimestamp() const;
+
     // release HWC resources (if any) for removable displays
     void disconnect();
 
@@ -207,6 +211,8 @@
     DisplayModeId mActiveModeId;
     const DisplayModes mSupportedModes;
 
+    std::atomic<nsecs_t> mLastHwVsync = 0;
+
     // TODO(b/74619554): Remove special cases for primary display.
     const bool mIsPrimary;
 
diff --git a/services/surfaceflinger/DisplayHardware/DisplayMode.h b/services/surfaceflinger/DisplayHardware/DisplayMode.h
index 61c1b61..1f0f3c3 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayMode.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayMode.h
@@ -22,6 +22,7 @@
 
 #include <android-base/stringprintf.h>
 #include <android/configuration.h>
+#include <ui/Size.h>
 #include <utils/Timers.h>
 
 #include <cstddef>
@@ -85,8 +86,8 @@
             return *this;
         }
 
-        Builder& setConfigGroup(int32_t configGroup) {
-            mDisplayMode->mConfigGroup = configGroup;
+        Builder& setGroup(int32_t group) {
+            mDisplayMode->mGroup = group;
             return *this;
         }
 
@@ -113,11 +114,15 @@
 
     int32_t getWidth() const { return mWidth; }
     int32_t getHeight() const { return mHeight; }
+    ui::Size getSize() const { return {mWidth, mHeight}; }
     Fps getFps() const { return mFps; }
     nsecs_t getVsyncPeriod() const { return mFps.getPeriodNsecs(); }
     float getDpiX() const { return mDpiX; }
     float getDpiY() const { return mDpiY; }
-    int32_t getConfigGroup() const { return mConfigGroup; }
+
+    // Switches between modes in the same group are seamless, i.e.
+    // without visual interruptions such as a black screen.
+    int32_t getGroup() const { return mGroup; }
 
 private:
     explicit DisplayMode(hal::HWConfigId id) : mHwcId(id) {}
@@ -130,15 +135,15 @@
     Fps mFps;
     float mDpiX = -1;
     float mDpiY = -1;
-    int32_t mConfigGroup = -1;
+    int32_t mGroup = -1;
 };
 
 inline std::string to_string(const DisplayMode& mode) {
     return base::StringPrintf("{id=%zu, hwcId=%d, width=%d, height=%d, refreshRate=%s, "
-                              "dpiX=%.2f, dpiY=%.2f, configGroup=%d}",
+                              "dpiX=%.2f, dpiY=%.2f, group=%d}",
                               mode.getId().value(), mode.getHwcId(), mode.getWidth(),
                               mode.getHeight(), to_string(mode.getFps()).c_str(), mode.getDpiX(),
-                              mode.getDpiY(), mode.getConfigGroup());
+                              mode.getDpiY(), mode.getGroup());
 }
 
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 3e856bb..f7fc162 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -58,11 +58,10 @@
 
 FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId,
                                        const sp<IGraphicBufferConsumer>& consumer,
-                                       uint32_t maxWidth, uint32_t maxHeight)
+                                       const ui::Size& size, const ui::Size& maxSize)
       : ConsumerBase(consumer),
         mDisplayId(displayId),
-        mMaxWidth(maxWidth),
-        mMaxHeight(maxHeight),
+        mMaxSize(maxSize),
         mCurrentBufferSlot(-1),
         mCurrentBuffer(),
         mCurrentFence(Fence::NO_FENCE),
@@ -77,15 +76,14 @@
     mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
                                        GRALLOC_USAGE_HW_RENDER |
                                        GRALLOC_USAGE_HW_COMPOSER);
-    const auto& activeMode = mHwc.getActiveMode(displayId);
-    ui::Size limitedSize = limitFramebufferSize(activeMode->getWidth(), activeMode->getHeight());
+    const auto limitedSize = limitFramebufferSize(size);
     mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
     mConsumer->setMaxAcquiredBufferCount(
             SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
 }
 
-void FramebufferSurface::resizeBuffers(uint32_t width, uint32_t height) {
-    ui::Size limitedSize = limitFramebufferSize(width, height);
+void FramebufferSurface::resizeBuffers(const ui::Size& newSize) {
+    const auto limitedSize = limitFramebufferSize(newSize);
     mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
 }
 
@@ -181,24 +179,24 @@
     }
 }
 
-ui::Size FramebufferSurface::limitFramebufferSize(uint32_t width, uint32_t height) {
-    ui::Size framebufferSize(width, height);
-    bool wasLimited = true;
-    if (width > mMaxWidth && mMaxWidth != 0) {
-        float aspectRatio = float(width) / float(height);
-        framebufferSize.height = mMaxWidth / aspectRatio;
-        framebufferSize.width = mMaxWidth;
+ui::Size FramebufferSurface::limitFramebufferSize(const ui::Size& size) {
+    ui::Size limitedSize = size;
+    bool wasLimited = false;
+    if (size.width > mMaxSize.width && mMaxSize.width != 0) {
+        const float aspectRatio = static_cast<float>(size.width) / size.height;
+        limitedSize.height = mMaxSize.width / aspectRatio;
+        limitedSize.width = mMaxSize.width;
         wasLimited = true;
     }
-    if (height > mMaxHeight && mMaxHeight != 0) {
-        float aspectRatio = float(width) / float(height);
-        framebufferSize.height = mMaxHeight;
-        framebufferSize.width = mMaxHeight * aspectRatio;
+    if (size.height > mMaxSize.height && mMaxSize.height != 0) {
+        const float aspectRatio = static_cast<float>(size.width) / size.height;
+        limitedSize.height = mMaxSize.height;
+        limitedSize.width = mMaxSize.height * aspectRatio;
         wasLimited = true;
     }
     ALOGI_IF(wasLimited, "framebuffer size has been limited to [%dx%d] from [%dx%d]",
-             framebufferSize.width, framebufferSize.height, width, height);
-    return framebufferSize;
+             limitedSize.width, limitedSize.height, size.width, size.height);
+    return limitedSize;
 }
 
 void FramebufferSurface::dumpAsString(String8& result) const {
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 759943a..5d1e131 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -41,8 +41,8 @@
 class FramebufferSurface : public ConsumerBase, public compositionengine::DisplaySurface {
 public:
     FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId,
-                       const sp<IGraphicBufferConsumer>& consumer, uint32_t maxWidth,
-                       uint32_t maxHeight);
+                       const sp<IGraphicBufferConsumer>& consumer, const ui::Size& size,
+                       const ui::Size& maxSize);
 
     virtual status_t beginFrame(bool mustRecompose);
     virtual status_t prepareFrame(CompositionType compositionType);
@@ -50,7 +50,7 @@
     virtual void onFrameCommitted();
     virtual void dumpAsString(String8& result) const;
 
-    virtual void resizeBuffers(uint32_t width, uint32_t height);
+    virtual void resizeBuffers(const ui::Size&) override;
 
     virtual const sp<Fence>& getClientTargetAcquireFence() const override;
 
@@ -62,7 +62,7 @@
     virtual void dumpLocked(String8& result, const char* prefix) const;
 
     // Limits the width and height by the maximum width specified in the constructor.
-    ui::Size limitFramebufferSize(uint32_t width, uint32_t height);
+    ui::Size limitFramebufferSize(const ui::Size&);
 
     // nextBuffer waits for and then latches the next buffer from the
     // BufferQueue and releases the previously latched buffer to the
@@ -74,11 +74,7 @@
 
     // Framebuffer size has a dimension limitation in pixels based on the graphics capabilities of
     // the device.
-    const uint32_t mMaxWidth;
-
-    // Framebuffer size has a dimension limitation in pixels based on the graphics capabilities of
-    // the device.
-    const uint32_t mMaxHeight;
+    const ui::Size mMaxSize;
 
     // mCurrentBufferIndex is the slot index of the current buffer or
     // INVALID_BUFFER_SLOT to indicate that either there is no current buffer
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 46dc54e..b9a8e4b 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -223,8 +223,6 @@
                  __FUNCTION__, to_string(*displayId).c_str());
 
     {
-        std::lock_guard lock(displayData.lastHwVsyncLock);
-
         // There have been reports of HWCs that signal several vsync events
         // with the same timestamp when turning the display off and on. This
         // is a bug in the HWC implementation, but filter the extra events
@@ -295,11 +293,10 @@
                                                   hal::DisplayType::PHYSICAL);
     newDisplay->setConnected(true);
     displayData.hwcDisplay = std::move(newDisplay);
-    loadModes(displayData, hwcDisplayId);
 }
 
 int32_t HWComposer::getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId configId,
-                                 hal::Attribute attribute) {
+                                 hal::Attribute attribute) const {
     int32_t value = 0;
     auto error = static_cast<hal::Error>(
             mComposer->getDisplayAttribute(hwcDisplayId, configId, attribute, &value));
@@ -308,30 +305,6 @@
     return value;
 }
 
-void HWComposer::loadModes(DisplayData& displayData, hal::HWDisplayId hwcDisplayId) {
-    ALOGV("[HWC display %" PRIu64 "] %s", hwcDisplayId, __FUNCTION__);
-
-    std::vector<hal::HWConfigId> configIds;
-    auto error = static_cast<hal::Error>(mComposer->getDisplayConfigs(hwcDisplayId, &configIds));
-    RETURN_IF_HWC_ERROR_FOR("getDisplayConfigs", error, *toPhysicalDisplayId(hwcDisplayId));
-
-    displayData.modes.clear();
-    for (auto configId : configIds) {
-        auto mode = DisplayMode::Builder(configId)
-                            .setId(DisplayModeId(displayData.modes.size()))
-                            .setWidth(getAttribute(hwcDisplayId, configId, hal::Attribute::WIDTH))
-                            .setHeight(getAttribute(hwcDisplayId, configId, hal::Attribute::HEIGHT))
-                            .setVsyncPeriod(getAttribute(hwcDisplayId, configId,
-                                                         hal::Attribute::VSYNC_PERIOD))
-                            .setDpiX(getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X))
-                            .setDpiY(getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y))
-                            .setConfigGroup(getAttribute(hwcDisplayId, configId,
-                                                         hal::Attribute::CONFIG_GROUP))
-                            .build();
-        displayData.modes.push_back(std::move(mode));
-    }
-}
-
 HWC2::Layer* HWComposer::createLayer(HalDisplayId displayId) {
     RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
 
@@ -348,55 +321,50 @@
     RETURN_IF_HWC_ERROR(error, displayId);
 }
 
-nsecs_t HWComposer::getRefreshTimestamp(PhysicalDisplayId displayId) const {
-    RETURN_IF_INVALID_DISPLAY(displayId, 0);
-    const auto& displayData = mDisplayData.at(displayId);
-    // this returns the last refresh timestamp.
-    // if the last one is not available, we estimate it based on
-    // the refresh period and whatever closest timestamp we have.
-    std::lock_guard lock(displayData.lastHwVsyncLock);
-    nsecs_t now = systemTime(CLOCK_MONOTONIC);
-    auto vsyncPeriodNanos = getDisplayVsyncPeriod(displayId);
-    return now - ((now - displayData.lastHwVsync) % vsyncPeriodNanos);
-}
-
 bool HWComposer::isConnected(PhysicalDisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, false);
     return mDisplayData.at(displayId).hwcDisplay->isConnected();
 }
 
-DisplayModes HWComposer::getModes(PhysicalDisplayId displayId) const {
+std::vector<HWComposer::HWCDisplayMode> HWComposer::getModes(PhysicalDisplayId displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, {});
 
-    // We cache the modes when the DisplayData is created on hotplug. If the modes need to
-    // change HWC will send a hotplug event which will recreate displayData.
-    return mDisplayData.at(displayId).modes;
+    const auto hwcDisplayId = mDisplayData.at(displayId).hwcDisplay->getId();
+    std::vector<hal::HWConfigId> configIds;
+    auto error = static_cast<hal::Error>(mComposer->getDisplayConfigs(hwcDisplayId, &configIds));
+    RETURN_IF_HWC_ERROR_FOR("getDisplayConfigs", error, *toPhysicalDisplayId(hwcDisplayId), {});
+
+    std::vector<HWCDisplayMode> modes;
+    modes.reserve(configIds.size());
+    for (auto configId : configIds) {
+        modes.push_back(HWCDisplayMode{
+                .hwcId = configId,
+                .width = getAttribute(hwcDisplayId, configId, hal::Attribute::WIDTH),
+                .height = getAttribute(hwcDisplayId, configId, hal::Attribute::HEIGHT),
+                .vsyncPeriod = getAttribute(hwcDisplayId, configId, hal::Attribute::VSYNC_PERIOD),
+                .dpiX = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_X),
+                .dpiY = getAttribute(hwcDisplayId, configId, hal::Attribute::DPI_Y),
+                .configGroup = getAttribute(hwcDisplayId, configId, hal::Attribute::CONFIG_GROUP),
+        });
+    }
+
+    return modes;
 }
 
-DisplayModePtr HWComposer::getActiveMode(PhysicalDisplayId displayId) const {
-    RETURN_IF_INVALID_DISPLAY(displayId, nullptr);
+std::optional<hal::HWConfigId> HWComposer::getActiveMode(PhysicalDisplayId displayId) const {
+    RETURN_IF_INVALID_DISPLAY(displayId, std::nullopt);
 
     const auto hwcId = *fromPhysicalDisplayId(displayId);
     ALOGV("[%" PRIu64 "] getActiveMode", hwcId);
     hal::HWConfigId configId;
     auto error = static_cast<hal::Error>(mComposer->getActiveConfig(hwcId, &configId));
 
-    const auto& modes = mDisplayData.at(displayId).modes;
     if (error == hal::Error::BAD_CONFIG) {
         LOG_DISPLAY_ERROR(displayId, "No active mode");
-        return nullptr;
+        return std::nullopt;
     }
 
-    RETURN_IF_HWC_ERROR(error, displayId, nullptr);
-
-    const auto it = std::find_if(modes.begin(), modes.end(),
-                                 [configId](auto mode) { return mode->getHwcId() == configId; });
-    if (it == modes.end()) {
-        LOG_DISPLAY_ERROR(displayId, "Unknown mode");
-        return nullptr;
-    }
-
-    return *it;
+    return configId;
 }
 
 // Composer 2.4
@@ -421,27 +389,20 @@
     return mDisplayData.at(displayId).hwcDisplay->isVsyncPeriodSwitchSupported();
 }
 
-nsecs_t HWComposer::getDisplayVsyncPeriod(PhysicalDisplayId displayId) const {
+status_t HWComposer::getDisplayVsyncPeriod(PhysicalDisplayId displayId,
+                                           nsecs_t* outVsyncPeriod) const {
     RETURN_IF_INVALID_DISPLAY(displayId, 0);
 
-    if (isVsyncPeriodSwitchSupported(displayId)) {
-        const auto hwcId = *fromPhysicalDisplayId(displayId);
-        Hwc2::VsyncPeriodNanos vsyncPeriodNanos = 0;
-        auto error =
-                static_cast<hal::Error>(mComposer->getDisplayVsyncPeriod(hwcId, &vsyncPeriodNanos));
-        RETURN_IF_HWC_ERROR(error, displayId, 0);
-        return static_cast<nsecs_t>(vsyncPeriodNanos);
+    if (!isVsyncPeriodSwitchSupported(displayId)) {
+        return INVALID_OPERATION;
     }
-
-    // Get the default vsync period
-    auto mode = getActiveMode(displayId);
-
-    if (!mode) {
-        // HWC has updated the display modes and hasn't notified us yet.
-        RETURN_IF_HWC_ERROR(hal::Error::BAD_CONFIG, displayId, 0);
-    }
-
-    return mode->getVsyncPeriod();
+    const auto hwcId = *fromPhysicalDisplayId(displayId);
+    Hwc2::VsyncPeriodNanos vsyncPeriodNanos = 0;
+    auto error =
+            static_cast<hal::Error>(mComposer->getDisplayVsyncPeriod(hwcId, &vsyncPeriodNanos));
+    RETURN_IF_HWC_ERROR(error, displayId, 0);
+    *outVsyncPeriod = static_cast<nsecs_t>(vsyncPeriodNanos);
+    return NO_ERROR;
 }
 
 std::vector<ui::ColorMode> HWComposer::getColorModes(PhysicalDisplayId displayId) const {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 1ffe276..f9c8e2e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -83,6 +83,16 @@
         ClientTargetProperty clientTargetProperty;
     };
 
+    struct HWCDisplayMode {
+        hal::HWConfigId hwcId;
+        int32_t width = -1;
+        int32_t height = -1;
+        nsecs_t vsyncPeriod = -1;
+        int32_t dpiX = -1;
+        int32_t dpiY = -1;
+        int32_t configGroup = -1;
+    };
+
     virtual ~HWComposer();
 
     virtual void setConfiguration(HWC2::ComposerCallback* callback, int32_t sequenceId) = 0;
@@ -182,12 +192,11 @@
     virtual bool onVsync(hal::HWDisplayId, int64_t timestamp) = 0;
     virtual void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) = 0;
 
-    virtual nsecs_t getRefreshTimestamp(PhysicalDisplayId) const = 0;
     virtual bool isConnected(PhysicalDisplayId) const = 0;
 
-    virtual DisplayModes getModes(PhysicalDisplayId) const = 0;
+    virtual std::vector<HWCDisplayMode> getModes(PhysicalDisplayId) const = 0;
 
-    virtual DisplayModePtr getActiveMode(PhysicalDisplayId) const = 0;
+    virtual std::optional<hal::HWConfigId> getActiveMode(PhysicalDisplayId) const = 0;
 
     virtual std::vector<ui::ColorMode> getColorModes(PhysicalDisplayId) const = 0;
 
@@ -197,7 +206,8 @@
     // Composer 2.4
     virtual DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const = 0;
     virtual bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const = 0;
-    virtual nsecs_t getDisplayVsyncPeriod(PhysicalDisplayId) const = 0;
+    virtual status_t getDisplayVsyncPeriod(PhysicalDisplayId displayId,
+                                           nsecs_t* outVsyncPeriod) const = 0;
     virtual status_t setActiveModeWithConstraints(PhysicalDisplayId, hal::HWConfigId,
                                                   const hal::VsyncPeriodChangeConstraints&,
                                                   hal::VsyncPeriodChangeTimeline* outTimeline) = 0;
@@ -314,12 +324,11 @@
     bool onVsync(hal::HWDisplayId, int64_t timestamp) override;
     void setVsyncEnabled(PhysicalDisplayId, hal::Vsync enabled) override;
 
-    nsecs_t getRefreshTimestamp(PhysicalDisplayId) const override;
     bool isConnected(PhysicalDisplayId) const override;
 
-    DisplayModes getModes(PhysicalDisplayId) const override;
+    std::vector<HWCDisplayMode> getModes(PhysicalDisplayId) const override;
 
-    DisplayModePtr getActiveMode(PhysicalDisplayId) const override;
+    std::optional<hal::HWConfigId> getActiveMode(PhysicalDisplayId) const override;
 
     std::vector<ui::ColorMode> getColorModes(PhysicalDisplayId) const override;
 
@@ -328,7 +337,8 @@
     // Composer 2.4
     DisplayConnectionType getDisplayConnectionType(PhysicalDisplayId) const override;
     bool isVsyncPeriodSwitchSupported(PhysicalDisplayId) const override;
-    nsecs_t getDisplayVsyncPeriod(PhysicalDisplayId displayId) const override;
+    status_t getDisplayVsyncPeriod(PhysicalDisplayId displayId,
+                                   nsecs_t* outVsyncPeriod) const override;
     status_t setActiveModeWithConstraints(PhysicalDisplayId, hal::HWConfigId,
                                           const hal::VsyncPeriodChangeConstraints&,
                                           hal::VsyncPeriodChangeTimeline* outTimeline) override;
@@ -365,7 +375,6 @@
         std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
         buffer_handle_t outbufHandle = nullptr;
         sp<Fence> outbufAcquireFence = Fence::NO_FENCE;
-        DisplayModes modes;
 
         bool validateWasSkipped;
         hal::Error presentError;
@@ -375,8 +384,7 @@
         std::mutex vsyncEnabledLock;
         hal::Vsync vsyncEnabled GUARDED_BY(vsyncEnabledLock) = hal::Vsync::DISABLE;
 
-        mutable std::mutex lastHwVsyncLock;
-        nsecs_t lastHwVsync GUARDED_BY(lastHwVsyncLock) = 0;
+        nsecs_t lastHwVsync = 0;
     };
 
     std::optional<DisplayIdentificationInfo> onHotplugConnect(hal::HWDisplayId);
@@ -384,8 +392,7 @@
     bool shouldIgnoreHotplugConnect(hal::HWDisplayId, bool hasDisplayIdentificationData) const;
 
     int32_t getAttribute(hal::HWDisplayId hwcDisplayId, hal::HWConfigId configId,
-                         hal::Attribute attribute);
-    void loadModes(DisplayData& displayData, hal::HWDisplayId hwcDisplayId);
+                         hal::Attribute attribute) const;
 
     void loadCapabilities();
     void loadLayerMetadataSupport();
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 2ac67cb..e26ab11 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -291,11 +291,11 @@
 void VirtualDisplaySurface::dumpAsString(String8& /* result */) const {
 }
 
-void VirtualDisplaySurface::resizeBuffers(const uint32_t w, const uint32_t h) {
-    mQueueBufferOutput.width = w;
-    mQueueBufferOutput.height = h;
-    mSinkBufferWidth = w;
-    mSinkBufferHeight = h;
+void VirtualDisplaySurface::resizeBuffers(const ui::Size& newSize) {
+    mQueueBufferOutput.width = newSize.width;
+    mQueueBufferOutput.height = newSize.height;
+    mSinkBufferWidth = newSize.width;
+    mSinkBufferHeight = newSize.height;
 }
 
 const sp<Fence>& VirtualDisplaySurface::getClientTargetAcquireFence() const {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index fba0e3b..bbb6306 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -90,7 +90,7 @@
     virtual status_t advanceFrame();
     virtual void onFrameCommitted();
     virtual void dumpAsString(String8& result) const;
-    virtual void resizeBuffers(const uint32_t w, const uint32_t h);
+    virtual void resizeBuffers(const ui::Size&) override;
     virtual const sp<Fence>& getClientTargetAcquireFence() const override;
 
 private:
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 3743716..3f833f4 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -312,6 +312,10 @@
 
 void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchTime) {
     std::scoped_lock lock(mMutex);
+    LOG_ALWAYS_FATAL_IF(mPresentState != PresentState::Unknown,
+                        "setPresentState called on a SurfaceFrame from Layer - %s, that has a "
+                        "PresentState - %s set already.",
+                        mDebugName.c_str(), toString(mPresentState).c_str());
     mPresentState = presentState;
     mLastLatchTime = lastLatchTime;
 }
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 08a5f0f..27b2b87 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -488,6 +488,7 @@
     compositionState->alpha = alpha;
     compositionState->backgroundBlurRadius = drawingState.backgroundBlurRadius;
     compositionState->blurRegions = drawingState.blurRegions;
+    compositionState->stretchEffect = drawingState.stretchEffect;
 }
 
 void Layer::prepareGeometryCompositionState() {
@@ -556,8 +557,8 @@
             isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
 
     // Force client composition for special cases known only to the front-end.
-    if (isHdrY410() || usesRoundedCorners || drawShadows() ||
-        getDrawingState().blurRegions.size() > 0) {
+    if (isHdrY410() || usesRoundedCorners || drawShadows() || drawingState.blurRegions.size() > 0 ||
+        drawingState.stretchEffect.hasEffect()) {
         compositionState->forceClientComposition = true;
     }
 }
@@ -656,6 +657,7 @@
         layerSettings.backgroundBlurRadius = getBackgroundBlurRadius();
         layerSettings.blurRegions = getBlurRegions();
     }
+    layerSettings.stretchEffect = getDrawingState().stretchEffect;
     // Record the name of the layer for debugging further down the stack.
     layerSettings.name = getName();
     return layerSettings;
@@ -841,13 +843,33 @@
         setTransactionFlags(eTransactionNeeded);
         mFlinger->setTransactionFlags(eTraversalNeeded);
     }
+    if (mCurrentState.bufferlessSurfaceFramesTX.size() >= State::kStateSurfaceFramesThreshold) {
+        // Ideally, the currentState would only contain one SurfaceFrame per transaction (assuming
+        // each Tx uses a different token). We don't expect the current state to hold a huge amount
+        // of SurfaceFrames. However, in the event it happens, this debug statement will leave a
+        // trail that can help in debugging.
+        ALOGW("Bufferless SurfaceFrames size on current state of layer %s is %" PRIu32 "",
+              mName.c_str(), static_cast<uint32_t>(mCurrentState.bufferlessSurfaceFramesTX.size()));
+    }
     mPendingStates.push_back(mCurrentState);
+    // Since the current state along with the SurfaceFrames has been pushed into the pendingState,
+    // we no longer need to retain them. If multiple states are pushed and applied together, we have
+    // a merging logic to address the SurfaceFrames at mergeSurfaceFrames().
+    mCurrentState.bufferlessSurfaceFramesTX.clear();
     ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
 }
 
+void Layer::mergeSurfaceFrames(State& source, State& target) {
+    // No need to merge BufferSurfaceFrame as the target's surfaceFrame, if it exists, will be used
+    // directly. Dropping of source's SurfaceFrame is taken care of at setBuffer().
+    target.bufferlessSurfaceFramesTX.merge(source.bufferlessSurfaceFramesTX);
+    source.bufferlessSurfaceFramesTX.clear();
+}
+
 void Layer::popPendingState(State* stateToCommit) {
     ATRACE_CALL();
 
+    mergeSurfaceFrames(*stateToCommit, mPendingStates[0]);
     *stateToCommit = mPendingStates[0];
     mPendingStates.pop_front();
     ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
@@ -906,20 +928,6 @@
         mFlinger->setTraversalNeeded();
     }
 
-    if (stateUpdateAvailable) {
-        mSurfaceFrame =
-                mFlinger->mFrameTimeline
-                        ->createSurfaceFrameForToken(stateToCommit->frameTimelineInfo, mOwnerPid,
-                                                     mOwnerUid, mName, mTransactionName);
-        mSurfaceFrame->setActualQueueTime(stateToCommit->postTime);
-        // For transactions we set the acquire fence time to the post time as we
-        // don't have a buffer. For BufferStateLayer it is overridden in
-        // BufferStateLayer::applyPendingStates
-        mSurfaceFrame->setAcquireFenceTime(stateToCommit->postTime);
-
-        onSurfaceFrameCreated(mSurfaceFrame);
-    }
-
     mCurrentState.modified = false;
     return stateUpdateAvailable;
 }
@@ -1048,10 +1056,22 @@
     return flags;
 }
 
-void Layer::commitTransaction(const State& stateToCommit) {
+void Layer::commitTransaction(State& stateToCommit) {
     mDrawingState = stateToCommit;
-    mSurfaceFrame->setPresentState(PresentState::Presented);
-    mFlinger->mFrameTimeline->addSurfaceFrame(mSurfaceFrame);
+
+    // Set the present state for all bufferlessSurfaceFramesTX to Presented. The
+    // bufferSurfaceFrameTX will be presented in latchBuffer.
+    for (auto& [token, surfaceFrame] : mDrawingState.bufferlessSurfaceFramesTX) {
+        if (surfaceFrame->getPresentState() != PresentState::Presented) {
+            // With applyPendingStates, we could end up having presented surfaceframes from previous
+            // states
+            surfaceFrame->setPresentState(PresentState::Presented);
+            mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame);
+        }
+    }
+    // Clear the surfaceFrames from the old state now that it has been copied into DrawingState.
+    stateToCommit.bufferSurfaceFrameTX.reset();
+    stateToCommit.bufferlessSurfaceFramesTX.clear();
 }
 
 uint32_t Layer::getTransactionFlags(uint32_t flags) {
@@ -1403,6 +1423,19 @@
     return true;
 }
 
+bool Layer::setStretchEffect(const StretchEffect& effect) {
+    StretchEffect temp = effect;
+    temp.sanitize();
+    if (mCurrentState.stretchEffect == temp) {
+        return false;
+    }
+    mCurrentState.sequence++;
+    mCurrentState.stretchEffect = temp;
+    mCurrentState.modified = true;
+    setTransactionFlags(eTransactionNeeded);
+    return true;
+}
+
 void Layer::updateTreeHasFrameRateVote() {
     const auto traverseTree = [&](const LayerVector::Visitor& visitor) {
         auto parent = getParent();
@@ -1474,11 +1507,94 @@
     return true;
 }
 
-void Layer::setFrameTimelineInfoForTransaction(const FrameTimelineInfo& info, nsecs_t postTime) {
+void Layer::setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info,
+                                                      nsecs_t postTime) {
+    mCurrentState.postTime = postTime;
+
+    // Check if one of the bufferlessSurfaceFramesTX contains the same vsyncId. This can happen if
+    // there are two transactions with the same token, the first one without a buffer and the
+    // second one with a buffer. We promote the bufferlessSurfaceFrame to a bufferSurfaceFrameTX
+    // in that case.
+    auto it = mCurrentState.bufferlessSurfaceFramesTX.find(info.vsyncId);
+    if (it != mCurrentState.bufferlessSurfaceFramesTX.end()) {
+        // Promote the bufferlessSurfaceFrame to a bufferSurfaceFrameTX
+        mCurrentState.bufferSurfaceFrameTX = it->second;
+        mCurrentState.bufferlessSurfaceFramesTX.erase(it);
+        mCurrentState.bufferSurfaceFrameTX->setActualQueueTime(postTime);
+    } else {
+        mCurrentState.bufferSurfaceFrameTX =
+                createSurfaceFrameForBuffer(info, postTime, mTransactionName);
+    }
+}
+
+void Layer::setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info,
+                                                          nsecs_t postTime) {
     mCurrentState.frameTimelineInfo = info;
     mCurrentState.postTime = postTime;
     mCurrentState.modified = true;
     setTransactionFlags(eTransactionNeeded);
+
+    if (const auto& bufferSurfaceFrameTX = mCurrentState.bufferSurfaceFrameTX;
+        bufferSurfaceFrameTX != nullptr) {
+        if (bufferSurfaceFrameTX->getToken() == info.vsyncId) {
+            // BufferSurfaceFrame takes precedence over BufferlessSurfaceFrame. If the same token is
+            // being used for BufferSurfaceFrame, don't create a new one.
+            return;
+        }
+    }
+    // For Transactions without a buffer, we create only one SurfaceFrame per vsyncId. If multiple
+    // transactions use the same vsyncId, we just treat them as one SurfaceFrame (unless they are
+    // targeting different vsyncs).
+    auto it = mCurrentState.bufferlessSurfaceFramesTX.find(info.vsyncId);
+    if (it == mCurrentState.bufferlessSurfaceFramesTX.end()) {
+        auto surfaceFrame = createSurfaceFrameForTransaction(info, postTime);
+        mCurrentState.bufferlessSurfaceFramesTX[info.vsyncId] = surfaceFrame;
+    } else {
+        if (it->second->getPresentState() == PresentState::Presented) {
+            // If the SurfaceFrame was already presented, its safe to overwrite it since it must
+            // have been from previous vsync.
+            it->second = createSurfaceFrameForTransaction(info, postTime);
+        }
+    }
+}
+
+void Layer::addSurfaceFrameDroppedForBuffer(
+        std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame) {
+    surfaceFrame->setPresentState(PresentState::Dropped);
+    mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame);
+}
+
+void Layer::addSurfaceFramePresentedForBuffer(
+        std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame, nsecs_t acquireFenceTime,
+        nsecs_t currentLatchTime) {
+    surfaceFrame->setAcquireFenceTime(acquireFenceTime);
+    surfaceFrame->setPresentState(PresentState::Presented, mLastLatchTime);
+    mFlinger->mFrameTimeline->addSurfaceFrame(surfaceFrame);
+    mLastLatchTime = currentLatchTime;
+}
+
+std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForTransaction(
+        const FrameTimelineInfo& info, nsecs_t postTime) {
+    auto surfaceFrame =
+            mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, mName,
+                                                                 mTransactionName);
+    // For Transactions, the post time is considered to be both queue and acquire fence time.
+    surfaceFrame->setActualQueueTime(postTime);
+    surfaceFrame->setAcquireFenceTime(postTime);
+    onSurfaceFrameCreated(surfaceFrame);
+    return surfaceFrame;
+}
+
+std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForBuffer(
+        const FrameTimelineInfo& info, nsecs_t queueTime, std::string debugName) {
+    auto surfaceFrame =
+            mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid, mName,
+                                                                 debugName);
+    // For buffers, acquire fence time will set during latch.
+    surfaceFrame->setActualQueueTime(queueTime);
+    // TODO(b/178542907): Implement onSurfaceFrameCreated for BQLayer as well.
+    onSurfaceFrameCreated(surfaceFrame);
+    return surfaceFrame;
 }
 
 Layer::FrameRate Layer::getFrameRateForLayerTree() const {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 4b40c8e..273601f 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -32,6 +32,7 @@
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
 #include <ui/Region.h>
+#include <ui/StretchEffect.h>
 #include <ui/Transform.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
@@ -54,7 +55,7 @@
 #include "Scheduler/Seamlessness.h"
 #include "SurfaceFlinger.h"
 #include "SurfaceTracing.h"
-#include "TransactionCompletedThread.h"
+#include "TransactionCallbackInvoker.h"
 
 using namespace android::surfaceflinger;
 
@@ -309,6 +310,23 @@
 
         // When the transaction was posted
         nsecs_t postTime;
+
+        // SurfaceFrame that tracks the timeline of Transactions that contain a Buffer. Only one
+        // such SurfaceFrame exists because only one buffer can be presented on the layer per vsync.
+        // If multiple buffers are queued, the prior ones will be dropped, along with the
+        // SurfaceFrame that's tracking them.
+        std::shared_ptr<frametimeline::SurfaceFrame> bufferSurfaceFrameTX;
+        // A map of token(frametimelineVsyncId) to the SurfaceFrame that's tracking a transaction
+        // that contains the token. Only one SurfaceFrame exisits for transactions that share the
+        // same token, unless they are presented in different vsyncs.
+        std::unordered_map<int64_t, std::shared_ptr<frametimeline::SurfaceFrame>>
+                bufferlessSurfaceFramesTX;
+        // An arbitrary threshold for the number of BufferlessSurfaceFrames in the state. Used to
+        // trigger a warning if the number of SurfaceFrames crosses the threshold.
+        static constexpr uint32_t kStateSurfaceFramesThreshold = 25;
+
+        // Stretch effect to apply to this layer
+        StretchEffect stretchEffect;
     };
 
     /*
@@ -447,7 +465,8 @@
     virtual bool setBuffer(const sp<GraphicBuffer>& /*buffer*/, const sp<Fence>& /*acquireFence*/,
                            nsecs_t /*postTime*/, nsecs_t /*desiredPresentTime*/,
                            bool /*isAutoTimestamp*/, const client_cache_t& /*clientCacheId*/,
-                           uint64_t /* frameNumber */, std::optional<nsecs_t> /* dequeueTime */) {
+                           uint64_t /* frameNumber */, std::optional<nsecs_t> /* dequeueTime */,
+                           const FrameTimelineInfo& /*info*/) {
         return false;
     };
     virtual bool setAcquireFence(const sp<Fence>& /*fence*/) { return false; };
@@ -611,6 +630,12 @@
 
     virtual void pushPendingState();
 
+    /*
+     * Merges the BufferlessSurfaceFrames from source with the target. If the same token exists in
+     * both source and target, target's SurfaceFrame will be retained.
+     */
+    void mergeSurfaceFrames(State& source, State& target);
+
     /**
      * Returns active buffer size in the correct orientation. Buffer size is determined by undoing
      * any buffer transformations. If the layer has no buffer then return INVALID_RECT.
@@ -866,8 +891,20 @@
     bool setFrameRate(FrameRate);
 
     virtual void setFrameTimelineInfoForBuffer(const FrameTimelineInfo& /*info*/) {}
-    void setFrameTimelineInfoForTransaction(const FrameTimelineInfo& frameTimelineInfo,
-                                            nsecs_t postTime);
+    void setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& info, nsecs_t postTime);
+    void setFrameTimelineVsyncForBufferlessTransaction(const FrameTimelineInfo& info,
+                                                       nsecs_t postTime);
+
+    void addSurfaceFrameDroppedForBuffer(
+            std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame);
+    void addSurfaceFramePresentedForBuffer(
+            std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame, nsecs_t acquireFenceTime,
+            nsecs_t currentLatchTime);
+
+    std::shared_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForTransaction(
+            const FrameTimelineInfo& info, nsecs_t postTime);
+    std::shared_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForBuffer(
+            const FrameTimelineInfo& info, nsecs_t queueTime, std::string debugName);
 
     // Creates a new handle each time, so we only expect
     // this to be called once.
@@ -904,7 +941,8 @@
     bool mPendingHWCDestroy{false};
 
     bool backpressureEnabled() { return mDrawingState.flags & layer_state_t::eEnableBackpressure; }
-    bool hasPendingBuffer() { return mCurrentState.buffer != mDrawingState.buffer; };
+
+    bool setStretchEffect(const StretchEffect& effect);
 
 protected:
     class SyncPoint {
@@ -972,6 +1010,7 @@
     friend class TestableSurfaceFlinger;
     friend class RefreshRateSelectionTest;
     friend class SetFrameRateTest;
+    friend class TransactionSurfaceFrameTest;
 
     virtual void setInitialValuesForClone(const sp<Layer>& clonedFrom);
     virtual std::optional<compositionengine::LayerFE::LayerSettings> prepareClientComposition(
@@ -980,7 +1019,7 @@
             const LayerFE::LayerSettings&, const Rect& layerStackRect,
             ui::Dataspace outputDataspace);
     virtual void preparePerFrameCompositionState();
-    virtual void commitTransaction(const State& stateToCommit);
+    virtual void commitTransaction(State& stateToCommit);
     virtual bool applyPendingStates(State* stateToCommit);
     virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit);
     virtual void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&) {}
@@ -1116,6 +1155,10 @@
     // If created from a system process, the value can be passed in.
     pid_t mOwnerPid;
 
+    // Keeps track of the time SF latched the last buffer from this layer.
+    // Used in buffer stuffing analysis in FrameTimeline.
+    nsecs_t mLastLatchTime = 0;
+
 private:
     virtual void setTransformHint(ui::Transform::RotationFlags) {}
 
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index f273725..43a6e55 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -1,8 +1,6 @@
 adyabr@google.com
-akrulec@google.com
 alecmouri@google.com
 chaviw@google.com
 lpy@google.com
 racarr@google.com
-stoza@google.com
 vishnun@google.com
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 9230e72..49ffc81 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -238,7 +238,7 @@
     auto buffer = getOrCreateBuffers(*mCurrentFps)[mFrame];
     mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
                       mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
-                      std::nullopt /* dequeueTime */);
+                      std::nullopt /* dequeueTime */, FrameTimelineInfo{});
 
     mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
 }
@@ -251,7 +251,7 @@
     auto buffer = buffers[mFrame];
     mLayer->setBuffer(buffer, Fence::NO_FENCE, 0, 0, true, {},
                       mLayer->getHeadFrameNumber(-1 /* expectedPresentTime */),
-                      std::nullopt /* dequeueTime */);
+                      std::nullopt /* dequeueTime */, FrameTimelineInfo{});
 
     mFlinger.mTransactionFlags.fetch_or(eTransactionMask);
 }
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index f90c130..ba43e70 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -90,9 +90,9 @@
             return StringPrintf("VSync{displayId=%s, count=%u, expectedVSyncTimestamp=%" PRId64 "}",
                                 to_string(event.header.displayId).c_str(), event.vsync.count,
                                 event.vsync.expectedVSyncTimestamp);
-        case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED:
-            return StringPrintf("ConfigChanged{displayId=%s, configId=%u}",
-                                to_string(event.header.displayId).c_str(), event.config.configId);
+        case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE:
+            return StringPrintf("ModeChanged{displayId=%s, modeId=%u}",
+                                to_string(event.header.displayId).c_str(), event.modeChange.modeId);
         default:
             return "Event{}";
     }
@@ -118,12 +118,12 @@
     return event;
 }
 
-DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId, DisplayModeId configId,
-                                              nsecs_t vsyncPeriod) {
+DisplayEventReceiver::Event makeModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
+                                            nsecs_t vsyncPeriod) {
     DisplayEventReceiver::Event event;
-    event.header = {DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, displayId, systemTime()};
-    event.config.configId = configId.value();
-    event.config.vsyncPeriod = vsyncPeriod;
+    event.header = {DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, displayId, systemTime()};
+    event.modeChange.modeId = modeId.value();
+    event.modeChange.vsyncPeriod = vsyncPeriod;
     return event;
 }
 
@@ -303,10 +303,6 @@
     std::lock_guard<std::mutex> lock(mMutex);
 
     const auto request = rate == 0 ? VSyncRequest::None : static_cast<VSyncRequest>(rate);
-    if (request != VSyncRequest::None && connection->resyncCallback) {
-        connection->resyncCallback();
-    }
-
     if (connection->vsyncRequest != request) {
         connection->vsyncRequest = request;
         mCondition.notify_all();
@@ -373,11 +369,11 @@
     mCondition.notify_all();
 }
 
-void EventThread::onConfigChanged(PhysicalDisplayId displayId, DisplayModeId configId,
-                                  nsecs_t vsyncPeriod) {
+void EventThread::onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
+                                nsecs_t vsyncPeriod) {
     std::lock_guard<std::mutex> lock(mMutex);
 
-    mPendingEvents.push_back(makeConfigChanged(displayId, configId, vsyncPeriod));
+    mPendingEvents.push_back(makeModeChanged(displayId, modeId, vsyncPeriod));
     mCondition.notify_all();
 }
 
@@ -518,9 +514,9 @@
         case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
             return true;
 
-        case DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED: {
+        case DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE: {
             return connection->mEventRegistration.test(
-                    ISurfaceComposer::EventRegistration::configChanged);
+                    ISurfaceComposer::EventRegistration::modeChanged);
         }
 
         case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 15efe21..3540604 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -123,9 +123,9 @@
 
     virtual void onHotplugReceived(PhysicalDisplayId displayId, bool connected) = 0;
 
-    // called when SF changes the active config and apps needs to be notified about the change
-    virtual void onConfigChanged(PhysicalDisplayId displayId, DisplayModeId configId,
-                                 nsecs_t vsyncPeriod) = 0;
+    // called when SF changes the active mode and apps needs to be notified about the change
+    virtual void onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
+                               nsecs_t vsyncPeriod) = 0;
 
     // called when SF updates the Frame Rate Override list
     virtual void onFrameRateOverridesChanged(PhysicalDisplayId displayId,
@@ -173,8 +173,8 @@
 
     void onHotplugReceived(PhysicalDisplayId displayId, bool connected) override;
 
-    void onConfigChanged(PhysicalDisplayId displayId, DisplayModeId configId,
-                         nsecs_t vsyncPeriod) override;
+    void onModeChanged(PhysicalDisplayId displayId, DisplayModeId modeId,
+                       nsecs_t vsyncPeriod) override;
 
     void onFrameRateOverridesChanged(PhysicalDisplayId displayId,
                                      std::vector<FrameRateOverride> overrides) override;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 7ef531d..ea92ad8 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -102,7 +102,7 @@
     LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);
 
     const auto& info = it->second;
-    info->setLastPresentTime(presentTime, now, updateType, mConfigChangePending);
+    info->setLastPresentTime(presentTime, now, updateType, mModeChangePending);
 
     // Activate layer if inactive.
     if (const auto end = activeLayers().end(); it >= end) {
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index bae9b5a..05ecc70 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -51,8 +51,8 @@
     // Sets the display size. Client is responsible for synchronization.
     void setDisplayArea(uint32_t displayArea) { mDisplayArea = displayArea; }
 
-    // Sets whether a config change is pending to be applied
-    void setConfigChangePending(bool pending) { mConfigChangePending = pending; }
+    // Sets whether a mode change is pending to be applied
+    void setModeChangePending(bool pending) { mModeChangePending = pending; }
 
     // Represents which layer activity is recorded
     enum class LayerUpdateType {
@@ -109,8 +109,8 @@
     // Whether to use priority sent from WindowManager to determine the relevancy of the layer.
     const bool mUseFrameRatePriority;
 
-    // Whether a config change is in progress or not
-    std::atomic<bool> mConfigChangePending = false;
+    // Whether a mode change is in progress or not
+    std::atomic<bool> mModeChangePending = false;
 };
 
 } // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp
index 4324855..4b4cdae 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.cpp
+++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp
@@ -44,7 +44,7 @@
         mRefreshRateHistory(name) {}
 
 void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType,
-                                   bool pendingConfigChange) {
+                                   bool pendingModeChange) {
     lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0));
 
     mLastUpdatedTime = std::max(lastPresentTime, now);
@@ -56,7 +56,7 @@
         case LayerUpdateType::Buffer:
             FrameTimeData frameTime = {.presentTime = lastPresentTime,
                                        .queueTime = mLastUpdatedTime,
-                                       .pendingConfigChange = pendingConfigChange};
+                                       .pendingModeChange = pendingModeChange};
             mFrameTimes.push_back(frameTime);
             if (mFrameTimes.size() > HISTORY_SIZE) {
                 mFrameTimes.pop_front();
@@ -124,11 +124,11 @@
 }
 
 std::optional<nsecs_t> LayerInfo::calculateAverageFrameTime() const {
-    // Ignore frames captured during a config change
-    const bool isDuringConfigChange =
+    // Ignore frames captured during a mode change
+    const bool isDuringModeChange =
             std::any_of(mFrameTimes.begin(), mFrameTimes.end(),
-                        [](auto frame) { return frame.pendingConfigChange; });
-    if (isDuringConfigChange) {
+                        [](const auto& frame) { return frame.pendingModeChange; });
+    if (isDuringModeChange) {
         return std::nullopt;
     }
 
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h
index e32ba09..40c0214 100644
--- a/services/surfaceflinger/Scheduler/LayerInfo.h
+++ b/services/surfaceflinger/Scheduler/LayerInfo.h
@@ -80,7 +80,7 @@
     // the layer was last updated. If the present time is farther in the future than the
     // updated time, the updated time is the present time.
     void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType,
-                            bool pendingConfigChange);
+                            bool pendingModeChange);
 
     // Sets an explicit layer vote. This usually comes directly from the application via
     // ANativeWindow_setFrameRate API
@@ -124,7 +124,7 @@
     struct FrameTimeData {
         nsecs_t presentTime; // desiredPresentTime, if provided
         nsecs_t queueTime;  // buffer queue time
-        bool pendingConfigChange;
+        bool pendingModeChange;
     };
 
     // Holds information about the calculated and reported refresh rate
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index 81ffe0f..e7a44a7 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -40,13 +40,13 @@
                               to_string(layer.desiredRefreshRate).c_str());
 }
 
-std::vector<Fps> constructKnownFrameRates(const DisplayModes& configs) {
+std::vector<Fps> constructKnownFrameRates(const DisplayModes& modes) {
     std::vector<Fps> knownFrameRates = {Fps(24.0f), Fps(30.0f), Fps(45.0f), Fps(60.0f), Fps(72.0f)};
-    knownFrameRates.reserve(knownFrameRates.size() + configs.size());
+    knownFrameRates.reserve(knownFrameRates.size() + modes.size());
 
     // Add all supported refresh rates to the set
-    for (const auto& config : configs) {
-        const auto refreshRate = Fps::fromPeriodNsecs(config->getVsyncPeriod());
+    for (const auto& mode : modes) {
+        const auto refreshRate = Fps::fromPeriodNsecs(mode->getVsyncPeriod());
         knownFrameRates.emplace_back(refreshRate);
     }
 
@@ -65,8 +65,8 @@
 
 std::string RefreshRate::toString() const {
     return base::StringPrintf("{id=%zu, hwcId=%d, fps=%.2f, width=%d, height=%d group=%d}",
-                              getConfigId().value(), hwcConfig->getHwcId(), getFps().getValue(),
-                              hwcConfig->getWidth(), hwcConfig->getHeight(), getConfigGroup());
+                              getModeId().value(), mode->getHwcId(), getFps().getValue(),
+                              mode->getWidth(), mode->getHeight(), getModeGroup());
 }
 
 std::string RefreshRateConfigs::layerVoteTypeString(LayerVoteType vote) {
@@ -89,9 +89,9 @@
 }
 
 std::string RefreshRateConfigs::Policy::toString() const {
-    return base::StringPrintf("default config ID: %zu, allowGroupSwitching = %d"
+    return base::StringPrintf("default mode ID: %zu, allowGroupSwitching = %d"
                               ", primary range: %s, app request range: %s",
-                              defaultConfig.value(), allowGroupSwitching,
+                              defaultMode.value(), allowGroupSwitching,
                               primaryRange.toString().c_str(), appRequestRange.toString().c_str());
 }
 
@@ -291,7 +291,7 @@
         scores.emplace_back(RefreshRateScore{refreshRate, 0.0f});
     }
 
-    const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig);
+    const auto& defaultMode = mRefreshRates.at(policy->defaultMode);
 
     for (const auto& layer : layers) {
         ALOGV("Calculating score for %s (%s, weight %.2f)", layer.name.c_str(),
@@ -303,11 +303,11 @@
         auto weight = layer.weight;
 
         for (auto i = 0u; i < scores.size(); i++) {
-            const bool isSeamlessSwitch = scores[i].refreshRate->getConfigGroup() ==
-                    mCurrentRefreshRate->getConfigGroup();
+            const bool isSeamlessSwitch =
+                    scores[i].refreshRate->getModeGroup() == mCurrentRefreshRate->getModeGroup();
 
             if (layer.seamlessness == Seamlessness::OnlySeamless && !isSeamlessSwitch) {
-                ALOGV("%s ignores %s to avoid non-seamless switch. Current config = %s",
+                ALOGV("%s ignores %s to avoid non-seamless switch. Current mode = %s",
                       formatLayerInfo(layer, weight).c_str(),
                       scores[i].refreshRate->toString().c_str(),
                       mCurrentRefreshRate->toString().c_str());
@@ -317,26 +317,25 @@
             if (layer.seamlessness == Seamlessness::SeamedAndSeamless && !isSeamlessSwitch &&
                 !layer.focused) {
                 ALOGV("%s ignores %s because it's not focused and the switch is going to be seamed."
-                      " Current config = %s",
+                      " Current mode = %s",
                       formatLayerInfo(layer, weight).c_str(),
                       scores[i].refreshRate->toString().c_str(),
                       mCurrentRefreshRate->toString().c_str());
                 continue;
             }
 
-            // Layers with default seamlessness vote for the current config group if
+            // Layers with default seamlessness vote for the current mode group if
             // there are layers with seamlessness=SeamedAndSeamless and for the default
-            // config group otherwise. In second case, if the current config group is different
+            // mode group otherwise. In second case, if the current mode group is different
             // from the default, this means a layer with seamlessness=SeamedAndSeamless has just
             // disappeared.
             const bool isInPolicyForDefault = seamedLayers > 0
-                    ? scores[i].refreshRate->getConfigGroup() ==
-                            mCurrentRefreshRate->getConfigGroup()
-                    : scores[i].refreshRate->getConfigGroup() == defaultConfig->getConfigGroup();
+                    ? scores[i].refreshRate->getModeGroup() == mCurrentRefreshRate->getModeGroup()
+                    : scores[i].refreshRate->getModeGroup() == defaultMode->getModeGroup();
 
             if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault &&
                 !layer.focused) {
-                ALOGV("%s ignores %s. Current config = %s", formatLayerInfo(layer, weight).c_str(),
+                ALOGV("%s ignores %s. Current mode = %s", formatLayerInfo(layer, weight).c_str(),
                       scores[i].refreshRate->toString().c_str(),
                       mCurrentRefreshRate->toString().c_str());
                 continue;
@@ -548,12 +547,12 @@
 
 const RefreshRate& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const {
     for (auto refreshRate : mPrimaryRefreshRates) {
-        if (mCurrentRefreshRate->getConfigGroup() == refreshRate->getConfigGroup()) {
+        if (mCurrentRefreshRate->getModeGroup() == refreshRate->getModeGroup()) {
             return *refreshRate;
         }
     }
-    ALOGE("Can't find min refresh rate by policy with the same config group"
-          " as the current config %s",
+    ALOGE("Can't find min refresh rate by policy with the same mode group"
+          " as the current mode %s",
           mCurrentRefreshRate->toString().c_str());
     // Defaulting to the lowest refresh rate
     return *mPrimaryRefreshRates.front();
@@ -567,12 +566,12 @@
 const RefreshRate& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const {
     for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); it++) {
         const auto& refreshRate = (**it);
-        if (mCurrentRefreshRate->getConfigGroup() == refreshRate.getConfigGroup()) {
+        if (mCurrentRefreshRate->getModeGroup() == refreshRate.getModeGroup()) {
             return refreshRate;
         }
     }
-    ALOGE("Can't find max refresh rate by policy with the same config group"
-          " as the current config %s",
+    ALOGE("Can't find max refresh rate by policy with the same mode group"
+          " as the current mode %s",
           mCurrentRefreshRate->toString().c_str());
     // Defaulting to the highest refresh rate
     return *mPrimaryRefreshRates.back();
@@ -593,50 +592,50 @@
                   mCurrentRefreshRate) != mAppRequestRefreshRates.end()) {
         return *mCurrentRefreshRate;
     }
-    return *mRefreshRates.at(getCurrentPolicyLocked()->defaultConfig);
+    return *mRefreshRates.at(getCurrentPolicyLocked()->defaultMode);
 }
 
-void RefreshRateConfigs::setCurrentConfigId(DisplayModeId configId) {
+void RefreshRateConfigs::setCurrentModeId(DisplayModeId modeId) {
     std::lock_guard lock(mLock);
-    mCurrentRefreshRate = mRefreshRates.at(configId).get();
+    mCurrentRefreshRate = mRefreshRates.at(modeId).get();
 }
 
-RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& configs, DisplayModeId currentConfigId,
+RefreshRateConfigs::RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId,
                                        bool enableFrameRateOverride)
-      : mKnownFrameRates(constructKnownFrameRates(configs)),
+      : mKnownFrameRates(constructKnownFrameRates(modes)),
         mEnableFrameRateOverride(enableFrameRateOverride) {
-    updateDisplayConfigs(configs, currentConfigId);
+    updateDisplayModes(modes, currentModeId);
 }
 
-void RefreshRateConfigs::updateDisplayConfigs(const DisplayModes& configs,
-                                              DisplayModeId currentConfigId) {
+void RefreshRateConfigs::updateDisplayModes(const DisplayModes& modes,
+                                            DisplayModeId currentModeId) {
     std::lock_guard lock(mLock);
-    LOG_ALWAYS_FATAL_IF(configs.empty());
-    LOG_ALWAYS_FATAL_IF(currentConfigId.value() >= configs.size());
+    LOG_ALWAYS_FATAL_IF(modes.empty());
+    LOG_ALWAYS_FATAL_IF(currentModeId.value() >= modes.size());
 
     mRefreshRates.clear();
-    for (const auto& config : configs) {
-        const auto configId = config->getId();
-        const auto fps = Fps::fromPeriodNsecs(config->getVsyncPeriod());
-        mRefreshRates.emplace(configId,
-                              std::make_unique<RefreshRate>(configId, config, fps,
+    for (const auto& mode : modes) {
+        const auto modeId = mode->getId();
+        const auto fps = Fps::fromPeriodNsecs(mode->getVsyncPeriod());
+        mRefreshRates.emplace(modeId,
+                              std::make_unique<RefreshRate>(modeId, mode, fps,
                                                             RefreshRate::ConstructorTag(0)));
-        if (configId == currentConfigId) {
-            mCurrentRefreshRate = mRefreshRates.at(configId).get();
+        if (modeId == currentModeId) {
+            mCurrentRefreshRate = mRefreshRates.at(modeId).get();
         }
     }
 
-    std::vector<const RefreshRate*> sortedConfigs;
-    getSortedRefreshRateListLocked([](const RefreshRate&) { return true; }, &sortedConfigs);
-    mDisplayManagerPolicy.defaultConfig = currentConfigId;
-    mMinSupportedRefreshRate = sortedConfigs.front();
-    mMaxSupportedRefreshRate = sortedConfigs.back();
+    std::vector<const RefreshRate*> sortedModes;
+    getSortedRefreshRateListLocked([](const RefreshRate&) { return true; }, &sortedModes);
+    mDisplayManagerPolicy.defaultMode = currentModeId;
+    mMinSupportedRefreshRate = sortedModes.front();
+    mMaxSupportedRefreshRate = sortedModes.back();
 
     mSupportsFrameRateOverride = false;
     if (mEnableFrameRateOverride) {
-        for (const auto& config1 : sortedConfigs) {
-            for (const auto& config2 : sortedConfigs) {
-                if (getFrameRateDivider(config1->getFps(), config2->getFps()) >= 2) {
+        for (const auto& mode1 : sortedModes) {
+            for (const auto& mode2 : sortedModes) {
+                if (getFrameRateDivider(mode1->getFps(), mode2->getFps()) >= 2) {
                     mSupportsFrameRateOverride = true;
                     break;
                 }
@@ -648,15 +647,15 @@
 }
 
 bool RefreshRateConfigs::isPolicyValidLocked(const Policy& policy) const {
-    // defaultConfig must be a valid config, and within the given refresh rate range.
-    auto iter = mRefreshRates.find(policy.defaultConfig);
+    // defaultMode must be a valid mode, and within the given refresh rate range.
+    auto iter = mRefreshRates.find(policy.defaultMode);
     if (iter == mRefreshRates.end()) {
-        ALOGE("Default config is not found.");
+        ALOGE("Default mode is not found.");
         return false;
     }
     const RefreshRate& refreshRate = *iter->second;
     if (!refreshRate.inPolicy(policy.primaryRange.min, policy.primaryRange.max)) {
-        ALOGE("Default config is not in the primary range.");
+        ALOGE("Default mode is not in the primary range.");
         return false;
     }
     return policy.appRequestRange.min.lessThanOrEqualWithMargin(policy.primaryRange.min) &&
@@ -706,10 +705,10 @@
     return mDisplayManagerPolicy;
 }
 
-bool RefreshRateConfigs::isConfigAllowed(DisplayModeId config) const {
+bool RefreshRateConfigs::isModeAllowed(DisplayModeId modeId) const {
     std::lock_guard lock(mLock);
     for (const RefreshRate* refreshRate : mAppRequestRefreshRates) {
-        if (refreshRate->configId == config) {
+        if (refreshRate->modeId == modeId) {
             return true;
         }
     }
@@ -723,60 +722,59 @@
     outRefreshRates->reserve(mRefreshRates.size());
     for (const auto& [type, refreshRate] : mRefreshRates) {
         if (shouldAddRefreshRate(*refreshRate)) {
-            ALOGV("getSortedRefreshRateListLocked: config %zu added to list policy",
-                  refreshRate->configId.value());
+            ALOGV("getSortedRefreshRateListLocked: mode %zu added to list policy",
+                  refreshRate->modeId.value());
             outRefreshRates->push_back(refreshRate.get());
         }
     }
 
     std::sort(outRefreshRates->begin(), outRefreshRates->end(),
               [](const auto refreshRate1, const auto refreshRate2) {
-                  if (refreshRate1->hwcConfig->getVsyncPeriod() !=
-                      refreshRate2->hwcConfig->getVsyncPeriod()) {
-                      return refreshRate1->hwcConfig->getVsyncPeriod() >
-                              refreshRate2->hwcConfig->getVsyncPeriod();
+                  if (refreshRate1->mode->getVsyncPeriod() !=
+                      refreshRate2->mode->getVsyncPeriod()) {
+                      return refreshRate1->mode->getVsyncPeriod() >
+                              refreshRate2->mode->getVsyncPeriod();
                   } else {
-                      return refreshRate1->hwcConfig->getConfigGroup() >
-                              refreshRate2->hwcConfig->getConfigGroup();
+                      return refreshRate1->mode->getGroup() > refreshRate2->mode->getGroup();
                   }
               });
 }
 
 void RefreshRateConfigs::constructAvailableRefreshRates() {
-    // Filter configs based on current policy and sort based on vsync period
+    // Filter modes based on current policy and sort based on vsync period
     const Policy* policy = getCurrentPolicyLocked();
-    const auto& defaultConfig = mRefreshRates.at(policy->defaultConfig)->hwcConfig;
+    const auto& defaultMode = mRefreshRates.at(policy->defaultMode)->mode;
     ALOGV("constructAvailableRefreshRates: %s ", policy->toString().c_str());
 
-    auto filterRefreshRates = [&](Fps min, Fps max, const char* listName,
-                                  std::vector<const RefreshRate*>*
-                                          outRefreshRates) REQUIRES(mLock) {
-        getSortedRefreshRateListLocked(
-                [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
-                    const auto& hwcConfig = refreshRate.hwcConfig;
+    auto filterRefreshRates =
+            [&](Fps min, Fps max, const char* listName,
+                std::vector<const RefreshRate*>* outRefreshRates) REQUIRES(mLock) {
+                getSortedRefreshRateListLocked(
+                        [&](const RefreshRate& refreshRate) REQUIRES(mLock) {
+                            const auto& mode = refreshRate.mode;
 
-                    return hwcConfig->getHeight() == defaultConfig->getHeight() &&
-                            hwcConfig->getWidth() == defaultConfig->getWidth() &&
-                            hwcConfig->getDpiX() == defaultConfig->getDpiX() &&
-                            hwcConfig->getDpiY() == defaultConfig->getDpiY() &&
-                            (policy->allowGroupSwitching ||
-                             hwcConfig->getConfigGroup() == defaultConfig->getConfigGroup()) &&
-                            refreshRate.inPolicy(min, max);
-                },
-                outRefreshRates);
+                            return mode->getHeight() == defaultMode->getHeight() &&
+                                    mode->getWidth() == defaultMode->getWidth() &&
+                                    mode->getDpiX() == defaultMode->getDpiX() &&
+                                    mode->getDpiY() == defaultMode->getDpiY() &&
+                                    (policy->allowGroupSwitching ||
+                                     mode->getGroup() == defaultMode->getGroup()) &&
+                                    refreshRate.inPolicy(min, max);
+                        },
+                        outRefreshRates);
 
-        LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(),
-                            "No matching configs for %s range: min=%s max=%s", listName,
-                            to_string(min).c_str(), to_string(max).c_str());
-        auto stringifyRefreshRates = [&]() -> std::string {
-            std::string str;
-            for (auto refreshRate : *outRefreshRates) {
-                base::StringAppendF(&str, "%s ", refreshRate->getName().c_str());
-            }
-            return str;
-        };
-        ALOGV("%s refresh rates: %s", listName, stringifyRefreshRates().c_str());
-    };
+                LOG_ALWAYS_FATAL_IF(outRefreshRates->empty(),
+                                    "No matching modes for %s range: min=%s max=%s", listName,
+                                    to_string(min).c_str(), to_string(max).c_str());
+                auto stringifyRefreshRates = [&]() -> std::string {
+                    std::string str;
+                    for (auto refreshRate : *outRefreshRates) {
+                        base::StringAppendF(&str, "%s ", refreshRate->getName().c_str());
+                    }
+                    return str;
+                };
+                ALOGV("%s refresh rates: %s", listName, stringifyRefreshRates().c_str());
+            };
 
     filterRefreshRates(policy->primaryRange.min, policy->primaryRange.max, "primary",
                        &mPrimaryRefreshRates);
@@ -845,20 +843,20 @@
 
 void RefreshRateConfigs::dump(std::string& result) const {
     std::lock_guard lock(mLock);
-    base::StringAppendF(&result, "DesiredDisplayConfigSpecs (DisplayManager): %s\n\n",
+    base::StringAppendF(&result, "DesiredDisplayModeSpecs (DisplayManager): %s\n\n",
                         mDisplayManagerPolicy.toString().c_str());
     scheduler::RefreshRateConfigs::Policy currentPolicy = *getCurrentPolicyLocked();
     if (mOverridePolicy && currentPolicy != mDisplayManagerPolicy) {
-        base::StringAppendF(&result, "DesiredDisplayConfigSpecs (Override): %s\n\n",
+        base::StringAppendF(&result, "DesiredDisplayModeSpecs (Override): %s\n\n",
                             currentPolicy.toString().c_str());
     }
 
-    auto config = mCurrentRefreshRate->hwcConfig;
-    base::StringAppendF(&result, "Current config: %s\n", mCurrentRefreshRate->toString().c_str());
+    auto mode = mCurrentRefreshRate->mode;
+    base::StringAppendF(&result, "Current mode: %s\n", mCurrentRefreshRate->toString().c_str());
 
     result.append("Refresh rates:\n");
     for (const auto& [id, refreshRate] : mRefreshRates) {
-        config = refreshRate->hwcConfig;
+        mode = refreshRate->mode;
         base::StringAppendF(&result, "\t%s\n", refreshRate->toString().c_str());
     }
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 0c7dc05..2bc22b4 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -64,12 +64,12 @@
         };
 
     public:
-        RefreshRate(DisplayModeId configId, DisplayModePtr config, Fps fps, ConstructorTag)
-              : configId(configId), hwcConfig(config), fps(std::move(fps)) {}
+        RefreshRate(DisplayModeId modeId, DisplayModePtr mode, Fps fps, ConstructorTag)
+              : modeId(modeId), mode(mode), fps(std::move(fps)) {}
 
-        DisplayModeId getConfigId() const { return configId; }
-        nsecs_t getVsyncPeriod() const { return hwcConfig->getVsyncPeriod(); }
-        int32_t getConfigGroup() const { return hwcConfig->getConfigGroup(); }
+        DisplayModeId getModeId() const { return modeId; }
+        nsecs_t getVsyncPeriod() const { return mode->getVsyncPeriod(); }
+        int32_t getModeGroup() const { return mode->getGroup(); }
         std::string getName() const { return to_string(fps); }
         Fps getFps() const { return fps; }
 
@@ -81,7 +81,7 @@
         }
 
         bool operator!=(const RefreshRate& other) const {
-            return configId != other.configId || hwcConfig != other.hwcConfig;
+            return modeId != other.modeId || mode != other.mode;
         }
 
         bool operator<(const RefreshRate& other) const {
@@ -99,11 +99,8 @@
         friend RefreshRateConfigs;
         friend class RefreshRateConfigsTest;
 
-        // This config ID corresponds to the position of the config in the vector that is stored
-        // on the device.
-        const DisplayModeId configId;
-        // The config itself
-        DisplayModePtr hwcConfig;
+        const DisplayModeId modeId;
+        DisplayModePtr mode;
         // Refresh rate in frames per second
         const Fps fps{0.0f};
     };
@@ -131,16 +128,16 @@
         static constexpr int kAllowGroupSwitchingDefault = false;
 
     public:
-        // The default config, used to ensure we only initiate display config switches within the
-        // same config group as defaultConfigId's group.
-        DisplayModeId defaultConfig;
-        // Whether or not we switch config groups to get the best frame rate.
+        // The default mode, used to ensure we only initiate display mode switches within the
+        // same mode group as defaultMode's group.
+        DisplayModeId defaultMode;
+        // Whether or not we switch mode 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
+        // display modes we'll consider when switching refresh rates. Unless we get an explicit
         // signal from an app, we should stay within this range.
         FpsRange primaryRange;
-        // The app request refresh rate range allows us to consider more display configs when
+        // The app request refresh rate range allows us to consider more display modes when
         // switching refresh rates. Although we should generally stay within the primary range,
         // specific considerations, such as layer frame rate settings specified via the
         // setFrameRate() api, may cause us to go outside the primary range. We never go outside the
@@ -150,25 +147,25 @@
 
         Policy() = default;
 
-        Policy(DisplayModeId defaultConfig, const FpsRange& range)
-              : Policy(defaultConfig, kAllowGroupSwitchingDefault, range, range) {}
+        Policy(DisplayModeId defaultMode, const FpsRange& range)
+              : Policy(defaultMode, kAllowGroupSwitchingDefault, range, range) {}
 
-        Policy(DisplayModeId defaultConfig, bool allowGroupSwitching, const FpsRange& range)
-              : Policy(defaultConfig, allowGroupSwitching, range, range) {}
+        Policy(DisplayModeId defaultMode, bool allowGroupSwitching, const FpsRange& range)
+              : Policy(defaultMode, allowGroupSwitching, range, range) {}
 
-        Policy(DisplayModeId defaultConfig, const FpsRange& primaryRange,
+        Policy(DisplayModeId defaultMode, const FpsRange& primaryRange,
                const FpsRange& appRequestRange)
-              : Policy(defaultConfig, kAllowGroupSwitchingDefault, primaryRange, appRequestRange) {}
+              : Policy(defaultMode, kAllowGroupSwitchingDefault, primaryRange, appRequestRange) {}
 
-        Policy(DisplayModeId defaultConfig, bool allowGroupSwitching, const FpsRange& primaryRange,
+        Policy(DisplayModeId defaultMode, bool allowGroupSwitching, const FpsRange& primaryRange,
                const FpsRange& appRequestRange)
-              : defaultConfig(defaultConfig),
+              : defaultMode(defaultMode),
                 allowGroupSwitching(allowGroupSwitching),
                 primaryRange(primaryRange),
                 appRequestRange(appRequestRange) {}
 
         bool operator==(const Policy& other) const {
-            return defaultConfig == other.defaultConfig && primaryRange == other.primaryRange &&
+            return defaultMode == other.defaultMode && primaryRange == other.primaryRange &&
                     appRequestRange == other.appRequestRange &&
                     allowGroupSwitching == other.allowGroupSwitching;
         }
@@ -200,8 +197,8 @@
     // Gets the display manager policy, regardless of whether an override policy is active.
     Policy getDisplayManagerPolicy() const EXCLUDES(mLock);
 
-    // Returns true if config is allowed by the current policy.
-    bool isConfigAllowed(DisplayModeId config) const EXCLUDES(mLock);
+    // Returns true if mode is allowed by the current policy.
+    bool isModeAllowed(DisplayModeId) const EXCLUDES(mLock);
 
     // Describes the different options the layer voted for refresh rate
     enum class LayerVoteType {
@@ -270,7 +267,7 @@
         return {mMinSupportedRefreshRate->getFps(), mMaxSupportedRefreshRate->getFps()};
     }
 
-    std::optional<Fps> onKernelTimerChanged(std::optional<DisplayModeId> desiredActiveConfigId,
+    std::optional<Fps> onKernelTimerChanged(std::optional<DisplayModeId> desiredActiveModeId,
                                             bool timerExpired) const EXCLUDES(mLock);
 
     // Returns the highest refresh rate according to the current policy. May change at runtime. Only
@@ -286,14 +283,14 @@
 
     // Returns the refresh rate that corresponds to a DisplayModeId. This may change at
     // runtime.
-    // TODO(b/159590486) An invalid config id may be given here if the dipslay configs have changed.
-    RefreshRate getRefreshRateFromConfigId(DisplayModeId configId) const EXCLUDES(mLock) {
+    // TODO(b/159590486) An invalid mode id may be given here if the dipslay modes have changed.
+    RefreshRate getRefreshRateFromModeId(DisplayModeId modeId) const EXCLUDES(mLock) {
         std::lock_guard lock(mLock);
-        return *mRefreshRates.at(configId);
+        return *mRefreshRates.at(modeId);
     };
 
-    // Stores the current configId the device operates at
-    void setCurrentConfigId(DisplayModeId configId) EXCLUDES(mLock);
+    // Stores the current modeId the device operates at
+    void setCurrentModeId(DisplayModeId) EXCLUDES(mLock);
 
     // Returns a string that represents the layer vote type
     static std::string layerVoteTypeString(LayerVoteType vote);
@@ -301,14 +298,13 @@
     // Returns a known frame rate that is the closest to frameRate
     Fps findClosestKnownFrameRate(Fps frameRate) const;
 
-    RefreshRateConfigs(const DisplayModes& configs, DisplayModeId currentConfigId,
+    RefreshRateConfigs(const DisplayModes& modes, DisplayModeId currentModeId,
                        bool enableFrameRateOverride = false);
 
-    void updateDisplayConfigs(const DisplayModes& configs, DisplayModeId currentConfig)
-            EXCLUDES(mLock);
+    void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock);
 
-    // Returns whether switching configs (refresh rate or resolution) is possible.
-    // TODO(b/158780872): Consider HAL support, and skip frame rate detection if the configs only
+    // Returns whether switching modes (refresh rate or resolution) is possible.
+    // TODO(b/158780872): Consider HAL support, and skip frame rate detection if the modes only
     // differ in resolution.
     bool canSwitch() const EXCLUDES(mLock) {
         std::lock_guard lock(mLock);
@@ -387,7 +383,7 @@
     float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&,
                                     bool isSeamlessSwitch) const REQUIRES(mLock);
 
-    // The list of refresh rates, indexed by display config ID. This may change after this
+    // The list of refresh rates, indexed by display modes ID. This may change after this
     // object is initialized.
     AllRefreshRatesMapType mRefreshRates GUARDED_BY(mLock);
 
@@ -399,7 +395,7 @@
     // vsyncPeriod (the first element is the lowest refresh rate).
     std::vector<const RefreshRate*> mAppRequestRefreshRates GUARDED_BY(mLock);
 
-    // The current config. This will change at runtime. This is set by SurfaceFlinger on
+    // The current display mode. This will change at runtime. This is set by SurfaceFlinger on
     // the main thread, and read by the Scheduler (and other objects) on other threads.
     const RefreshRate* mCurrentRefreshRate GUARDED_BY(mLock);
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index d861209..9813270 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -348,55 +348,53 @@
     thread->onFrameRateOverridesChanged(displayId, std::move(overrides));
 }
 
-void Scheduler::onPrimaryDisplayConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
-                                              DisplayModeId configId, nsecs_t vsyncPeriod) {
+void Scheduler::onPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
+                                            DisplayModeId modeId, nsecs_t vsyncPeriod) {
     {
         std::lock_guard<std::mutex> lock(mFeatureStateLock);
-        // Cache the last reported config for primary display.
-        mFeatures.cachedConfigChangedParams = {handle, displayId, configId, vsyncPeriod};
+        // Cache the last reported modes for primary display.
+        mFeatures.cachedModeChangedParams = {handle, displayId, modeId, vsyncPeriod};
     }
-    onNonPrimaryDisplayConfigChanged(handle, displayId, configId, vsyncPeriod);
+    onNonPrimaryDisplayModeChanged(handle, displayId, modeId, vsyncPeriod);
 }
 
-void Scheduler::dispatchCachedReportedConfig() {
+void Scheduler::dispatchCachedReportedMode() {
     // Check optional fields first.
-    if (!mFeatures.configId.has_value()) {
-        ALOGW("No config ID found, not dispatching cached config.");
+    if (!mFeatures.modeId.has_value()) {
+        ALOGW("No mode ID found, not dispatching cached mode.");
         return;
     }
-    if (!mFeatures.cachedConfigChangedParams.has_value()) {
-        ALOGW("No config changed params found, not dispatching cached config.");
+    if (!mFeatures.cachedModeChangedParams.has_value()) {
+        ALOGW("No mode changed params found, not dispatching cached mode.");
         return;
     }
 
-    const auto configId = *mFeatures.configId;
-    const auto vsyncPeriod =
-            mRefreshRateConfigs.getRefreshRateFromConfigId(configId).getVsyncPeriod();
+    const auto modeId = *mFeatures.modeId;
+    const auto vsyncPeriod = mRefreshRateConfigs.getRefreshRateFromModeId(modeId).getVsyncPeriod();
 
-    // If there is no change from cached config, there is no need to dispatch an event
-    if (configId == mFeatures.cachedConfigChangedParams->configId &&
-        vsyncPeriod == mFeatures.cachedConfigChangedParams->vsyncPeriod) {
+    // If there is no change from cached mode, there is no need to dispatch an event
+    if (modeId == mFeatures.cachedModeChangedParams->modeId &&
+        vsyncPeriod == mFeatures.cachedModeChangedParams->vsyncPeriod) {
         return;
     }
 
-    mFeatures.cachedConfigChangedParams->configId = configId;
-    mFeatures.cachedConfigChangedParams->vsyncPeriod = vsyncPeriod;
-    onNonPrimaryDisplayConfigChanged(mFeatures.cachedConfigChangedParams->handle,
-                                     mFeatures.cachedConfigChangedParams->displayId,
-                                     mFeatures.cachedConfigChangedParams->configId,
-                                     mFeatures.cachedConfigChangedParams->vsyncPeriod);
+    mFeatures.cachedModeChangedParams->modeId = modeId;
+    mFeatures.cachedModeChangedParams->vsyncPeriod = vsyncPeriod;
+    onNonPrimaryDisplayModeChanged(mFeatures.cachedModeChangedParams->handle,
+                                   mFeatures.cachedModeChangedParams->displayId,
+                                   mFeatures.cachedModeChangedParams->modeId,
+                                   mFeatures.cachedModeChangedParams->vsyncPeriod);
 }
 
-void Scheduler::onNonPrimaryDisplayConfigChanged(ConnectionHandle handle,
-                                                 PhysicalDisplayId displayId,
-                                                 DisplayModeId configId, nsecs_t vsyncPeriod) {
+void Scheduler::onNonPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
+                                               DisplayModeId modeId, nsecs_t vsyncPeriod) {
     android::EventThread* thread;
     {
         std::lock_guard<std::mutex> lock(mConnectionsLock);
         RETURN_IF_INVALID_HANDLE(handle);
         thread = mConnections[handle].thread.get();
     }
-    thread->onConfigChanged(displayId, configId, vsyncPeriod);
+    thread->onModeChanged(displayId, modeId, vsyncPeriod);
 }
 
 size_t Scheduler::getEventThreadConnectionCount(ConnectionHandle handle) {
@@ -590,9 +588,9 @@
     }
 }
 
-void Scheduler::setConfigChangePending(bool pending) {
+void Scheduler::setModeChangePending(bool pending) {
     if (mLayerHistory) {
-        mLayerHistory->setConfigChangePending(pending);
+        mLayerHistory->setModeChangePending(pending);
     }
 }
 
@@ -603,7 +601,7 @@
 
     scheduler::LayerHistory::Summary summary = mLayerHistory->summarize(systemTime());
     scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
-    DisplayModeId newConfigId;
+    DisplayModeId newModeId;
     bool frameRateChanged;
     bool frameRateOverridesChanged;
     {
@@ -613,28 +611,28 @@
         }
         mFeatures.contentRequirements = summary;
 
-        newConfigId = calculateRefreshRateConfigIndexType(&consideredSignals);
-        auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
+        newModeId = calculateRefreshRateModeId(&consideredSignals);
+        auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId);
         frameRateOverridesChanged =
                 updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps());
 
-        if (mFeatures.configId == newConfigId) {
-            // We don't need to change the config, but we might need to send an event
-            // about a config change, since it was suppressed due to a previous idleConsidered
+        if (mFeatures.modeId == newModeId) {
+            // We don't need to change the display mode, but we might need to send an event
+            // about a mode change, since it was suppressed due to a previous idleConsidered
             if (!consideredSignals.idle) {
-                dispatchCachedReportedConfig();
+                dispatchCachedReportedMode();
             }
             frameRateChanged = false;
         } else {
-            mFeatures.configId = newConfigId;
+            mFeatures.modeId = newModeId;
             frameRateChanged = true;
         }
     }
     if (frameRateChanged) {
-        auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
+        auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId);
         mSchedulerCallback.changeRefreshRate(newRefreshRate,
-                                             consideredSignals.idle ? ConfigEvent::None
-                                                                    : ConfigEvent::Changed);
+                                             consideredSignals.idle ? ModeEvent::None
+                                                                    : ModeEvent::Changed);
     }
     if (frameRateOverridesChanged) {
         mSchedulerCallback.triggerOnFrameRateOverridesChanged();
@@ -783,7 +781,7 @@
 
 template <class T>
 bool Scheduler::handleTimerStateChanged(T* currentState, T newState) {
-    DisplayModeId newConfigId;
+    DisplayModeId newModeId;
     bool refreshRateChanged = false;
     bool frameRateOverridesChanged;
     scheduler::RefreshRateConfigs::GlobalSignals consideredSignals;
@@ -793,29 +791,27 @@
             return false;
         }
         *currentState = newState;
-        newConfigId = calculateRefreshRateConfigIndexType(&consideredSignals);
-        const RefreshRate& newRefreshRate =
-                mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
+        newModeId = calculateRefreshRateModeId(&consideredSignals);
+        const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId);
         frameRateOverridesChanged =
                 updateFrameRateOverrides(consideredSignals, newRefreshRate.getFps());
-        if (mFeatures.configId == newConfigId) {
-            // We don't need to change the config, but we might need to send an event
-            // about a config change, since it was suppressed due to a previous idleConsidered
+        if (mFeatures.modeId == newModeId) {
+            // We don't need to change the display mode, but we might need to send an event
+            // about a mode change, since it was suppressed due to a previous idleConsidered
             if (!consideredSignals.idle) {
-                dispatchCachedReportedConfig();
+                dispatchCachedReportedMode();
             }
         } else {
-            mFeatures.configId = newConfigId;
+            mFeatures.modeId = newModeId;
             refreshRateChanged = true;
         }
     }
     if (refreshRateChanged) {
-        const RefreshRate& newRefreshRate =
-                mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
+        const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromModeId(newModeId);
 
         mSchedulerCallback.changeRefreshRate(newRefreshRate,
-                                             consideredSignals.idle ? ConfigEvent::None
-                                                                    : ConfigEvent::Changed);
+                                             consideredSignals.idle ? ModeEvent::None
+                                                                    : ModeEvent::Changed);
     }
     if (frameRateOverridesChanged) {
         mSchedulerCallback.triggerOnFrameRateOverridesChanged();
@@ -823,7 +819,7 @@
     return consideredSignals.touch;
 }
 
-DisplayModeId Scheduler::calculateRefreshRateConfigIndexType(
+DisplayModeId Scheduler::calculateRefreshRateModeId(
         scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals) {
     ATRACE_CALL();
     if (consideredSignals) *consideredSignals = {};
@@ -833,7 +829,7 @@
     if (mDisplayPowerTimer &&
         (!mFeatures.isDisplayPowerStateNormal ||
          mFeatures.displayPowerTimer == TimerState::Reset)) {
-        return mRefreshRateConfigs.getMaxRefreshRateByPolicy().getConfigId();
+        return mRefreshRateConfigs.getMaxRefreshRateByPolicy().getModeId();
     }
 
     const bool touchActive = mTouchTimer && mFeatures.touch == TouchState::Active;
@@ -842,16 +838,16 @@
     return mRefreshRateConfigs
             .getBestRefreshRate(mFeatures.contentRequirements, {.touch = touchActive, .idle = idle},
                                 consideredSignals)
-            .getConfigId();
+            .getModeId();
 }
 
-std::optional<DisplayModeId> Scheduler::getPreferredConfigId() {
+std::optional<DisplayModeId> Scheduler::getPreferredModeId() {
     std::lock_guard<std::mutex> lock(mFeatureStateLock);
-    // Make sure that the default config ID is first updated, before returned.
-    if (mFeatures.configId.has_value()) {
-        mFeatures.configId = calculateRefreshRateConfigIndexType();
+    // Make sure that the default mode ID is first updated, before returned.
+    if (mFeatures.modeId.has_value()) {
+        mFeatures.modeId = calculateRefreshRateModeId();
     }
-    return mFeatures.configId;
+    return mFeatures.modeId;
 }
 
 void Scheduler::onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 340ca8e..5237516 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -70,7 +70,7 @@
 class Scheduler {
 public:
     using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
-    using ConfigEvent = scheduler::RefreshRateConfigEvent;
+    using ModeEvent = scheduler::RefreshRateConfigEvent;
 
     Scheduler(const scheduler::RefreshRateConfigs&, ISchedulerCallback&);
     ~Scheduler();
@@ -87,10 +87,10 @@
     sp<EventThreadConnection> getEventConnection(ConnectionHandle);
 
     void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected);
-    void onPrimaryDisplayConfigChanged(ConnectionHandle, PhysicalDisplayId, DisplayModeId configId,
-                                       nsecs_t vsyncPeriod) EXCLUDES(mFeatureStateLock);
-    void onNonPrimaryDisplayConfigChanged(ConnectionHandle, PhysicalDisplayId,
-                                          DisplayModeId configId, nsecs_t vsyncPeriod);
+    void onPrimaryDisplayModeChanged(ConnectionHandle, PhysicalDisplayId, DisplayModeId,
+                                     nsecs_t vsyncPeriod) EXCLUDES(mFeatureStateLock);
+    void onNonPrimaryDisplayModeChanged(ConnectionHandle, PhysicalDisplayId, DisplayModeId,
+                                        nsecs_t vsyncPeriod);
     void onScreenAcquired(ConnectionHandle);
     void onScreenReleased(ConnectionHandle);
 
@@ -128,7 +128,7 @@
     // Layers are registered on creation, and unregistered when the weak reference expires.
     void registerLayer(Layer*);
     void recordLayerHistory(Layer*, nsecs_t presentTime, LayerHistory::LayerUpdateType updateType);
-    void setConfigChangePending(bool pending);
+    void setModeChangePending(bool pending);
 
     // Detects content using layer history, and selects a matching refresh rate.
     void chooseRefreshRateForContent();
@@ -153,7 +153,7 @@
     void dumpVsync(std::string&) const;
 
     // Get the appropriate refresh for current conditions.
-    std::optional<DisplayModeId> getPreferredConfigId();
+    std::optional<DisplayModeId> getPreferredModeId();
 
     // Notifies the scheduler about a refresh rate timeline change.
     void onNewVsyncPeriodChangeTimeline(const hal::VsyncPeriodChangeTimeline& timeline);
@@ -227,11 +227,11 @@
     // This function checks whether individual features that are affecting the refresh rate
     // selection were initialized, prioritizes them, and calculates the DisplayModeId
     // for the suggested refresh rate.
-    DisplayModeId calculateRefreshRateConfigIndexType(
+    DisplayModeId calculateRefreshRateModeId(
             scheduler::RefreshRateConfigs::GlobalSignals* consideredSignals = nullptr)
             REQUIRES(mFeatureStateLock);
 
-    void dispatchCachedReportedConfig() REQUIRES(mFeatureStateLock);
+    void dispatchCachedReportedMode() REQUIRES(mFeatureStateLock);
     bool updateFrameRateOverrides(scheduler::RefreshRateConfigs::GlobalSignals consideredSignals,
                                   Fps displayRefreshRate) REQUIRES(mFeatureStateLock)
             EXCLUDES(mFrameRateOverridesMutex);
@@ -283,20 +283,20 @@
         TouchState touch = TouchState::Inactive;
         TimerState displayPowerTimer = TimerState::Expired;
 
-        std::optional<DisplayModeId> configId;
+        std::optional<DisplayModeId> modeId;
         LayerHistory::Summary contentRequirements;
 
         bool isDisplayPowerStateNormal = true;
 
-        // Used to cache the last parameters of onPrimaryDisplayConfigChanged
-        struct ConfigChangedParams {
+        // Used to cache the last parameters of onPrimaryDisplayModeChanged
+        struct ModeChangedParams {
             ConnectionHandle handle;
             PhysicalDisplayId displayId;
-            DisplayModeId configId;
+            DisplayModeId modeId;
             nsecs_t vsyncPeriod;
         };
 
-        std::optional<ConfigChangedParams> cachedConfigChangedParams;
+        std::optional<ModeChangedParams> cachedModeChangedParams;
     } mFeatures GUARDED_BY(mFeatureStateLock);
 
     const scheduler::RefreshRateConfigs& mRefreshRateConfigs;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index eeb3ad2..a36502c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -67,8 +67,9 @@
 #include <sys/types.h>
 #include <ui/ColorSpace.h>
 #include <ui/DebugUtils.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayId.h>
 #include <ui/DisplayInfo.h>
+#include <ui/DisplayMode.h>
 #include <ui/DisplayStatInfo.h>
 #include <ui/DisplayState.h>
 #include <ui/GraphicBufferAllocator.h>
@@ -275,7 +276,6 @@
 const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
 const String16 sRotateSurfaceFlinger("android.permission.ROTATE_SURFACE_FLINGER");
 const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
-const String16 sUseBackgroundBlur("android.permission.USE_BACKGROUND_BLUR");
 const String16 sDump("android.permission.DUMP");
 const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled";
 
@@ -333,10 +333,6 @@
             PermissionCache::checkPermission(sRotateSurfaceFlinger, pid, uid);
 }
 
-bool originalCallerCanUseBlurs(int originPid, int originUid) {
-    return PermissionCache::checkPermission(sUseBackgroundBlur, originPid, originUid);
-}
-
 SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {}
 
 SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
@@ -891,9 +887,9 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken,
-                                           Vector<DisplayConfig>* configs) {
-    if (!displayToken || !configs) {
+status_t SurfaceFlinger::getDisplayModes(const sp<IBinder>& displayToken,
+                                         Vector<ui::DisplayMode>* modes) {
+    if (!displayToken || !modes) {
         return BAD_VALUE;
     }
 
@@ -904,16 +900,16 @@
         return NAME_NOT_FOUND;
     }
 
-    configs->clear();
+    modes->clear();
 
-    for (const auto& mode : display->getSupportedModes()) {
-        DisplayConfig config;
+    for (const auto& supportedMode : display->getSupportedModes()) {
+        ui::DisplayMode mode;
 
-        auto width = mode->getWidth();
-        auto height = mode->getHeight();
+        auto width = supportedMode->getWidth();
+        auto height = supportedMode->getHeight();
 
-        auto xDpi = mode->getDpiX();
-        auto yDpi = mode->getDpiY();
+        auto xDpi = supportedMode->getDpiX();
+        auto yDpi = supportedMode->getDpiY();
 
         if (display->isPrimary() &&
             (internalDisplayOrientation == ui::ROTATION_90 ||
@@ -922,24 +918,24 @@
             std::swap(xDpi, yDpi);
         }
 
-        config.resolution = ui::Size(width, height);
+        mode.resolution = ui::Size(width, height);
 
         if (mEmulatedDisplayDensity) {
-            config.xDpi = mEmulatedDisplayDensity;
-            config.yDpi = mEmulatedDisplayDensity;
+            mode.xDpi = mEmulatedDisplayDensity;
+            mode.yDpi = mEmulatedDisplayDensity;
         } else {
-            config.xDpi = xDpi;
-            config.yDpi = yDpi;
+            mode.xDpi = xDpi;
+            mode.yDpi = yDpi;
         }
 
-        const nsecs_t period = mode->getVsyncPeriod();
-        config.refreshRate = Fps::fromPeriodNsecs(period).getValue();
+        const nsecs_t period = supportedMode->getVsyncPeriod();
+        mode.refreshRate = Fps::fromPeriodNsecs(period).getValue();
 
         const auto vsyncConfigSet =
-                mVsyncConfiguration->getConfigsForRefreshRate(Fps(config.refreshRate));
-        config.appVsyncOffset = vsyncConfigSet.late.appOffset;
-        config.sfVsyncOffset = vsyncConfigSet.late.sfOffset;
-        config.configGroup = mode->getConfigGroup();
+                mVsyncConfiguration->getConfigsForRefreshRate(Fps(mode.refreshRate));
+        mode.appVsyncOffset = vsyncConfigSet.late.appOffset;
+        mode.sfVsyncOffset = vsyncConfigSet.late.sfOffset;
+        mode.group = supportedMode->getGroup();
 
         // This is how far in advance a buffer must be queued for
         // presentation at a given time.  If you want a buffer to appear
@@ -953,9 +949,9 @@
         //
         // We add an additional 1ms to allow for processing time and
         // differences between the ideal and actual refresh rate.
-        config.presentationDeadline = period - config.sfVsyncOffset + 1000000;
+        mode.presentationDeadline = period - mode.sfVsyncOffset + 1000000;
 
-        configs->push_back(config);
+        modes->push_back(mode);
     }
 
     return NO_ERROR;
@@ -970,15 +966,15 @@
     return NO_ERROR;
 }
 
-int SurfaceFlinger::getActiveConfig(const sp<IBinder>& displayToken) {
-    int activeConfig;
+int SurfaceFlinger::getActiveDisplayModeId(const sp<IBinder>& displayToken) {
+    int activeMode;
     bool isPrimary;
 
     {
         Mutex::Autolock lock(mStateLock);
 
         if (const auto display = getDisplayDeviceLocked(displayToken)) {
-            activeConfig = display->getActiveMode()->getId().value();
+            activeMode = display->getActiveMode()->getId().value();
             isPrimary = display->isPrimary();
         } else {
             ALOGE("%s: Invalid display token %p", __FUNCTION__, displayToken.get());
@@ -987,36 +983,35 @@
     }
 
     if (isPrimary) {
-        if (const auto config = getDesiredActiveConfig()) {
-            return config->configId.value();
+        if (const auto mode = getDesiredActiveMode()) {
+            return mode->modeId.value();
         }
     }
 
-    return activeConfig;
+    return activeMode;
 }
 
-void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
+void SurfaceFlinger::setDesiredActiveMode(const ActiveModeInfo& info) {
     ATRACE_CALL();
-    auto refreshRate = mRefreshRateConfigs->getRefreshRateFromConfigId(info.configId);
-    ALOGV("setDesiredActiveConfig(%s)", refreshRate.getName().c_str());
+    auto refreshRate = mRefreshRateConfigs->getRefreshRateFromModeId(info.modeId);
+    ALOGV("%s(%s)", __func__, refreshRate.getName().c_str());
 
-    std::lock_guard<std::mutex> lock(mActiveConfigLock);
-    if (mDesiredActiveConfigChanged) {
-        // If a config change is pending, just cache the latest request in
-        // mDesiredActiveConfig
-        const Scheduler::ConfigEvent prevConfig = mDesiredActiveConfig.event;
-        mDesiredActiveConfig = info;
-        mDesiredActiveConfig.event = mDesiredActiveConfig.event | prevConfig;
+    std::lock_guard<std::mutex> lock(mActiveModeLock);
+    if (mDesiredActiveModeChanged) {
+        // If a mode change is pending, just cache the latest request in mDesiredActiveMode
+        const Scheduler::ModeEvent prevConfig = mDesiredActiveMode.event;
+        mDesiredActiveMode = info;
+        mDesiredActiveMode.event = mDesiredActiveMode.event | prevConfig;
     } else {
-        // Check if we are already at the desired config
+        // Check if we are already at the desired mode
         const auto display = getDefaultDisplayDeviceLocked();
-        if (!display || display->getActiveMode()->getId() == refreshRate.getConfigId()) {
+        if (!display || display->getActiveMode()->getId() == refreshRate.getModeId()) {
             return;
         }
 
-        // Initiate a config change.
-        mDesiredActiveConfigChanged = true;
-        mDesiredActiveConfig = info;
+        // Initiate a mode change.
+        mDesiredActiveModeChanged = true;
+        mDesiredActiveMode = info;
 
         // This will trigger HWC refresh without resetting the idle timer.
         repaintEverythingForHWC();
@@ -1028,7 +1023,7 @@
         modulateVsync(&VsyncModulator::onRefreshRateChangeInitiated);
 
         updatePhaseConfiguration(refreshRate.getFps());
-        mScheduler->setConfigChangePending(true);
+        mScheduler->setModeChangePending(true);
     }
 
     if (mRefreshRateOverlay) {
@@ -1036,7 +1031,7 @@
     }
 }
 
-status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int modeId) {
+status_t SurfaceFlinger::setActiveMode(const sp<IBinder>& displayToken, int modeId) {
     ATRACE_CALL();
 
     if (!displayToken) {
@@ -1046,13 +1041,13 @@
     auto future = schedule([=]() -> status_t {
         const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken));
         if (!display) {
-            ALOGE("Attempt to set allowed display configs for invalid display token %p",
+            ALOGE("Attempt to set allowed display modes for invalid display token %p",
                   displayToken.get());
             return NAME_NOT_FOUND;
         }
 
         if (display->isVirtual()) {
-            ALOGW("Attempt to set allowed display configs for virtual display");
+            ALOGW("Attempt to set allowed display modes for virtual display");
             return INVALID_OPERATION;
         }
 
@@ -1071,13 +1066,13 @@
                                                            {fps, fps}};
         constexpr bool kOverridePolicy = false;
 
-        return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
+        return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy);
     });
 
     return future.get();
 }
 
-void SurfaceFlinger::setActiveConfigInternal() {
+void SurfaceFlinger::setActiveModeInternal() {
     ATRACE_CALL();
 
     const auto display = getDefaultDisplayDeviceLocked();
@@ -1085,21 +1080,21 @@
         return;
     }
 
-    const auto upcomingConfig = display->getMode(mUpcomingActiveConfig.configId);
-    if (!upcomingConfig) {
-        ALOGW("Upcoming active config is no longer supported. ConfigId = %zu",
-              mUpcomingActiveConfig.configId.value());
+    const auto upcomingMode = display->getMode(mUpcomingActiveMode.modeId);
+    if (!upcomingMode) {
+        ALOGW("Upcoming active mode is no longer supported. Mode ID = %zu",
+              mUpcomingActiveMode.modeId.value());
         // TODO(b/159590486) Handle the error better. Some parts of SurfaceFlinger may
-        // have been already updated with the upcoming active config.
+        // have been already updated with the upcoming active mode.
         return;
     }
     const Fps oldRefreshRate = display->getActiveMode()->getFps();
 
-    std::lock_guard<std::mutex> lock(mActiveConfigLock);
-    mRefreshRateConfigs->setCurrentConfigId(mUpcomingActiveConfig.configId);
-    display->setActiveMode(mUpcomingActiveConfig.configId);
+    std::lock_guard<std::mutex> lock(mActiveModeLock);
+    mRefreshRateConfigs->setCurrentModeId(mUpcomingActiveMode.modeId);
+    display->setActiveMode(mUpcomingActiveMode.modeId);
 
-    const Fps refreshRate = upcomingConfig->getFps();
+    const Fps refreshRate = upcomingMode->getFps();
 
     mRefreshRateStats->setRefreshRate(refreshRate);
 
@@ -1109,71 +1104,71 @@
     updatePhaseConfiguration(refreshRate);
     ATRACE_INT("ActiveConfigFPS", refreshRate.getValue());
 
-    if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
+    if (mUpcomingActiveMode.event != Scheduler::ModeEvent::None) {
         const nsecs_t vsyncPeriod = refreshRate.getPeriodNsecs();
         const auto physicalId = display->getPhysicalId();
-        mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, physicalId,
-                                                  mUpcomingActiveConfig.configId, vsyncPeriod);
+        mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, physicalId,
+                                                mUpcomingActiveMode.modeId, vsyncPeriod);
     }
 }
 
-void SurfaceFlinger::clearDesiredActiveConfigState() {
-    std::lock_guard<std::mutex> lock(mActiveConfigLock);
-    mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
-    mDesiredActiveConfigChanged = false;
-    mScheduler->setConfigChangePending(false);
+void SurfaceFlinger::clearDesiredActiveModeState() {
+    std::lock_guard<std::mutex> lock(mActiveModeLock);
+    mDesiredActiveMode.event = Scheduler::ModeEvent::None;
+    mDesiredActiveModeChanged = false;
+    mScheduler->setModeChangePending(false);
 }
 
-void SurfaceFlinger::desiredActiveConfigChangeDone() {
-    const auto modeId = getDesiredActiveConfig()->configId;
+void SurfaceFlinger::desiredActiveModeChangeDone() {
+    const auto modeId = getDesiredActiveMode()->modeId;
 
-    clearDesiredActiveConfigState();
+    clearDesiredActiveModeState();
 
     const auto refreshRate = getDefaultDisplayDeviceLocked()->getMode(modeId)->getFps();
     mScheduler->resyncToHardwareVsync(true, refreshRate.getPeriodNsecs());
     updatePhaseConfiguration(refreshRate);
 }
 
-void SurfaceFlinger::performSetActiveConfig() {
+void SurfaceFlinger::performSetActiveMode() {
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
     // Store the local variable to release the lock.
-    const auto desiredActiveConfig = getDesiredActiveConfig();
-    if (!desiredActiveConfig) {
-        // No desired active config pending to be applied
+    const auto desiredActiveMode = getDesiredActiveMode();
+    if (!desiredActiveMode) {
+        // No desired active mode pending to be applied
         return;
     }
 
     const auto display = getDefaultDisplayDeviceLocked();
-    const auto desiredConfig = display->getMode(desiredActiveConfig->configId);
-    if (!desiredConfig) {
-        ALOGW("Desired display config is no longer supported. Config ID = %zu",
-              desiredActiveConfig->configId.value());
-        clearDesiredActiveConfigState();
+    const auto desiredMode = display->getMode(desiredActiveMode->modeId);
+    if (!desiredMode) {
+        ALOGW("Desired display mode is no longer supported. Mode ID = %zu",
+              desiredActiveMode->modeId.value());
+        clearDesiredActiveModeState();
         return;
     }
-    const auto refreshRate = desiredConfig->getFps();
-    ALOGV("performSetActiveConfig changing active config to %zu(%s)",
-          desiredConfig->getId().value(), to_string(refreshRate).c_str());
+    const auto refreshRate = desiredMode->getFps();
+    ALOGV("%s changing active mode to %zu(%s)", __FUNCTION__, desiredMode->getId().value(),
+          to_string(refreshRate).c_str());
 
-    if (!display || display->getActiveMode()->getId() == desiredActiveConfig->configId) {
+    if (!display || display->getActiveMode()->getId() == desiredActiveMode->modeId) {
         // display is not valid or we are already in the requested mode
         // on both cases there is nothing left to do
-        desiredActiveConfigChangeDone();
+        desiredActiveModeChangeDone();
         return;
     }
 
-    // Desired active config was set, it is different than the config currently in use, however
-    // allowed configs might have changed by the time we process the refresh.
-    // Make sure the desired config is still allowed
-    if (!isDisplayConfigAllowed(desiredActiveConfig->configId)) {
-        desiredActiveConfigChangeDone();
+    // Desired active mode was set, it is different than the mode currently in use, however
+    // allowed modes might have changed by the time we process the refresh.
+    // Make sure the desired mode is still allowed
+    if (!isDisplayModeAllowed(desiredActiveMode->modeId)) {
+        desiredActiveModeChangeDone();
         return;
     }
 
-    mUpcomingActiveConfig = *desiredActiveConfig;
+    mUpcomingActiveMode = *desiredActiveMode;
 
-    ATRACE_INT("ActiveConfigFPS_HWC", refreshRate.getValue());
+    ATRACE_INT("ActiveModeFPS_HWC", refreshRate.getValue());
 
     // TODO(b/142753666) use constrains
     hal::VsyncPeriodChangeConstraints constraints;
@@ -1182,7 +1177,7 @@
 
     hal::VsyncPeriodChangeTimeline outTimeline;
     const auto status =
-            display->initiateModeChange(mUpcomingActiveConfig.configId, constraints, &outTimeline);
+            display->initiateModeChange(mUpcomingActiveMode.modeId, constraints, &outTimeline);
     if (status != NO_ERROR) {
         // initiateModeChange may fail if a hotplug event is just about
         // to be sent. We just log the error in this case.
@@ -1192,7 +1187,7 @@
 
     mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline);
     // Scheduler will submit an empty frame to HWC if needed.
-    mSetActiveConfigPending = true;
+    mSetActiveModePending = true;
 }
 
 status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
@@ -1586,12 +1581,11 @@
 }
 
 nsecs_t SurfaceFlinger::getVsyncPeriodFromHWC() const {
-    const auto displayId = getInternalDisplayIdLocked();
-    if (!displayId || !getHwComposer().isConnected(*displayId)) {
-        return 0;
+    if (const auto display = getDefaultDisplayDeviceLocked()) {
+        return display->getVsyncPeriodFromHWC();
     }
 
-    return getHwComposer().getDisplayVsyncPeriod(*displayId);
+    return 0;
 }
 
 void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId,
@@ -1605,6 +1599,12 @@
         return;
     }
 
+    if (const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId)) {
+        auto token = getPhysicalDisplayTokenLocked(*displayId);
+        auto display = getDisplayDeviceLocked(token);
+        display->onVsync(timestamp);
+    }
+
     if (!getHwComposer().onVsync(hwcDisplayId, timestamp)) {
         return;
     }
@@ -1626,12 +1626,12 @@
     *compositorTiming = getBE().mCompositorTiming;
 }
 
-bool SurfaceFlinger::isDisplayConfigAllowed(DisplayModeId configId) const {
-    return mRefreshRateConfigs->isConfigAllowed(configId);
+bool SurfaceFlinger::isDisplayModeAllowed(DisplayModeId modeId) const {
+    return mRefreshRateConfigs->isModeAllowed(modeId);
 }
 
 void SurfaceFlinger::changeRefreshRateLocked(const RefreshRate& refreshRate,
-                                             Scheduler::ConfigEvent event) {
+                                             Scheduler::ModeEvent event) {
     const auto display = getDefaultDisplayDeviceLocked();
     if (!display || mBootStage != BootStage::FINISHED) {
         return;
@@ -1639,13 +1639,13 @@
     ATRACE_CALL();
 
     // Don't do any updating if the current fps is the same as the new one.
-    if (!isDisplayConfigAllowed(refreshRate.getConfigId())) {
-        ALOGV("Skipping config %zu as it is not part of allowed configs",
-              refreshRate.getConfigId().value());
+    if (!isDisplayModeAllowed(refreshRate.getModeId())) {
+        ALOGV("Skipping mode %zu as it is not part of allowed modes",
+              refreshRate.getModeId().value());
         return;
     }
 
-    setDesiredActiveConfig({refreshRate.getConfigId(), event});
+    setDesiredActiveMode({refreshRate.getModeId(), event});
 }
 
 void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hal::HWDisplayId hwcDisplayId,
@@ -1828,18 +1828,18 @@
         mGpuFrameMissedCount++;
     }
 
-    // If we are in the middle of a config change and the fence hasn't
+    // If we are in the middle of a mode change and the fence hasn't
     // fired yet just wait for the next invalidate
-    if (mSetActiveConfigPending) {
+    if (mSetActiveModePending) {
         if (framePending) {
             mEventQueue->invalidate();
             return;
         }
 
         // We received the present fence from the HWC, so we assume it successfully updated
-        // the config, hence we update SF.
-        mSetActiveConfigPending = false;
-        ON_MAIN_THREAD(setActiveConfigInternal());
+        // the mode, hence we update SF.
+        mSetActiveModePending = false;
+        ON_MAIN_THREAD(setActiveModeInternal());
     }
 
     if (framePending) {
@@ -1919,7 +1919,7 @@
         mScheduler->chooseRefreshRateForContent();
     }
 
-    ON_MAIN_THREAD(performSetActiveConfig());
+    ON_MAIN_THREAD(performSetActiveMode());
 
     updateCursorAsync();
     updateInputFlinger();
@@ -2194,8 +2194,8 @@
         }
     });
 
-    mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]);
-    mTransactionCompletedThread.sendCallbacks();
+    mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0]);
+    mTransactionCallbackInvoker.sendCallbacks();
 
     if (display && display->isPrimary() && display->getPowerMode() == hal::PowerMode::ON &&
         presentFenceTime->isValid()) {
@@ -2220,8 +2220,7 @@
         } else if (isDisplayConnected) {
             // The HWC doesn't support present fences, so use the refresh
             // timestamp instead.
-            const nsecs_t presentTime =
-                    getHwComposer().getRefreshTimestamp(display->getPhysicalId());
+            const nsecs_t presentTime = display->getRefreshTimestamp();
             mAnimFrameTracker.setActualPresentTime(presentTime);
         }
         mAnimFrameTracker.advanceFrame();
@@ -2358,6 +2357,24 @@
     // here the transaction has been committed
 }
 
+DisplayModes SurfaceFlinger::loadSupportedDisplayModes(PhysicalDisplayId displayId) const {
+    const auto hwcModes = getHwComposer().getModes(displayId);
+    DisplayModes modes;
+    size_t nextModeId = 0;
+    for (const auto& hwcMode : hwcModes) {
+        modes.push_back(DisplayMode::Builder(hwcMode.hwcId)
+                                .setId(DisplayModeId{nextModeId++})
+                                .setWidth(hwcMode.width)
+                                .setHeight(hwcMode.height)
+                                .setVsyncPeriod(hwcMode.vsyncPeriod)
+                                .setDpiX(hwcMode.dpiX)
+                                .setDpiY(hwcMode.dpiY)
+                                .setGroup(hwcMode.configGroup)
+                                .build());
+    }
+    return modes;
+}
+
 void SurfaceFlinger::processDisplayHotplugEventsLocked() {
     for (const auto& event : mPendingHotplugEvents) {
         std::optional<DisplayIdentificationInfo> info =
@@ -2371,8 +2388,14 @@
         const auto it = mPhysicalDisplayTokens.find(displayId);
 
         if (event.connection == hal::Connection::CONNECTED) {
-            auto supportedModes = getHwComposer().getModes(displayId);
-            const auto activeMode = getHwComposer().getActiveMode(displayId);
+            auto supportedModes = loadSupportedDisplayModes(displayId);
+            const auto activeModeHwcId = getHwComposer().getActiveMode(displayId);
+            LOG_ALWAYS_FATAL_IF(!activeModeHwcId, "HWC returned no active mode");
+
+            const auto activeMode = *std::find_if(supportedModes.begin(), supportedModes.end(),
+                                                  [activeModeHwcId](const DisplayModePtr& mode) {
+                                                      return mode->getHwcId() == *activeModeHwcId;
+                                                  });
             // TODO(b/175678215) Handle the case when activeMode is not in supportedModes
 
             if (it == mPhysicalDisplayTokens.end()) {
@@ -2523,17 +2546,15 @@
 
 void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
                                          const DisplayDeviceState& state) {
-    int width = 0;
-    int height = 0;
+    ui::Size resolution(0, 0);
     ui::PixelFormat pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_UNKNOWN);
     if (state.physical) {
-        width = state.physical->activeMode->getWidth();
-        height = state.physical->activeMode->getHeight();
+        resolution = state.physical->activeMode->getSize();
         pixelFormat = static_cast<ui::PixelFormat>(PIXEL_FORMAT_RGBA_8888);
     } else if (state.surface != nullptr) {
-        int status = state.surface->query(NATIVE_WINDOW_WIDTH, &width);
+        int status = state.surface->query(NATIVE_WINDOW_WIDTH, &resolution.width);
         ALOGE_IF(status != NO_ERROR, "Unable to query width (%d)", status);
-        status = state.surface->query(NATIVE_WINDOW_HEIGHT, &height);
+        status = state.surface->query(NATIVE_WINDOW_HEIGHT, &resolution.height);
         ALOGE_IF(status != NO_ERROR, "Unable to query height (%d)", status);
         int intPixelFormat;
         status = state.surface->query(NATIVE_WINDOW_FORMAT, &intPixelFormat);
@@ -2550,7 +2571,7 @@
     if (const auto& physical = state.physical) {
         builder.setPhysical({physical->id, physical->type});
     }
-    builder.setPixels(ui::Size(width, height));
+    builder.setPixels(resolution);
     builder.setPixelFormat(pixelFormat);
     builder.setIsSecure(state.isSecure);
     builder.setLayerStackId(state.layerStack);
@@ -2585,7 +2606,8 @@
         const auto physicalId = PhysicalDisplayId::tryCast(displayId);
         LOG_FATAL_IF(!physicalId);
         displaySurface = new FramebufferSurface(getHwComposer(), *physicalId, bqConsumer,
-                                                maxGraphicsWidth, maxGraphicsHeight);
+                                                state.physical->activeMode->getSize(),
+                                                ui::Size(maxGraphicsWidth, maxGraphicsHeight));
         producer = bqProducer;
     }
 
@@ -2652,9 +2674,8 @@
 
             // TODO(b/175678251) Call a listener instead.
             if (currentState.physical->hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
-                mRefreshRateConfigs
-                        ->updateDisplayConfigs(currentState.physical->supportedModes,
-                                               currentState.physical->activeMode->getId());
+                mRefreshRateConfigs->updateDisplayModes(currentState.physical->supportedModes,
+                                                        currentState.physical->activeMode->getId());
                 mVsyncConfiguration->reset();
                 updatePhaseConfiguration(mRefreshRateConfigs->getCurrentRefreshRate().getFps());
                 if (mRefreshRateOverlay) {
@@ -2912,8 +2933,7 @@
     mCompositionEngine->updateCursorAsync(refreshArgs);
 }
 
-void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate,
-                                       Scheduler::ConfigEvent event) {
+void SurfaceFlinger::changeRefreshRate(const RefreshRate& refreshRate, Scheduler::ModeEvent event) {
     // If this is called from the main thread mStateLock must be locked before
     // Currently the only way to call this function from the main thread is from
     // Scheduler::chooseRefreshRateForContent
@@ -2973,16 +2993,16 @@
     mRegionSamplingThread =
             new RegionSamplingThread(*this, *mScheduler,
                                      RegionSamplingThread::EnvironmentTimingTunables());
-    // Dispatch a config change request for the primary display on scheduler
+    // Dispatch a mode change request for the primary display on scheduler
     // initialization, so that the EventThreads always contain a reference to a
     // prior configuration.
     //
     // This is a bit hacky, but this avoids a back-pointer into the main SF
     // classes from EventThread, and there should be no run-time binder cost
     // anyway since there are no connected apps at this point.
-    mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, displayId,
-                                              displayState.physical->activeMode->getId(),
-                                              vsyncPeriod);
+    mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, displayId,
+                                            displayState.physical->activeMode->getId(),
+                                            vsyncPeriod);
     static auto ignorePresentFences =
             base::GetBoolProperty("debug.sf.vsync_reactor_ignore_present_fences"s, false);
     mScheduler->setIgnorePresentFences(
@@ -3268,66 +3288,75 @@
     // we must keep a copy of the transactions (specifically the composer
     // states) around outside the scope of the lock
     std::vector<const TransactionState> transactions;
+    // Layer handles that have transactions with buffers that are ready to be applied.
+    std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> pendingBuffers;
     {
-        Mutex::Autolock _l(mQueueLock);
-        // Collect transactions from pending transaction queue.
-        auto it = mPendingTransactionQueues.begin();
-        while (it != mPendingTransactionQueues.end()) {
-            auto& [applyToken, transactionQueue] = *it;
+        Mutex::Autolock _l(mStateLock);
+        {
+            Mutex::Autolock _l(mQueueLock);
+            // Collect transactions from pending transaction queue.
+            auto it = mPendingTransactionQueues.begin();
+            while (it != mPendingTransactionQueues.end()) {
+                auto& [applyToken, transactionQueue] = *it;
 
-            while (!transactionQueue.empty()) {
-                const auto& transaction = transactionQueue.front();
+                while (!transactionQueue.empty()) {
+                    const auto& transaction = transactionQueue.front();
+                    if (!transactionIsReadyToBeApplied(transaction.isAutoTimestamp,
+                                                       transaction.desiredPresentTime,
+                                                       transaction.states,
+                                                       false /* updateTransactionCounters*/,
+                                                       pendingBuffers)) {
+                        setTransactionFlags(eTransactionFlushNeeded);
+                        break;
+                    }
+                    transactions.push_back(transaction);
+                    transactionQueue.pop();
+                }
+
+                if (transactionQueue.empty()) {
+                    it = mPendingTransactionQueues.erase(it);
+                    mTransactionQueueCV.broadcast();
+                } else {
+                    it = std::next(it, 1);
+                }
+            }
+
+            // Collect transactions from current transaction queue or queue to pending transactions.
+            // Case 1: push to pending when transactionIsReadyToBeApplied is false.
+            // Case 2: push to pending when there exist a pending queue.
+            // Case 3: others are ready to apply.
+            while (!mTransactionQueue.empty()) {
+                const auto& transaction = mTransactionQueue.front();
+                bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) !=
+                        mPendingTransactionQueues.end();
+                // Call transactionIsReadyToBeApplied first in case we need to
+                // incrementPendingBufferCount and keep track of pending buffers
+                // if the transaction contains a buffer.
                 if (!transactionIsReadyToBeApplied(transaction.isAutoTimestamp,
                                                    transaction.desiredPresentTime,
-                                                   transaction.states)) {
-                    setTransactionFlags(eTransactionFlushNeeded);
-                    break;
+                                                   transaction.states,
+                                                   true /* updateTransactionCounters */,
+                                                   pendingBuffers) ||
+                    pendingTransactions) {
+                    mPendingTransactionQueues[transaction.applyToken].push(transaction);
+                } else {
+                    transactions.push_back(transaction);
                 }
-                transactions.push_back(transaction);
-                transactionQueue.pop();
-            }
-
-            if (transactionQueue.empty()) {
-                it = mPendingTransactionQueues.erase(it);
-                mTransactionQueueCV.broadcast();
-            } else {
-                it = std::next(it, 1);
+                mTransactionQueue.pop();
             }
         }
 
-        // Collect transactions from current transaction queue or queue to pending transactions.
-        // Case 1: push to pending when transactionIsReadyToBeApplied is false.
-        // Case 2: push to pending when there exist a pending queue.
-        // Case 3: others are ready to apply.
-        while (!mTransactionQueue.empty()) {
-            const auto& transaction = mTransactionQueue.front();
-            bool pendingTransactions = mPendingTransactionQueues.find(transaction.applyToken) !=
-                    mPendingTransactionQueues.end();
-            // Call transactionIsReadyToBeApplied first in case we need to
-            // incrementPendingBufferCount if the transaction contains a buffer.
-            if (!transactionIsReadyToBeApplied(transaction.isAutoTimestamp,
-                                               transaction.desiredPresentTime, transaction.states,
-                                               true) ||
-                pendingTransactions) {
-                mPendingTransactionQueues[transaction.applyToken].push(transaction);
-            } else {
-                transactions.push_back(transaction);
-            }
-            mTransactionQueue.pop();
+        // Now apply all transactions.
+        for (const auto& transaction : transactions) {
+            applyTransactionState(transaction.frameTimelineInfo, transaction.states,
+                                  transaction.displays, transaction.flags,
+                                  transaction.inputWindowCommands, transaction.desiredPresentTime,
+                                  transaction.isAutoTimestamp, transaction.buffer,
+                                  transaction.postTime, transaction.privileged,
+                                  transaction.hasListenerCallbacks, transaction.listenerCallbacks,
+                                  transaction.originPid, transaction.originUid, transaction.id);
         }
     }
-
-    // Now apply all transactions.
-    Mutex::Autolock _l(mStateLock);
-    for (const auto& transaction : transactions) {
-        applyTransactionState(transaction.frameTimelineInfo, transaction.states,
-                              transaction.displays, transaction.flags,
-                              transaction.inputWindowCommands, transaction.desiredPresentTime,
-                              transaction.isAutoTimestamp, transaction.buffer, transaction.postTime,
-                              transaction.privileged, transaction.hasListenerCallbacks,
-                              transaction.listenerCallbacks, transaction.originPid,
-                              transaction.originUid, transaction.id);
-    }
 }
 
 bool SurfaceFlinger::transactionFlushNeeded() {
@@ -3335,9 +3364,10 @@
     return !mPendingTransactionQueues.empty();
 }
 
-bool SurfaceFlinger::transactionIsReadyToBeApplied(bool isAutoTimestamp, int64_t desiredPresentTime,
-                                                   const Vector<ComposerState>& states,
-                                                   bool updateTransactionCounters) {
+bool SurfaceFlinger::transactionIsReadyToBeApplied(
+        bool isAutoTimestamp, int64_t desiredPresentTime, const Vector<ComposerState>& states,
+        bool updateTransactionCounters,
+        std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& pendingBuffers) {
     const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
     bool ready = true;
     // Do not present if the desiredPresentTime has not passed unless it is more than one second
@@ -3356,7 +3386,6 @@
             ready = false;
         }
 
-        Mutex::Autolock _l(mStateLock);
         sp<Layer> layer = nullptr;
         if (s.surface) {
             layer = fromHandleLocked(s.surface).promote();
@@ -3379,12 +3408,11 @@
 
         // If backpressure is enabled and we already have a buffer to commit, keep the transaction
         // in the queue.
-        bool hasBuffer = s.what & layer_state_t::eBufferChanged ||
-                s.what & layer_state_t::eCachedBufferChanged;
-        if (hasBuffer && layer->backpressureEnabled() && layer->hasPendingBuffer() &&
-            isAutoTimestamp) {
+        const bool hasPendingBuffer = pendingBuffers.find(s.surface) != pendingBuffers.end();
+        if (layer->backpressureEnabled() && hasPendingBuffer && isAutoTimestamp) {
             ready = false;
         }
+        pendingBuffers.insert(s.surface);
     }
     return ready;
 }
@@ -3524,8 +3552,8 @@
     // that listeners with SurfaceControls will start registration during setClientStateLocked
     // below.
     for (const auto& listener : listenerCallbacks) {
-        mTransactionCompletedThread.startRegistration(listener);
-        mTransactionCompletedThread.endRegistration(listener);
+        mTransactionCallbackInvoker.startRegistration(listener);
+        mTransactionCallbackInvoker.endRegistration(listener);
     }
 
     std::unordered_set<ListenerCallbacks, ListenerCallbacksHash> listenerCallbacksWithSurfaces;
@@ -3533,8 +3561,7 @@
     for (const ComposerState& state : states) {
         clientStateFlags |=
                 setClientStateLocked(frameTimelineInfo, state, desiredPresentTime, isAutoTimestamp,
-                                     postTime, privileged, listenerCallbacksWithSurfaces, originPid,
-                                     originUid);
+                                     postTime, privileged, listenerCallbacksWithSurfaces);
         if ((flags & eAnimation) && state.state.surface) {
             if (const auto layer = fromHandleLocked(state.state.surface).promote(); layer) {
                 mScheduler->recordLayerHistory(layer.get(),
@@ -3545,12 +3572,12 @@
     }
 
     for (const auto& listenerCallback : listenerCallbacksWithSurfaces) {
-        mTransactionCompletedThread.endRegistration(listenerCallback);
+        mTransactionCallbackInvoker.endRegistration(listenerCallback);
     }
 
     // If the state doesn't require a traversal and there are callbacks, send them now
     if (!(clientStateFlags & eTraversalNeeded) && hasListenerCallbacks) {
-        mTransactionCompletedThread.sendCallbacks();
+        mTransactionCallbackInvoker.sendCallbacks();
     }
     transactionFlags |= clientStateFlags;
 
@@ -3659,14 +3686,13 @@
 uint32_t SurfaceFlinger::setClientStateLocked(
         const FrameTimelineInfo& frameTimelineInfo, const ComposerState& composerState,
         int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged,
-        std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks,
-        int originPid, int originUid) {
+        std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks) {
     const layer_state_t& s = composerState.state;
 
     for (auto& listener : s.listeners) {
         // note that startRegistration will not re-register if the listener has
         // already be registered for a prior surface control
-        mTransactionCompletedThread.startRegistration(listener);
+        mTransactionCallbackInvoker.startRegistration(listener);
         listenerCallbacks.insert(listener);
     }
 
@@ -3679,7 +3705,7 @@
     }
     if (layer == nullptr) {
         for (auto& [listener, callbackIds] : s.listeners) {
-            mTransactionCompletedThread.registerUnpresentedCallbackHandle(
+            mTransactionCallbackInvoker.registerUnpresentedCallbackHandle(
                     new CallbackHandle(listener, callbackIds, s.surface));
         }
         return 0;
@@ -3806,14 +3832,10 @@
         if (layer->setCornerRadius(s.cornerRadius))
             flags |= eTraversalNeeded;
     }
-
-    if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs && mSupportsBlur &&
-        originalCallerCanUseBlurs(originPid, originUid)) {
+    if (what & layer_state_t::eBackgroundBlurRadiusChanged && !mDisableBlurs && mSupportsBlur) {
         if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded;
     }
-
-    if (what & layer_state_t::eBlurRegionsChanged &&
-        originalCallerCanUseBlurs(originPid, originUid)) {
+    if (what & layer_state_t::eBlurRegionsChanged) {
         if (layer->setBlurRegions(s.blurRegions)) flags |= eTraversalNeeded;
     }
     if (what & layer_state_t::eLayerStackChanged) {
@@ -3914,10 +3936,11 @@
             flags |= eTraversalNeeded;
         }
     }
+    FrameTimelineInfo info;
     if (what & layer_state_t::eFrameTimelineInfoChanged) {
-        layer->setFrameTimelineInfoForTransaction(s.frameTimelineInfo, postTime);
+        info = s.frameTimelineInfo;
     } else if (frameTimelineInfo.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
-        layer->setFrameTimelineInfoForTransaction(frameTimelineInfo, postTime);
+        info = frameTimelineInfo;
     }
     if (what & layer_state_t::eFixedTransformHintChanged) {
         if (layer->setFixedTransformHint(s.fixedTransformHint)) {
@@ -3927,6 +3950,11 @@
     if (what & layer_state_t::eAutoRefreshChanged) {
         layer->setAutoRefresh(s.autoRefresh);
     }
+    if (what & layer_state_t::eStretchChanged) {
+        if (layer->setStretchEffect(s.stretchEffect)) {
+            flags |= eTraversalNeeded;
+        }
+    }
     // This has to happen after we reparent children because when we reparent to null we remove
     // child layers from current state and remove its relative z. If the children are reparented in
     // the same transaction, then we have to make sure we reparent the children first so we do not
@@ -3976,9 +4004,11 @@
                 : layer->getHeadFrameNumber(-1 /* expectedPresentTime */) + 1;
 
         if (layer->setBuffer(buffer, s.acquireFence, postTime, desiredPresentTime, isAutoTimestamp,
-                             s.cachedBuffer, frameNumber, dequeueBufferTimestamp)) {
+                             s.cachedBuffer, frameNumber, dequeueBufferTimestamp, info)) {
             flags |= eTraversalNeeded;
         }
+    } else if (info.vsyncId != FrameTimelineInfo::INVALID_VSYNC_ID) {
+        layer->setFrameTimelineVsyncForBufferlessTransaction(info, postTime);
     }
 
     if (layer->setTransactionCompletedListeners(callbackHandles)) flags |= eTraversalNeeded;
@@ -4515,8 +4545,8 @@
 
     mRefreshRateConfigs->dump(result);
 
-    StringAppendF(&result, "(config override by backdoor: %s)\n\n",
-                  mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
+    StringAppendF(&result, "(mode override by backdoor: %s)\n\n",
+                  mDebugDisplayModeSetByBackdoor ? "yes" : "no");
 
     mScheduler->dump(mAppConnectionHandle, result);
     mScheduler->dumpVsync(result);
@@ -4834,15 +4864,12 @@
                   "  gpu_to_cpu_unsupported    : %d\n",
                   mTransactionFlags.load(), !mGpuToCpuSupported);
 
-    if (const auto displayId = getInternalDisplayIdLocked();
-        displayId && getHwComposer().isConnected(*displayId)) {
-        const auto activeConfig = getHwComposer().getActiveMode(*displayId);
+    if (const auto display = getDefaultDisplayDeviceLocked()) {
         std::string fps, xDpi, yDpi;
-        if (activeConfig) {
-            const auto vsyncPeriod = getHwComposer().getDisplayVsyncPeriod(*displayId);
-            fps = base::StringPrintf("%s", to_string(Fps::fromPeriodNsecs(vsyncPeriod)).c_str());
-            xDpi = base::StringPrintf("%.2f", activeConfig->getDpiX());
-            yDpi = base::StringPrintf("%.2f", activeConfig->getDpiY());
+        if (const auto activeMode = display->getActiveMode()) {
+            fps = to_string(activeMode->getFps());
+            xDpi = base::StringPrintf("%.2f", activeMode->getDpiX());
+            yDpi = base::StringPrintf("%.2f", activeMode->getDpiY());
         } else {
             fps = "unknown";
             xDpi = "unknown";
@@ -4938,8 +4965,8 @@
         case ENABLE_VSYNC_INJECTIONS:
         case GET_ANIMATION_FRAME_STATS:
         case GET_HDR_CAPABILITIES:
-        case SET_DESIRED_DISPLAY_CONFIG_SPECS:
-        case GET_DESIRED_DISPLAY_CONFIG_SPECS:
+        case SET_DESIRED_DISPLAY_MODE_SPECS:
+        case GET_DESIRED_DISPLAY_MODE_SPECS:
         case SET_ACTIVE_COLOR_MODE:
         case GET_AUTO_LOW_LATENCY_MODE_SUPPORT:
         case SET_AUTO_LOW_LATENCY_MODE:
@@ -4981,13 +5008,13 @@
         // information, so it is OK to pass them.
         case AUTHENTICATE_SURFACE:
         case GET_ACTIVE_COLOR_MODE:
-        case GET_ACTIVE_CONFIG:
+        case GET_ACTIVE_DISPLAY_MODE:
         case GET_PHYSICAL_DISPLAY_IDS:
         case GET_PHYSICAL_DISPLAY_TOKEN:
         case GET_DISPLAY_COLOR_MODES:
         case GET_DISPLAY_NATIVE_PRIMARIES:
         case GET_DISPLAY_INFO:
-        case GET_DISPLAY_CONFIGS:
+        case GET_DISPLAY_MODES:
         case GET_DISPLAY_STATE:
         case GET_DISPLAY_STATS:
         case GET_SUPPORTED_FRAME_TIMESTAMPS:
@@ -5008,8 +5035,9 @@
         case CAPTURE_DISPLAY:
         case SET_DISPLAY_BRIGHTNESS:
         case SET_FRAME_TIMELINE_INFO:
-        // This is not sensitive information, so should not require permission control.
-        case GET_GPU_CONTEXT_PRIORITY: {
+        case GET_GPU_CONTEXT_PRIORITY:
+        case GET_EXTRA_BUFFER_COUNT: {
+            // This is not sensitive information, so should not require permission control.
             return OK;
         }
         case ADD_REGION_SAMPLING_LISTENER:
@@ -5361,7 +5389,7 @@
             }
             case 1035: {
                 const int modeId = data.readInt32();
-                mDebugDisplayConfigSetByBackdoor = false;
+                mDebugDisplayModeSetByBackdoor = false;
 
                 const auto displayId = getInternalDisplayId();
                 if (!displayId) {
@@ -5369,12 +5397,12 @@
                     return NO_ERROR;
                 }
 
-                status_t result = setActiveConfig(getPhysicalDisplayToken(*displayId), modeId);
+                status_t result = setActiveMode(getPhysicalDisplayToken(*displayId), modeId);
                 if (result != NO_ERROR) {
                     return result;
                 }
 
-                mDebugDisplayConfigSetByBackdoor = true;
+                mDebugDisplayModeSetByBackdoor = true;
 
                 return NO_ERROR;
             }
@@ -5453,14 +5481,13 @@
     // Update the overlay on the main thread to avoid race conditions with
     // mRefreshRateConfigs->getCurrentRefreshRate()
     static_cast<void>(schedule([=] {
-        const auto desiredActiveConfig = getDesiredActiveConfig();
-        const std::optional<DisplayModeId> desiredConfigId = desiredActiveConfig
-                ? std::make_optional(desiredActiveConfig->configId)
-                : std::nullopt;
+        const auto desiredActiveMode = getDesiredActiveMode();
+        const std::optional<DisplayModeId> desiredModeId =
+                desiredActiveMode ? std::make_optional(desiredActiveMode->modeId) : std::nullopt;
 
         const bool timerExpired = mKernelIdleTimerEnabled && expired;
         const auto newRefreshRate =
-                mRefreshRateConfigs->onKernelTimerChanged(desiredConfigId, timerExpired);
+                mRefreshRateConfigs->onKernelTimerChanged(desiredModeId, timerExpired);
         if (newRefreshRate) {
             if (Mutex::Autolock lock(mStateLock); mRefreshRateOverlay) {
                 mRefreshRateOverlay->changeRefreshRate(*newRefreshRate);
@@ -6047,7 +6074,7 @@
     }
 }
 
-status_t SurfaceFlinger::setDesiredDisplayConfigSpecsInternal(
+status_t SurfaceFlinger::setDesiredDisplayModeSpecsInternal(
         const sp<DisplayDevice>& display,
         const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy) {
     Mutex::Autolock lock(mStateLock);
@@ -6057,10 +6084,10 @@
     LOG_ALWAYS_FATAL_IF(!policy && !overridePolicy, "Can only clear the override policy");
 
     if (!display->isPrimary()) {
-        // TODO(b/144711714): For non-primary displays we should be able to set an active config
+        // TODO(b/144711714): For non-primary displays we should be able to set an active mode
         // as well. For now, just call directly to initiateModeChange but ideally
-        // it should go thru setDesiredActiveConfig, similar to primary display.
-        ALOGV("setAllowedDisplayConfigsInternal for non-primary display");
+        // it should go thru setDesiredActiveMode, similar to primary display.
+        ALOGV("%s for non-primary display", __func__);
         const auto displayId = display->getPhysicalId();
 
         hal::VsyncPeriodChangeConstraints constraints;
@@ -6068,23 +6095,22 @@
         constraints.seamlessRequired = false;
 
         hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
-        if (display->initiateModeChange(policy->defaultConfig, constraints, &timeline) !=
-            NO_ERROR) {
+        if (display->initiateModeChange(policy->defaultMode, constraints, &timeline) != NO_ERROR) {
             return BAD_VALUE;
         }
         if (timeline.refreshRequired) {
             repaintEverythingForHWC();
         }
 
-        display->setActiveMode(policy->defaultConfig);
-        const nsecs_t vsyncPeriod = display->getMode(policy->defaultConfig)->getVsyncPeriod();
-        mScheduler->onNonPrimaryDisplayConfigChanged(mAppConnectionHandle, displayId,
-                                                     policy->defaultConfig, vsyncPeriod);
+        display->setActiveMode(policy->defaultMode);
+        const nsecs_t vsyncPeriod = display->getMode(policy->defaultMode)->getVsyncPeriod();
+        mScheduler->onNonPrimaryDisplayModeChanged(mAppConnectionHandle, displayId,
+                                                   policy->defaultMode, vsyncPeriod);
         return NO_ERROR;
     }
 
-    if (mDebugDisplayConfigSetByBackdoor) {
-        // ignore this request as config is overridden by backdoor
+    if (mDebugDisplayModeSetByBackdoor) {
+        // ignore this request as mode is overridden by backdoor
         return NO_ERROR;
     }
 
@@ -6099,42 +6125,43 @@
     }
     scheduler::RefreshRateConfigs::Policy currentPolicy = mRefreshRateConfigs->getCurrentPolicy();
 
-    ALOGV("Setting desired display config specs: %s", currentPolicy.toString().c_str());
+    ALOGV("Setting desired display mode specs: %s", currentPolicy.toString().c_str());
 
     // TODO(b/140204874): Leave the event in until we do proper testing with all apps that might
     // be depending in this callback.
-    const auto activeConfig = display->getActiveMode();
-    const nsecs_t vsyncPeriod = activeConfig->getVsyncPeriod();
+    const auto activeMode = display->getActiveMode();
+    const nsecs_t vsyncPeriod = activeMode->getVsyncPeriod();
     const auto physicalId = display->getPhysicalId();
-    mScheduler->onPrimaryDisplayConfigChanged(mAppConnectionHandle, physicalId,
-                                              activeConfig->getId(), vsyncPeriod);
+    mScheduler->onPrimaryDisplayModeChanged(mAppConnectionHandle, physicalId, activeMode->getId(),
+                                            vsyncPeriod);
     toggleKernelIdleTimer();
 
-    auto configId = mScheduler->getPreferredConfigId();
-    auto preferredRefreshRate = configId
-            ? mRefreshRateConfigs->getRefreshRateFromConfigId(*configId)
-            // NOTE: Choose the default config ID, if Scheduler doesn't have one in mind.
-            : mRefreshRateConfigs->getRefreshRateFromConfigId(currentPolicy.defaultConfig);
-    ALOGV("trying to switch to Scheduler preferred config %zu (%s)",
-          preferredRefreshRate.getConfigId().value(), preferredRefreshRate.getName().c_str());
+    auto modeId = mScheduler->getPreferredModeId();
+    auto preferredRefreshRate = modeId
+            ? mRefreshRateConfigs->getRefreshRateFromModeId(*modeId)
+            // NOTE: Choose the default mode ID, if Scheduler doesn't have one in mind.
+            : mRefreshRateConfigs->getRefreshRateFromModeId(currentPolicy.defaultMode);
+    ALOGV("trying to switch to Scheduler preferred mode %zu (%s)",
+          preferredRefreshRate.getModeId().value(), preferredRefreshRate.getName().c_str());
 
-    if (isDisplayConfigAllowed(preferredRefreshRate.getConfigId())) {
-        ALOGV("switching to Scheduler preferred config %zu",
-              preferredRefreshRate.getConfigId().value());
-        setDesiredActiveConfig(
-                {preferredRefreshRate.getConfigId(), Scheduler::ConfigEvent::Changed});
+    if (isDisplayModeAllowed(preferredRefreshRate.getModeId())) {
+        ALOGV("switching to Scheduler preferred display mode %zu",
+              preferredRefreshRate.getModeId().value());
+        setDesiredActiveMode({preferredRefreshRate.getModeId(), Scheduler::ModeEvent::Changed});
     } else {
-        LOG_ALWAYS_FATAL("Desired config not allowed: %zu",
-                         preferredRefreshRate.getConfigId().value());
+        LOG_ALWAYS_FATAL("Desired display mode not allowed: %zu",
+                         preferredRefreshRate.getModeId().value());
     }
 
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::setDesiredDisplayConfigSpecs(
-        const sp<IBinder>& displayToken, int32_t defaultConfig, bool allowGroupSwitching,
-        float primaryRefreshRateMin, float primaryRefreshRateMax, float appRequestRefreshRateMin,
-        float appRequestRefreshRateMax) {
+status_t SurfaceFlinger::setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
+                                                    size_t defaultMode, bool allowGroupSwitching,
+                                                    float primaryRefreshRateMin,
+                                                    float primaryRefreshRateMax,
+                                                    float appRequestRefreshRateMin,
+                                                    float appRequestRefreshRateMax) {
     ATRACE_CALL();
 
     if (!displayToken) {
@@ -6144,34 +6171,34 @@
     auto future = schedule([=]() -> status_t {
         const auto display = ON_MAIN_THREAD(getDisplayDeviceLocked(displayToken));
         if (!display) {
-            ALOGE("Attempt to set desired display configs for invalid display token %p",
+            ALOGE("Attempt to set desired display modes for invalid display token %p",
                   displayToken.get());
             return NAME_NOT_FOUND;
         } else if (display->isVirtual()) {
-            ALOGW("Attempt to set desired display configs for virtual display");
+            ALOGW("Attempt to set desired display modes for virtual display");
             return INVALID_OPERATION;
         } else {
             using Policy = scheduler::RefreshRateConfigs::Policy;
-            const Policy policy{DisplayModeId(defaultConfig),
+            const Policy policy{DisplayModeId(defaultMode),
                                 allowGroupSwitching,
                                 {Fps(primaryRefreshRateMin), Fps(primaryRefreshRateMax)},
                                 {Fps(appRequestRefreshRateMin), Fps(appRequestRefreshRateMax)}};
             constexpr bool kOverridePolicy = false;
 
-            return setDesiredDisplayConfigSpecsInternal(display, policy, kOverridePolicy);
+            return setDesiredDisplayModeSpecsInternal(display, policy, kOverridePolicy);
         }
     });
 
     return future.get();
 }
 
-status_t SurfaceFlinger::getDesiredDisplayConfigSpecs(
-        const sp<IBinder>& displayToken, int32_t* outDefaultConfig, bool* outAllowGroupSwitching,
+status_t SurfaceFlinger::getDesiredDisplayModeSpecs(
+        const sp<IBinder>& displayToken, size_t* outDefaultMode, bool* outAllowGroupSwitching,
         float* outPrimaryRefreshRateMin, float* outPrimaryRefreshRateMax,
         float* outAppRequestRefreshRateMin, float* outAppRequestRefreshRateMax) {
     ATRACE_CALL();
 
-    if (!displayToken || !outDefaultConfig || !outPrimaryRefreshRateMin ||
+    if (!displayToken || !outDefaultMode || !outPrimaryRefreshRateMin ||
         !outPrimaryRefreshRateMax || !outAppRequestRefreshRateMin || !outAppRequestRefreshRateMax) {
         return BAD_VALUE;
     }
@@ -6185,7 +6212,7 @@
     if (display->isPrimary()) {
         scheduler::RefreshRateConfigs::Policy policy =
                 mRefreshRateConfigs->getDisplayManagerPolicy();
-        *outDefaultConfig = policy.defaultConfig.value();
+        *outDefaultMode = policy.defaultMode.value();
         *outAllowGroupSwitching = policy.allowGroupSwitching;
         *outPrimaryRefreshRateMin = policy.primaryRange.min.getValue();
         *outPrimaryRefreshRateMax = policy.primaryRange.max.getValue();
@@ -6196,7 +6223,7 @@
         return INVALID_OPERATION;
     } else {
         const auto activeMode = display->getActiveMode();
-        *outDefaultConfig = activeMode->getId().value();
+        *outDefaultMode = activeMode->getId().value();
         *outAllowGroupSwitching = false;
         auto vsyncPeriod = activeMode->getVsyncPeriod();
         *outPrimaryRefreshRateMin = Fps::fromPeriodNsecs(vsyncPeriod).getValue();
@@ -6326,16 +6353,15 @@
             const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
 
             // 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
+            // defaultMode from the display manager policy, we could be setting a new display
+            // manager policy, leaving us using a stale defaultMode. The defaultMode doesn't
             // 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;
+            overridePolicy.defaultMode = mRefreshRateConfigs->getDisplayManagerPolicy().defaultMode;
             overridePolicy.allowGroupSwitching = true;
             constexpr bool kOverridePolicy = true;
-            result = setDesiredDisplayConfigSpecsInternal(display, overridePolicy, kOverridePolicy);
+            result = setDesiredDisplayModeSpecsInternal(display, overridePolicy, kOverridePolicy);
         }
 
         if (result == NO_ERROR) {
@@ -6375,7 +6401,7 @@
         if (mFrameRateFlexibilityTokenCount == 0) {
             const auto display = ON_MAIN_THREAD(getDefaultDisplayDeviceLocked());
             constexpr bool kOverridePolicy = true;
-            status_t result = setDesiredDisplayConfigSpecsInternal(display, {}, kOverridePolicy);
+            status_t result = setDesiredDisplayModeSpecsInternal(display, {}, kOverridePolicy);
             LOG_ALWAYS_FATAL_IF(result < 0, "Failed releasing frame rate flexibility token");
         }
     }));
@@ -6436,6 +6462,25 @@
     return getRenderEngine().getContextPriority();
 }
 
+int SurfaceFlinger::calculateExtraBufferCount(Fps maxSupportedRefreshRate,
+                                              std::chrono::nanoseconds presentLatency) {
+    auto pipelineDepth = presentLatency.count() / maxSupportedRefreshRate.getPeriodNsecs();
+    if (presentLatency.count() % maxSupportedRefreshRate.getPeriodNsecs()) {
+        pipelineDepth++;
+    }
+    return std::max(0ll, pipelineDepth - 2);
+}
+
+status_t SurfaceFlinger::getExtraBufferCount(int* extraBuffers) const {
+    const auto maxSupportedRefreshRate = mRefreshRateConfigs->getSupportedRefreshRateRange().max;
+    const auto vsyncConfig =
+            mVsyncConfiguration->getConfigsForRefreshRate(maxSupportedRefreshRate).late;
+    const auto presentLatency = vsyncConfig.appWorkDuration + vsyncConfig.sfWorkDuration;
+
+    *extraBuffers = calculateExtraBufferCount(maxSupportedRefreshRate, presentLatency);
+    return NO_ERROR;
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index b519dcf..a62d0b9 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -64,7 +64,7 @@
 #include "SurfaceFlingerFactory.h"
 #include "SurfaceTracing.h"
 #include "TracedOrdinal.h"
-#include "TransactionCompletedThread.h"
+#include "TransactionCallbackInvoker.h"
 
 #include <atomic>
 #include <cstdint>
@@ -319,8 +319,8 @@
 
     void removeFromOffscreenLayers(Layer* layer);
 
-    TransactionCompletedThread& getTransactionCompletedThread() {
-        return mTransactionCompletedThread;
+    TransactionCallbackInvoker& getTransactionCallbackInvoker() {
+        return mTransactionCallbackInvoker;
     }
 
     // Converts from a binder handle to a Layer
@@ -345,8 +345,8 @@
     virtual uint32_t setClientStateLocked(
             const FrameTimelineInfo& info, const ComposerState& composerState,
             int64_t desiredPresentTime, bool isAutoTimestamp, int64_t postTime, bool privileged,
-            std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks,
-            int originPid, int originUid) REQUIRES(mStateLock);
+            std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks)
+            REQUIRES(mStateLock);
     virtual void commitTransactionLocked();
 
     // Used internally by computeLayerBounds() to gets the clip rectangle to use for the
@@ -414,12 +414,12 @@
         void traverseInReverseZOrder(const LayerVector::Visitor& visitor) const;
     };
 
-    struct ActiveConfigInfo {
-        DisplayModeId configId;
-        Scheduler::ConfigEvent event = Scheduler::ConfigEvent::None;
+    struct ActiveModeInfo {
+        DisplayModeId modeId;
+        Scheduler::ModeEvent event = Scheduler::ModeEvent::None;
 
-        bool operator!=(const ActiveConfigInfo& other) const {
-            return configId != other.configId || event != other.event;
+        bool operator!=(const ActiveModeInfo& other) const {
+            return modeId != other.modeId || event != other.event;
         }
     };
 
@@ -554,8 +554,8 @@
     status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats) override;
     status_t getDisplayState(const sp<IBinder>& displayToken, ui::DisplayState*) override;
     status_t getDisplayInfo(const sp<IBinder>& displayToken, DisplayInfo*) override;
-    status_t getDisplayConfigs(const sp<IBinder>& displayToken, Vector<DisplayConfig>*) override;
-    int getActiveConfig(const sp<IBinder>& displayToken) override;
+    status_t getDisplayModes(const sp<IBinder>& displayToken, Vector<ui::DisplayMode>*) override;
+    int getActiveDisplayModeId(const sp<IBinder>& displayToken) override;
     status_t getDisplayColorModes(const sp<IBinder>& displayToken, Vector<ui::ColorMode>*) override;
     status_t getDisplayNativePrimaries(const sp<IBinder>& displayToken,
                                        ui::DisplayPrimaries&) override;
@@ -594,17 +594,16 @@
     status_t addRegionSamplingListener(const Rect& samplingArea, const sp<IBinder>& stopLayerHandle,
                                        const sp<IRegionSamplingListener>& listener) override;
     status_t removeRegionSamplingListener(const sp<IRegionSamplingListener>& listener) override;
-    status_t setDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken, int32_t displayModeId,
-                                          bool allowGroupSwitching, float primaryRefreshRateMin,
-                                          float primaryRefreshRateMax,
-                                          float appRequestRefreshRateMin,
-                                          float appRequestRefreshRateMax) override;
-    status_t getDesiredDisplayConfigSpecs(const sp<IBinder>& displayToken,
-                                          int32_t* outDefaultConfig, bool* outAllowGroupSwitching,
-                                          float* outPrimaryRefreshRateMin,
-                                          float* outPrimaryRefreshRateMax,
-                                          float* outAppRequestRefreshRateMin,
-                                          float* outAppRequestRefreshRateMax) override;
+    status_t setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, size_t displayModeId,
+                                        bool allowGroupSwitching, float primaryRefreshRateMin,
+                                        float primaryRefreshRateMax, float appRequestRefreshRateMin,
+                                        float appRequestRefreshRateMax) override;
+    status_t getDesiredDisplayModeSpecs(const sp<IBinder>& displayToken, size_t* outDefaultMode,
+                                        bool* outAllowGroupSwitching,
+                                        float* outPrimaryRefreshRateMin,
+                                        float* outPrimaryRefreshRateMax,
+                                        float* outAppRequestRefreshRateMin,
+                                        float* outAppRequestRefreshRateMax) override;
     status_t getDisplayBrightnessSupport(const sp<IBinder>& displayToken,
                                          bool* outSupport) const override;
     status_t setDisplayBrightness(const sp<IBinder>& displayToken, float brightness) override;
@@ -623,6 +622,8 @@
 
     int getGPUContextPriority() override;
 
+    status_t getExtraBufferCount(int* extraBuffers) const override;
+
     // Implements IBinder::DeathRecipient.
     void binderDied(const wp<IBinder>& who) override;
 
@@ -649,7 +650,7 @@
     // Toggles hardware VSYNC by calling into HWC.
     void setVsyncEnabled(bool) override;
     // Initiates a refresh rate change to be applied on invalidate.
-    void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ConfigEvent) override;
+    void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override;
     // Forces full composition on all displays without resetting the scheduler idle timer.
     void repaintEverythingForHWC() override;
     // Called when kernel idle timer has expired. Used to update the refresh rate overlay.
@@ -677,24 +678,24 @@
 
     // Called on the main thread in response to initializeDisplays()
     void onInitializeDisplays() REQUIRES(mStateLock);
-    // Sets the desired active config bit. It obtains the lock, and sets mDesiredActiveConfig.
-    void setDesiredActiveConfig(const ActiveConfigInfo& info) REQUIRES(mStateLock);
-    status_t setActiveConfig(const sp<IBinder>& displayToken, int id);
-    // Once HWC has returned the present fence, this sets the active config and a new refresh
+    // Sets the desired active mode bit. It obtains the lock, and sets mDesiredActiveMode.
+    void setDesiredActiveMode(const ActiveModeInfo& info) REQUIRES(mStateLock);
+    status_t setActiveMode(const sp<IBinder>& displayToken, int id);
+    // Once HWC has returned the present fence, this sets the active mode and a new refresh
     // rate in SF.
-    void setActiveConfigInternal() REQUIRES(mStateLock);
-    // Calls to setActiveConfig on the main thread if there is a pending config
+    void setActiveModeInternal() REQUIRES(mStateLock);
+    // Calls to setActiveMode on the main thread if there is a pending mode change
     // that needs to be applied.
-    void performSetActiveConfig() REQUIRES(mStateLock);
-    void clearDesiredActiveConfigState() REQUIRES(mStateLock) EXCLUDES(mActiveConfigLock);
-    // Called when active config is no longer is progress
-    void desiredActiveConfigChangeDone() REQUIRES(mStateLock);
+    void performSetActiveMode() REQUIRES(mStateLock);
+    void clearDesiredActiveModeState() REQUIRES(mStateLock) EXCLUDES(mActiveModeLock);
+    // Called when active mode is no longer is progress
+    void desiredActiveModeChangeDone() REQUIRES(mStateLock);
     // Called on the main thread in response to setPowerMode()
     void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
             REQUIRES(mStateLock);
 
-    // Sets the desired display configs.
-    status_t setDesiredDisplayConfigSpecsInternal(
+    // Sets the desired display mode specs.
+    status_t setDesiredDisplayModeSpecsInternal(
             const sp<DisplayDevice>& display,
             const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
             EXCLUDES(mStateLock);
@@ -760,9 +761,11 @@
     uint32_t setTransactionFlags(uint32_t flags, TransactionSchedule);
     void commitTransaction() REQUIRES(mStateLock);
     void commitOffscreenLayers();
-    bool transactionIsReadyToBeApplied(bool isAutoTimestamp, int64_t desiredPresentTime,
-                                       const Vector<ComposerState>& states,
-                                       bool updateTransactionCounters = false);
+    bool transactionIsReadyToBeApplied(
+            bool isAutoTimestamp, int64_t desiredPresentTime, const Vector<ComposerState>& states,
+            bool updateTransactionCounters,
+            std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& pendingBuffers)
+            REQUIRES(mStateLock);
     uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
     uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
             REQUIRES(mStateLock);
@@ -902,6 +905,7 @@
     /*
      * Display management
      */
+    DisplayModes loadSupportedDisplayModes(PhysicalDisplayId) const;
     sp<DisplayDevice> setupNewDisplayDeviceInternal(
             const wp<IBinder>& displayToken,
             std::shared_ptr<compositionengine::Display> compositionDisplay,
@@ -926,9 +930,9 @@
 
     // Sets the refresh rate by switching active configs, if they are available for
     // the desired refresh rate.
-    void changeRefreshRateLocked(const RefreshRate&, Scheduler::ConfigEvent) REQUIRES(mStateLock);
+    void changeRefreshRateLocked(const RefreshRate&, Scheduler::ModeEvent) REQUIRES(mStateLock);
 
-    bool isDisplayConfigAllowed(DisplayModeId configId) const REQUIRES(mStateLock);
+    bool isDisplayModeAllowed(DisplayModeId) const REQUIRES(mStateLock);
 
     // Gets the fence for the previous frame.
     // Must be called on the main thread.
@@ -1044,12 +1048,15 @@
      * Misc
      */
 
-    std::optional<ActiveConfigInfo> getDesiredActiveConfig() EXCLUDES(mActiveConfigLock) {
-        std::lock_guard<std::mutex> lock(mActiveConfigLock);
-        if (mDesiredActiveConfigChanged) return mDesiredActiveConfig;
+    std::optional<ActiveModeInfo> getDesiredActiveMode() EXCLUDES(mActiveModeLock) {
+        std::lock_guard<std::mutex> lock(mActiveModeLock);
+        if (mDesiredActiveModeChanged) return mDesiredActiveMode;
         return std::nullopt;
     }
 
+    static int calculateExtraBufferCount(Fps maxSupportedRefreshRate,
+                                         std::chrono::nanoseconds presentLatency);
+
     sp<StartPropertySetThread> mStartPropertySetThread;
     surfaceflinger::Factory& mFactory;
 
@@ -1158,7 +1165,7 @@
     std::atomic<uint32_t> mHwcFrameMissedCount = 0;
     std::atomic<uint32_t> mGpuFrameMissedCount = 0;
 
-    TransactionCompletedThread mTransactionCompletedThread;
+    TransactionCallbackInvoker mTransactionCallbackInvoker;
 
     // Restrict layers to use two buffers in their bufferqueues.
     bool mLayerTripleBufferingDisabled = false;
@@ -1243,18 +1250,18 @@
     nsecs_t mScheduledPresentTime = 0;
     hal::Vsync mHWCVsyncPendingState = hal::Vsync::DISABLE;
 
-    std::mutex mActiveConfigLock;
-    // This bit is set once we start setting the config. We read from this bit during the
-    // process. If at the end, this bit is different than mDesiredActiveConfig, we restart
+    std::mutex mActiveModeLock;
+    // This bit is set once we start setting the mode. We read from this bit during the
+    // process. If at the end, this bit is different than mDesiredActiveMode, we restart
     // the process.
-    ActiveConfigInfo mUpcomingActiveConfig; // Always read and written on the main thread.
-    // This bit can be set at any point in time when the system wants the new config.
-    ActiveConfigInfo mDesiredActiveConfig GUARDED_BY(mActiveConfigLock);
+    ActiveModeInfo mUpcomingActiveMode; // Always read and written on the main thread.
+    // This bit can be set at any point in time when the system wants the new mode.
+    ActiveModeInfo mDesiredActiveMode GUARDED_BY(mActiveModeLock);
 
     // below flags are set by main thread only
-    TracedOrdinal<bool> mDesiredActiveConfigChanged
-            GUARDED_BY(mActiveConfigLock) = {"DesiredActiveConfigChanged", false};
-    bool mSetActiveConfigPending = false;
+    TracedOrdinal<bool> mDesiredActiveModeChanged
+            GUARDED_BY(mActiveModeLock) = {"DesiredActiveModeChanged", false};
+    bool mSetActiveModePending = false;
 
     bool mLumaSampling = true;
     sp<RegionSamplingThread> mRegionSamplingThread;
@@ -1278,8 +1285,8 @@
     void enableRefreshRateOverlay(bool enable);
     std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay GUARDED_BY(mStateLock);
 
-    // Flag used to set override allowed display configs from backdoor
-    bool mDebugDisplayConfigSetByBackdoor = false;
+    // Flag used to set override desired display mode from backdoor
+    bool mDebugDisplayModeSetByBackdoor = false;
 
     // A set of layers that have no parent so they are not drawn on screen.
     // Should only be accessed by the main thread.
diff --git a/services/surfaceflinger/TransactionCallbackInvoker.cpp b/services/surfaceflinger/TransactionCallbackInvoker.cpp
new file mode 100644
index 0000000..a78510e
--- /dev/null
+++ b/services/surfaceflinger/TransactionCallbackInvoker.cpp
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
+//#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "TransactionCallbackInvoker"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "TransactionCallbackInvoker.h"
+
+#include <cinttypes>
+
+#include <binder/IInterface.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+// Returns 0 if they are equal
+//         <0 if the first id that doesn't match is lower in c2 or all ids match but c2 is shorter
+//         >0 if the first id that doesn't match is greater in c2 or all ids match but c2 is longer
+//
+// See CallbackIdsHash for a explaniation of why this works
+static int compareCallbackIds(const std::vector<CallbackId>& c1,
+                              const std::vector<CallbackId>& c2) {
+    if (c1.empty()) {
+        return !c2.empty();
+    }
+    return c1.front() - c2.front();
+}
+
+TransactionCallbackInvoker::~TransactionCallbackInvoker() {
+    {
+        std::lock_guard lock(mMutex);
+        for (const auto& [listener, transactionStats] : mCompletedTransactions) {
+            listener->unlinkToDeath(mDeathRecipient);
+        }
+    }
+}
+
+status_t TransactionCallbackInvoker::startRegistration(const ListenerCallbacks& listenerCallbacks) {
+    std::lock_guard lock(mMutex);
+
+    auto [itr, inserted] = mRegisteringTransactions.insert(listenerCallbacks);
+    auto& [listener, callbackIds] = listenerCallbacks;
+
+    if (inserted) {
+        if (mCompletedTransactions.count(listener) == 0) {
+            status_t err = listener->linkToDeath(mDeathRecipient);
+            if (err != NO_ERROR) {
+                ALOGE("cannot add callback because linkToDeath failed, err: %d", err);
+                return err;
+            }
+        }
+        auto& transactionStatsDeque = mCompletedTransactions[listener];
+        transactionStatsDeque.emplace_back(callbackIds);
+    }
+
+    return NO_ERROR;
+}
+
+status_t TransactionCallbackInvoker::endRegistration(const ListenerCallbacks& listenerCallbacks) {
+    std::lock_guard lock(mMutex);
+
+    auto itr = mRegisteringTransactions.find(listenerCallbacks);
+    if (itr == mRegisteringTransactions.end()) {
+        ALOGE("cannot end a registration that does not exist");
+        return BAD_VALUE;
+    }
+
+    mRegisteringTransactions.erase(itr);
+
+    return NO_ERROR;
+}
+
+bool TransactionCallbackInvoker::isRegisteringTransaction(
+        const sp<IBinder>& transactionListener, const std::vector<CallbackId>& callbackIds) {
+    ListenerCallbacks listenerCallbacks(transactionListener, callbackIds);
+
+    auto itr = mRegisteringTransactions.find(listenerCallbacks);
+    return itr != mRegisteringTransactions.end();
+}
+
+status_t TransactionCallbackInvoker::registerPendingCallbackHandle(
+        const sp<CallbackHandle>& handle) {
+    std::lock_guard lock(mMutex);
+
+    // If we can't find the transaction stats something has gone wrong. The client should call
+    // startRegistration before trying to register a pending callback handle.
+    TransactionStats* transactionStats;
+    status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
+    if (err != NO_ERROR) {
+        ALOGE("cannot find transaction stats");
+        return err;
+    }
+
+    mPendingTransactions[handle->listener][handle->callbackIds]++;
+    return NO_ERROR;
+}
+
+status_t TransactionCallbackInvoker::finalizePendingCallbackHandles(
+        const std::deque<sp<CallbackHandle>>& handles, const std::vector<JankData>& jankData) {
+    if (handles.empty()) {
+        return NO_ERROR;
+    }
+    std::lock_guard lock(mMutex);
+
+    for (const auto& handle : handles) {
+        auto listener = mPendingTransactions.find(handle->listener);
+        if (listener != mPendingTransactions.end()) {
+            auto& pendingCallbacks = listener->second;
+            auto pendingCallback = pendingCallbacks.find(handle->callbackIds);
+
+            if (pendingCallback != pendingCallbacks.end()) {
+                auto& pendingCount = pendingCallback->second;
+
+                // Decrease the pending count for this listener
+                if (--pendingCount == 0) {
+                    pendingCallbacks.erase(pendingCallback);
+                }
+            } else {
+                ALOGW("there are more latched callbacks than there were registered callbacks");
+            }
+            if (listener->second.size() == 0) {
+                mPendingTransactions.erase(listener);
+            }
+        } else {
+            ALOGW("cannot find listener in mPendingTransactions");
+        }
+
+        status_t err = addCallbackHandle(handle, jankData);
+        if (err != NO_ERROR) {
+            ALOGE("could not add callback handle");
+            return err;
+        }
+    }
+
+    return NO_ERROR;
+}
+
+status_t TransactionCallbackInvoker::registerUnpresentedCallbackHandle(
+        const sp<CallbackHandle>& handle) {
+    std::lock_guard lock(mMutex);
+
+    return addCallbackHandle(handle, std::vector<JankData>());
+}
+
+status_t TransactionCallbackInvoker::findTransactionStats(
+        const sp<IBinder>& listener, const std::vector<CallbackId>& callbackIds,
+        TransactionStats** outTransactionStats) {
+    auto& transactionStatsDeque = mCompletedTransactions[listener];
+
+    // Search back to front because the most recent transactions are at the back of the deque
+    auto itr = transactionStatsDeque.rbegin();
+    for (; itr != transactionStatsDeque.rend(); itr++) {
+        if (compareCallbackIds(itr->callbackIds, callbackIds) == 0) {
+            *outTransactionStats = &(*itr);
+            return NO_ERROR;
+        }
+    }
+
+    ALOGE("could not find transaction stats");
+    return BAD_VALUE;
+}
+
+status_t TransactionCallbackInvoker::addCallbackHandle(const sp<CallbackHandle>& handle,
+        const std::vector<JankData>& jankData) {
+    // If we can't find the transaction stats something has gone wrong. The client should call
+    // startRegistration before trying to add a callback handle.
+    TransactionStats* transactionStats;
+    status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    transactionStats->latchTime = handle->latchTime;
+    // If the layer has already been destroyed, don't add the SurfaceControl to the callback.
+    // The client side keeps a sp<> to the SurfaceControl so if the SurfaceControl has been
+    // destroyed the client side is dead and there won't be anyone to send the callback to.
+    sp<IBinder> surfaceControl = handle->surfaceControl.promote();
+    if (surfaceControl) {
+        FrameEventHistoryStats eventStats(handle->frameNumber,
+                                          handle->gpuCompositionDoneFence->getSnapshot().fence,
+                                          handle->compositorTiming, handle->refreshStartTime,
+                                          handle->dequeueReadyTime);
+        transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
+                                                    handle->previousReleaseFence,
+                                                    handle->transformHint, eventStats, jankData);
+    }
+    return NO_ERROR;
+}
+
+void TransactionCallbackInvoker::addPresentFence(const sp<Fence>& presentFence) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mPresentFence = presentFence;
+}
+
+void TransactionCallbackInvoker::sendCallbacks() {
+    std::lock_guard lock(mMutex);
+
+    // For each listener
+    auto completedTransactionsItr = mCompletedTransactions.begin();
+    while (completedTransactionsItr != mCompletedTransactions.end()) {
+        auto& [listener, transactionStatsDeque] = *completedTransactionsItr;
+        ListenerStats listenerStats;
+        listenerStats.listener = listener;
+
+        // For each transaction
+        auto transactionStatsItr = transactionStatsDeque.begin();
+        while (transactionStatsItr != transactionStatsDeque.end()) {
+            auto& transactionStats = *transactionStatsItr;
+
+            // If this transaction is still registering, it is not safe to send a callback
+            // because there could be surface controls that haven't been added to
+            // transaction stats or mPendingTransactions.
+            if (isRegisteringTransaction(listener, transactionStats.callbackIds)) {
+                break;
+            }
+
+            // If we are still waiting on the callback handles for this transaction, stop
+            // here because all transaction callbacks for the same listener must come in order
+            auto pendingTransactions = mPendingTransactions.find(listener);
+            if (pendingTransactions != mPendingTransactions.end() &&
+                pendingTransactions->second.count(transactionStats.callbackIds) != 0) {
+                break;
+            }
+
+            // If the transaction has been latched
+            if (transactionStats.latchTime >= 0) {
+                if (!mPresentFence) {
+                    break;
+                }
+                transactionStats.presentFence = mPresentFence;
+            }
+
+            // Remove the transaction from completed to the callback
+            listenerStats.transactionStats.push_back(std::move(transactionStats));
+            transactionStatsItr = transactionStatsDeque.erase(transactionStatsItr);
+        }
+        // If the listener has completed transactions
+        if (!listenerStats.transactionStats.empty()) {
+            // If the listener is still alive
+            if (listener->isBinderAlive()) {
+                // Send callback.  The listener stored in listenerStats
+                // comes from the cross-process setTransactionState call to
+                // SF.  This MUST be an ITransactionCompletedListener.  We
+                // keep it as an IBinder due to consistency reasons: if we
+                // interface_cast at the IPC boundary when reading a Parcel,
+                // we get pointers that compare unequal in the SF process.
+                interface_cast<ITransactionCompletedListener>(listenerStats.listener)
+                        ->onTransactionCompleted(listenerStats);
+                if (transactionStatsDeque.empty()) {
+                    listener->unlinkToDeath(mDeathRecipient);
+                    completedTransactionsItr =
+                            mCompletedTransactions.erase(completedTransactionsItr);
+                } else {
+                    completedTransactionsItr++;
+                }
+            } else {
+                completedTransactionsItr =
+                        mCompletedTransactions.erase(completedTransactionsItr);
+            }
+        } else {
+            completedTransactionsItr++;
+        }
+    }
+
+    if (mPresentFence) {
+        mPresentFence.clear();
+    }
+}
+
+// -----------------------------------------------------------------------
+
+CallbackHandle::CallbackHandle(const sp<IBinder>& transactionListener,
+                               const std::vector<CallbackId>& ids, const sp<IBinder>& sc)
+      : listener(transactionListener), callbackIds(ids), surfaceControl(sc) {}
+
+} // namespace android
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCallbackInvoker.h
similarity index 88%
rename from services/surfaceflinger/TransactionCompletedThread.h
rename to services/surfaceflinger/TransactionCallbackInvoker.h
index c4ba7e4..a240c82 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCallbackInvoker.h
@@ -52,11 +52,9 @@
     uint64_t frameNumber = 0;
 };
 
-class TransactionCompletedThread {
+class TransactionCallbackInvoker {
 public:
-    ~TransactionCompletedThread();
-
-    void run();
+    ~TransactionCallbackInvoker();
 
     // Adds listener and callbackIds in case there are no SurfaceControls that are supposed
     // to be included in the callback. This functions should be call before attempting to register
@@ -66,13 +64,13 @@
     // It is safe to send a callback if the Transaction doesn't have any Pending callback handles.
     status_t endRegistration(const ListenerCallbacks& listenerCallbacks);
 
-    // Informs the TransactionCompletedThread that there is a Transaction with a CallbackHandle
+    // Informs the TransactionCallbackInvoker that there is a Transaction with a CallbackHandle
     // that needs to be latched and presented this frame. This function should be called once the
-    // layer has received the CallbackHandle so the TransactionCompletedThread knows not to send
+    // layer has received the CallbackHandle so the TransactionCallbackInvoker knows not to send
     // a callback for that Listener/Transaction pair until that CallbackHandle has been latched and
     // presented.
     status_t registerPendingCallbackHandle(const sp<CallbackHandle>& handle);
-    // Notifies the TransactionCompletedThread that a pending CallbackHandle has been presented.
+    // Notifies the TransactionCallbackInvoker that a pending CallbackHandle has been presented.
     status_t finalizePendingCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
                                             const std::vector<JankData>& jankData);
 
@@ -85,7 +83,6 @@
     void sendCallbacks();
 
 private:
-    void threadMain();
 
     bool isRegisteringTransaction(const sp<IBinder>& transactionListener,
                                   const std::vector<CallbackId>& callbackIds) REQUIRES(mMutex);
@@ -97,7 +94,7 @@
     status_t addCallbackHandle(const sp<CallbackHandle>& handle,
                                const std::vector<JankData>& jankData) REQUIRES(mMutex);
 
-    class ThreadDeathRecipient : public IBinder::DeathRecipient {
+    class CallbackDeathRecipient : public IBinder::DeathRecipient {
     public:
         // This function is a no-op. isBinderAlive needs a linked DeathRecipient to work.
         // Death recipients needs a binderDied function.
@@ -106,12 +103,8 @@
         // sendObituary is only called if linkToDeath was called with a DeathRecipient.)
         void binderDied(const wp<IBinder>& /*who*/) override {}
     };
-    sp<ThreadDeathRecipient> mDeathRecipient;
-
-    // Protects the creation and destruction of mThread
-    std::mutex mThreadMutex;
-
-    std::thread mThread GUARDED_BY(mThreadMutex);
+    sp<CallbackDeathRecipient> mDeathRecipient =
+        new CallbackDeathRecipient();
 
     std::mutex mMutex;
     std::condition_variable_any mConditionVariable;
@@ -128,9 +121,6 @@
     std::unordered_map<sp<IBinder>, std::deque<TransactionStats>, IListenerHash>
             mCompletedTransactions GUARDED_BY(mMutex);
 
-    bool mRunning GUARDED_BY(mMutex) = false;
-    bool mKeepRunning GUARDED_BY(mMutex) = true;
-
     sp<Fence> mPresentFence GUARDED_BY(mMutex);
 };
 
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
deleted file mode 100644
index 1797af4..0000000
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ /dev/null
@@ -1,372 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wconversion"
-
-//#define LOG_NDEBUG 0
-#undef LOG_TAG
-#define LOG_TAG "TransactionCompletedThread"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "TransactionCompletedThread.h"
-
-#include <cinttypes>
-
-#include <binder/IInterface.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-// Returns 0 if they are equal
-//         <0 if the first id that doesn't match is lower in c2 or all ids match but c2 is shorter
-//         >0 if the first id that doesn't match is greater in c2 or all ids match but c2 is longer
-//
-// See CallbackIdsHash for a explaniation of why this works
-static int compareCallbackIds(const std::vector<CallbackId>& c1,
-                              const std::vector<CallbackId>& c2) {
-    if (c1.empty()) {
-        return !c2.empty();
-    }
-    return c1.front() - c2.front();
-}
-
-TransactionCompletedThread::~TransactionCompletedThread() {
-    std::lock_guard lockThread(mThreadMutex);
-
-    {
-        std::lock_guard lock(mMutex);
-        mKeepRunning = false;
-        mConditionVariable.notify_all();
-    }
-
-    if (mThread.joinable()) {
-        mThread.join();
-    }
-
-    {
-        std::lock_guard lock(mMutex);
-        for (const auto& [listener, transactionStats] : mCompletedTransactions) {
-            listener->unlinkToDeath(mDeathRecipient);
-        }
-    }
-}
-
-void TransactionCompletedThread::run() {
-    std::lock_guard lock(mMutex);
-    if (mRunning || !mKeepRunning) {
-        return;
-    }
-    mDeathRecipient = new ThreadDeathRecipient();
-    mRunning = true;
-
-    std::lock_guard lockThread(mThreadMutex);
-    mThread = std::thread(&TransactionCompletedThread::threadMain, this);
-}
-
-status_t TransactionCompletedThread::startRegistration(const ListenerCallbacks& listenerCallbacks) {
-    // begin running if not already running
-    run();
-    std::lock_guard lock(mMutex);
-    if (!mRunning) {
-        ALOGE("cannot add callback because the callback thread isn't running");
-        return BAD_VALUE;
-    }
-
-    auto [itr, inserted] = mRegisteringTransactions.insert(listenerCallbacks);
-    auto& [listener, callbackIds] = listenerCallbacks;
-
-    if (inserted) {
-        if (mCompletedTransactions.count(listener) == 0) {
-            status_t err = listener->linkToDeath(mDeathRecipient);
-            if (err != NO_ERROR) {
-                ALOGE("cannot add callback because linkToDeath failed, err: %d", err);
-                return err;
-            }
-        }
-        auto& transactionStatsDeque = mCompletedTransactions[listener];
-        transactionStatsDeque.emplace_back(callbackIds);
-    }
-
-    return NO_ERROR;
-}
-
-status_t TransactionCompletedThread::endRegistration(const ListenerCallbacks& listenerCallbacks) {
-    std::lock_guard lock(mMutex);
-    if (!mRunning) {
-        ALOGE("cannot add callback because the callback thread isn't running");
-        return BAD_VALUE;
-    }
-
-    auto itr = mRegisteringTransactions.find(listenerCallbacks);
-    if (itr == mRegisteringTransactions.end()) {
-        ALOGE("cannot end a registration that does not exist");
-        return BAD_VALUE;
-    }
-
-    mRegisteringTransactions.erase(itr);
-
-    return NO_ERROR;
-}
-
-bool TransactionCompletedThread::isRegisteringTransaction(
-        const sp<IBinder>& transactionListener, const std::vector<CallbackId>& callbackIds) {
-    ListenerCallbacks listenerCallbacks(transactionListener, callbackIds);
-
-    auto itr = mRegisteringTransactions.find(listenerCallbacks);
-    return itr != mRegisteringTransactions.end();
-}
-
-status_t TransactionCompletedThread::registerPendingCallbackHandle(
-        const sp<CallbackHandle>& handle) {
-    std::lock_guard lock(mMutex);
-    if (!mRunning) {
-        ALOGE("cannot register callback handle because the callback thread isn't running");
-        return BAD_VALUE;
-    }
-
-    // If we can't find the transaction stats something has gone wrong. The client should call
-    // startRegistration before trying to register a pending callback handle.
-    TransactionStats* transactionStats;
-    status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
-    if (err != NO_ERROR) {
-        ALOGE("cannot find transaction stats");
-        return err;
-    }
-
-    mPendingTransactions[handle->listener][handle->callbackIds]++;
-    return NO_ERROR;
-}
-
-status_t TransactionCompletedThread::finalizePendingCallbackHandles(
-        const std::deque<sp<CallbackHandle>>& handles, const std::vector<JankData>& jankData) {
-    if (handles.empty()) {
-        return NO_ERROR;
-    }
-    std::lock_guard lock(mMutex);
-    if (!mRunning) {
-        ALOGE("cannot add presented callback handle because the callback thread isn't running");
-        return BAD_VALUE;
-    }
-
-    for (const auto& handle : handles) {
-        auto listener = mPendingTransactions.find(handle->listener);
-        if (listener != mPendingTransactions.end()) {
-            auto& pendingCallbacks = listener->second;
-            auto pendingCallback = pendingCallbacks.find(handle->callbackIds);
-
-            if (pendingCallback != pendingCallbacks.end()) {
-                auto& pendingCount = pendingCallback->second;
-
-                // Decrease the pending count for this listener
-                if (--pendingCount == 0) {
-                    pendingCallbacks.erase(pendingCallback);
-                }
-            } else {
-                ALOGW("there are more latched callbacks than there were registered callbacks");
-            }
-            if (listener->second.size() == 0) {
-                mPendingTransactions.erase(listener);
-            }
-        } else {
-            ALOGW("cannot find listener in mPendingTransactions");
-        }
-
-        status_t err = addCallbackHandle(handle, jankData);
-        if (err != NO_ERROR) {
-            ALOGE("could not add callback handle");
-            return err;
-        }
-    }
-
-    return NO_ERROR;
-}
-
-status_t TransactionCompletedThread::registerUnpresentedCallbackHandle(
-        const sp<CallbackHandle>& handle) {
-    std::lock_guard lock(mMutex);
-    if (!mRunning) {
-        ALOGE("cannot add unpresented callback handle because the callback thread isn't running");
-        return BAD_VALUE;
-    }
-
-    return addCallbackHandle(handle, std::vector<JankData>());
-}
-
-status_t TransactionCompletedThread::findTransactionStats(
-        const sp<IBinder>& listener, const std::vector<CallbackId>& callbackIds,
-        TransactionStats** outTransactionStats) {
-    auto& transactionStatsDeque = mCompletedTransactions[listener];
-
-    // Search back to front because the most recent transactions are at the back of the deque
-    auto itr = transactionStatsDeque.rbegin();
-    for (; itr != transactionStatsDeque.rend(); itr++) {
-        if (compareCallbackIds(itr->callbackIds, callbackIds) == 0) {
-            *outTransactionStats = &(*itr);
-            return NO_ERROR;
-        }
-    }
-
-    ALOGE("could not find transaction stats");
-    return BAD_VALUE;
-}
-
-status_t TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle,
-        const std::vector<JankData>& jankData) {
-    // If we can't find the transaction stats something has gone wrong. The client should call
-    // startRegistration before trying to add a callback handle.
-    TransactionStats* transactionStats;
-    status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    transactionStats->latchTime = handle->latchTime;
-    // If the layer has already been destroyed, don't add the SurfaceControl to the callback.
-    // The client side keeps a sp<> to the SurfaceControl so if the SurfaceControl has been
-    // destroyed the client side is dead and there won't be anyone to send the callback to.
-    sp<IBinder> surfaceControl = handle->surfaceControl.promote();
-    if (surfaceControl) {
-        FrameEventHistoryStats eventStats(handle->frameNumber,
-                                          handle->gpuCompositionDoneFence->getSnapshot().fence,
-                                          handle->compositorTiming, handle->refreshStartTime,
-                                          handle->dequeueReadyTime);
-        transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
-                                                    handle->previousReleaseFence,
-                                                    handle->transformHint, eventStats, jankData);
-    }
-    return NO_ERROR;
-}
-
-void TransactionCompletedThread::addPresentFence(const sp<Fence>& presentFence) {
-    std::lock_guard<std::mutex> lock(mMutex);
-    mPresentFence = presentFence;
-}
-
-void TransactionCompletedThread::sendCallbacks() {
-    std::lock_guard lock(mMutex);
-    if (mRunning) {
-        mConditionVariable.notify_all();
-    }
-}
-
-void TransactionCompletedThread::threadMain() {
-    std::lock_guard lock(mMutex);
-
-    while (mKeepRunning) {
-        mConditionVariable.wait(mMutex);
-        std::vector<ListenerStats> completedListenerStats;
-
-        // For each listener
-        auto completedTransactionsItr = mCompletedTransactions.begin();
-        while (completedTransactionsItr != mCompletedTransactions.end()) {
-            auto& [listener, transactionStatsDeque] = *completedTransactionsItr;
-            ListenerStats listenerStats;
-            listenerStats.listener = listener;
-
-            // For each transaction
-            auto transactionStatsItr = transactionStatsDeque.begin();
-            while (transactionStatsItr != transactionStatsDeque.end()) {
-                auto& transactionStats = *transactionStatsItr;
-
-                // If this transaction is still registering, it is not safe to send a callback
-                // because there could be surface controls that haven't been added to
-                // transaction stats or mPendingTransactions.
-                if (isRegisteringTransaction(listener, transactionStats.callbackIds)) {
-                    break;
-                }
-
-                // If we are still waiting on the callback handles for this transaction, stop
-                // here because all transaction callbacks for the same listener must come in order
-                auto pendingTransactions = mPendingTransactions.find(listener);
-                if (pendingTransactions != mPendingTransactions.end() &&
-                    pendingTransactions->second.count(transactionStats.callbackIds) != 0) {
-                    break;
-                }
-
-                // If the transaction has been latched
-                if (transactionStats.latchTime >= 0) {
-                    if (!mPresentFence) {
-                        break;
-                    }
-                    transactionStats.presentFence = mPresentFence;
-                }
-
-                // Remove the transaction from completed to the callback
-                listenerStats.transactionStats.push_back(std::move(transactionStats));
-                transactionStatsItr = transactionStatsDeque.erase(transactionStatsItr);
-            }
-            // If the listener has completed transactions
-            if (!listenerStats.transactionStats.empty()) {
-                // If the listener is still alive
-                if (listener->isBinderAlive()) {
-                    // Send callback.  The listener stored in listenerStats
-                    // comes from the cross-process setTransactionState call to
-                    // SF.  This MUST be an ITransactionCompletedListener.  We
-                    // keep it as an IBinder due to consistency reasons: if we
-                    // interface_cast at the IPC boundary when reading a Parcel,
-                    // we get pointers that compare unequal in the SF process.
-                    interface_cast<ITransactionCompletedListener>(listenerStats.listener)
-                            ->onTransactionCompleted(listenerStats);
-                    if (transactionStatsDeque.empty()) {
-                        listener->unlinkToDeath(mDeathRecipient);
-                        completedTransactionsItr =
-                                mCompletedTransactions.erase(completedTransactionsItr);
-                    } else {
-                        completedTransactionsItr++;
-                    }
-                } else {
-                    completedTransactionsItr =
-                            mCompletedTransactions.erase(completedTransactionsItr);
-                }
-            } else {
-                completedTransactionsItr++;
-            }
-
-            completedListenerStats.push_back(std::move(listenerStats));
-        }
-
-        if (mPresentFence) {
-            mPresentFence.clear();
-        }
-
-        // If everyone else has dropped their reference to a layer and its listener is dead,
-        // we are about to cause the layer to be deleted. If this happens at the wrong time and
-        // we are holding mMutex, we will cause a deadlock.
-        //
-        // The deadlock happens because this thread is holding on to mMutex and when we delete
-        // the layer, it grabs SF's mStateLock. A different SF binder thread grabs mStateLock,
-        // then call's TransactionCompletedThread::run() which tries to grab mMutex.
-        //
-        // To avoid this deadlock, we need to unlock mMutex when dropping our last reference to
-        // to the layer.
-        mMutex.unlock();
-        completedListenerStats.clear();
-        mMutex.lock();
-    }
-}
-
-// -----------------------------------------------------------------------
-
-CallbackHandle::CallbackHandle(const sp<IBinder>& transactionListener,
-                               const std::vector<CallbackId>& ids, const sp<IBinder>& sc)
-      : listener(transactionListener), callbackIds(ids), surfaceControl(sc) {}
-
-} // 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/Android.bp b/services/surfaceflinger/tests/Android.bp
index cfaf229..8142aad 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -49,7 +49,7 @@
         "android.hardware.graphics.composer@2.1",
     ],
     shared_libs: [
-        "android.hardware.graphics.common-unstable-ndk_platform",
+        "android.hardware.graphics.common-V2-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 9302463..53e37d8 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -25,7 +25,7 @@
 #include <gui/SurfaceComposerClient.h>
 #include <private/android_filesystem_config.h>
 #include <private/gui/ComposerService.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 #include <utils/String8.h>
 #include <functional>
 #include "utils/ScreenshotUtils.h"
@@ -81,14 +81,13 @@
         mDisplay = SurfaceComposerClient::getInternalDisplayToken();
         ASSERT_FALSE(mDisplay == nullptr);
 
-        DisplayConfig config;
-        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplay, &config));
+        ui::DisplayMode mode;
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(mDisplay, &mode));
 
         // Background surface
-        mBGSurfaceControl =
-                mComposerClient->createSurface(SURFACE_NAME, config.resolution.getWidth(),
-                                               config.resolution.getHeight(),
-                                               PIXEL_FORMAT_RGBA_8888, 0);
+        mBGSurfaceControl = mComposerClient->createSurface(SURFACE_NAME, mode.resolution.getWidth(),
+                                                           mode.resolution.getHeight(),
+                                                           PIXEL_FORMAT_RGBA_8888, 0);
         ASSERT_TRUE(mBGSurfaceControl != nullptr);
         ASSERT_TRUE(mBGSurfaceControl->isValid());
 
@@ -185,13 +184,13 @@
     const auto display = SurfaceComposerClient::getInternalDisplayToken();
     ASSERT_TRUE(display != nullptr);
 
-    DisplayConfig config;
-    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+    ui::DisplayMode mode;
+    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
 
-    Vector<DisplayConfig> configs;
-    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
+    Vector<ui::DisplayMode> modes;
+    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes));
 
-    ASSERT_TRUE(SurfaceComposerClient::getActiveConfig(display) >= 0);
+    ASSERT_TRUE(SurfaceComposerClient::getActiveDisplayModeId(display) >= 0);
 
     ASSERT_NE(static_cast<ui::ColorMode>(BAD_VALUE),
               SurfaceComposerClient::getActiveColorMode(display));
@@ -217,25 +216,23 @@
 
 TEST_F(CredentialsTest, SetDesiredDisplayConfigsTest) {
     const auto display = SurfaceComposerClient::getInternalDisplayToken();
-    int32_t defaultConfig;
+    size_t defaultMode;
     bool allowGroupSwitching;
     float primaryFpsMin;
     float primaryFpsMax;
     float appRequestFpsMin;
     float appRequestFpsMax;
     status_t res =
-            SurfaceComposerClient::getDesiredDisplayConfigSpecs(display, &defaultConfig,
-                                                                &allowGroupSwitching,
-                                                                &primaryFpsMin, &primaryFpsMax,
-                                                                &appRequestFpsMin,
-                                                                &appRequestFpsMax);
+            SurfaceComposerClient::getDesiredDisplayModeSpecs(display, &defaultMode,
+                                                              &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);
+        return SurfaceComposerClient::setDesiredDisplayModeSpecs(display, defaultMode,
+                                                                 allowGroupSwitching, primaryFpsMin,
+                                                                 primaryFpsMax, appRequestFpsMin,
+                                                                 appRequestFpsMax);
     };
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
 }
diff --git a/services/surfaceflinger/tests/DisplayConfigs_test.cpp b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
index 55b3173..9f025a6 100644
--- a/services/surfaceflinger/tests/DisplayConfigs_test.cpp
+++ b/services/surfaceflinger/tests/DisplayConfigs_test.cpp
@@ -22,7 +22,7 @@
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 #include <private/gui/ComposerService.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 #include <utils/Errors.h>
 #include <utils/Vector.h>
 
@@ -38,7 +38,7 @@
  */
 class RefreshRateRangeTest : public ::testing::Test {
 private:
-    int32_t initialDefaultConfig;
+    size_t initialDefaultMode;
     bool initialAllowGroupSwitching;
     float initialPrimaryMin;
     float initialPrimaryMax;
@@ -49,25 +49,24 @@
     void SetUp() override {
         mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
         status_t res =
-                SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken,
-                                                                    &initialDefaultConfig,
-                                                                    &initialAllowGroupSwitching,
-                                                                    &initialPrimaryMin,
-                                                                    &initialPrimaryMax,
-                                                                    &initialAppRequestMin,
-                                                                    &initialAppRequestMax);
+                SurfaceComposerClient::getDesiredDisplayModeSpecs(mDisplayToken,
+                                                                  &initialDefaultMode,
+                                                                  &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);
+                SurfaceComposerClient::setDesiredDisplayModeSpecs(mDisplayToken, initialDefaultMode,
+                                                                  initialAllowGroupSwitching,
+                                                                  initialPrimaryMin,
+                                                                  initialPrimaryMax,
+                                                                  initialAppRequestMin,
+                                                                  initialAppRequestMax);
         ASSERT_EQ(res, NO_ERROR);
     }
 
@@ -77,60 +76,59 @@
 };
 
 TEST_F(RefreshRateRangeTest, setAllConfigs) {
-    Vector<DisplayConfig> configs;
-    status_t res = SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &configs);
+    Vector<ui::DisplayMode> modes;
+    status_t res = SurfaceComposerClient::getDisplayModes(mDisplayToken, &modes);
     ASSERT_EQ(res, NO_ERROR);
-    ASSERT_GT(configs.size(), 0);
+    ASSERT_GT(modes.size(), 0);
 
-    for (size_t i = 0; i < configs.size(); i++) {
-        res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken,
-                                                                  static_cast<int32_t>(i), false,
-                                                                  configs[i].refreshRate,
-                                                                  configs[i].refreshRate,
-                                                                  configs[i].refreshRate,
-                                                                  configs[i].refreshRate);
+    for (size_t i = 0; i < modes.size(); i++) {
+        res = SurfaceComposerClient::setDesiredDisplayModeSpecs(mDisplayToken, i, false,
+                                                                modes[i].refreshRate,
+                                                                modes[i].refreshRate,
+                                                                modes[i].refreshRate,
+                                                                modes[i].refreshRate);
         ASSERT_EQ(res, NO_ERROR);
 
-        int defaultConfig;
+        size_t defaultConfig;
         bool allowGroupSwitching;
         float primaryRefreshRateMin;
         float primaryRefreshRateMax;
         float appRequestRefreshRateMin;
         float appRequestRefreshRateMax;
-        res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
-                                                                  &allowGroupSwitching,
-                                                                  &primaryRefreshRateMin,
-                                                                  &primaryRefreshRateMax,
-                                                                  &appRequestRefreshRateMin,
-                                                                  &appRequestRefreshRateMax);
+        res = SurfaceComposerClient::getDesiredDisplayModeSpecs(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);
+        ASSERT_EQ(primaryRefreshRateMin, modes[i].refreshRate);
+        ASSERT_EQ(primaryRefreshRateMax, modes[i].refreshRate);
+        ASSERT_EQ(appRequestRefreshRateMin, modes[i].refreshRate);
+        ASSERT_EQ(appRequestRefreshRateMax, modes[i].refreshRate);
     }
 }
 
 void RefreshRateRangeTest::testSetAllowGroupSwitching(bool allowGroupSwitching) {
-    status_t res = SurfaceComposerClient::setDesiredDisplayConfigSpecs(mDisplayToken, 0,
-                                                                       allowGroupSwitching, 0.f,
-                                                                       90.f, 0.f, 90.f);
+    status_t res =
+            SurfaceComposerClient::setDesiredDisplayModeSpecs(mDisplayToken, 0, allowGroupSwitching,
+                                                              0.f, 90.f, 0.f, 90.f);
     ASSERT_EQ(res, NO_ERROR);
-    int defaultConfig;
+    size_t defaultConfig;
     bool newAllowGroupSwitching;
     float primaryRefreshRateMin;
     float primaryRefreshRateMax;
     float appRequestRefreshRateMin;
     float appRequestRefreshRateMax;
 
-    res = SurfaceComposerClient::getDesiredDisplayConfigSpecs(mDisplayToken, &defaultConfig,
-                                                              &newAllowGroupSwitching,
-                                                              &primaryRefreshRateMin,
-                                                              &primaryRefreshRateMax,
-                                                              &appRequestRefreshRateMin,
-                                                              &appRequestRefreshRateMax);
+    res = SurfaceComposerClient::getDesiredDisplayModeSpecs(mDisplayToken, &defaultConfig,
+                                                            &newAllowGroupSwitching,
+                                                            &primaryRefreshRateMin,
+                                                            &primaryRefreshRateMax,
+                                                            &appRequestRefreshRateMin,
+                                                            &appRequestRefreshRateMax);
     ASSERT_EQ(res, NO_ERROR);
     ASSERT_EQ(defaultConfig, 0);
     ASSERT_EQ(newAllowGroupSwitching, allowGroupSwitching);
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
index 4023c66..a8647c3 100644
--- a/services/surfaceflinger/tests/IPC_test.cpp
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -23,7 +23,7 @@
 #include <gui/LayerState.h>
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 #include <utils/String8.h>
 
 #include <limits>
@@ -227,10 +227,10 @@
         ASSERT_EQ(NO_ERROR, mClient->initCheck());
 
         mPrimaryDisplay = mClient->getInternalDisplayToken();
-        DisplayConfig config;
-        mClient->getActiveDisplayConfig(mPrimaryDisplay, &config);
-        mDisplayWidth = config.resolution.getWidth();
-        mDisplayHeight = config.resolution.getHeight();
+        ui::DisplayMode mode;
+        mClient->getActiveDisplayMode(mPrimaryDisplay, &mode);
+        mDisplayWidth = mode.resolution.getWidth();
+        mDisplayHeight = mode.resolution.getHeight();
 
         Transaction setupTransaction;
         setupTransaction.setDisplayLayerStack(mPrimaryDisplay, 0);
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
index 6758518..eba2c25 100644
--- a/services/surfaceflinger/tests/LayerTransactionTest.h
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -25,7 +25,7 @@
 #include <gui/ISurfaceComposer.h>
 #include <gui/SurfaceComposerClient.h>
 #include <private/gui/ComposerService.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 
 #include "BufferGenerator.h"
 #include "utils/ScreenshotUtils.h"
@@ -265,16 +265,16 @@
         mDisplay = mClient->getInternalDisplayToken();
         ASSERT_FALSE(mDisplay == nullptr) << "failed to get display";
 
-        DisplayConfig config;
-        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(mDisplay, &config));
-        mDisplayRect = Rect(config.resolution);
+        ui::DisplayMode mode;
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(mDisplay, &mode));
+        mDisplayRect = Rect(mode.resolution);
         mDisplayWidth = mDisplayRect.getWidth();
         mDisplayHeight = mDisplayRect.getHeight();
 
         // After a new buffer is queued, SurfaceFlinger is notified and will
         // latch the new buffer on next vsync.  Let's heuristically wait for 3
         // vsyncs.
-        mBufferPostDelay = static_cast<int32_t>(1e6 / config.refreshRate) * 3;
+        mBufferPostDelay = static_cast<int32_t>(1e6 / mode.refreshRate) * 3;
 
         mDisplayLayerStack = 0;
 
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
index 6c56d20..ec826ae 100644
--- a/services/surfaceflinger/tests/LayerUpdate_test.cpp
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -36,9 +36,9 @@
         const auto display = SurfaceComposerClient::getInternalDisplayToken();
         ASSERT_FALSE(display == nullptr);
 
-        DisplayConfig config;
-        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
-        const ui::Size& resolution = config.resolution;
+        ui::DisplayMode mode;
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+        const ui::Size& resolution = mode.resolution;
 
         // Background surface
         mBGSurfaceControl = createLayer(String8("BG Test Surface"), resolution.getWidth(),
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
index db0c56f..eaf54e3 100644
--- a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -37,13 +37,13 @@
 
         mMainDisplay = SurfaceComposerClient::getInternalDisplayToken();
         SurfaceComposerClient::getDisplayState(mMainDisplay, &mMainDisplayState);
-        SurfaceComposerClient::getActiveDisplayConfig(mMainDisplay, &mMainDisplayConfig);
+        SurfaceComposerClient::getActiveDisplayMode(mMainDisplay, &mMainDisplayMode);
 
         sp<IGraphicBufferConsumer> consumer;
         BufferQueue::createBufferQueue(&mProducer, &consumer);
         consumer->setConsumerName(String8("Virtual disp consumer"));
-        consumer->setDefaultBufferSize(mMainDisplayConfig.resolution.getWidth(),
-                                       mMainDisplayConfig.resolution.getHeight());
+        consumer->setDefaultBufferSize(mMainDisplayMode.resolution.getWidth(),
+                                       mMainDisplayMode.resolution.getHeight());
     }
 
     virtual void TearDown() {
@@ -59,7 +59,7 @@
             t.setDisplaySurface(mVirtualDisplay, mProducer);
             t.setDisplayLayerStack(mVirtualDisplay, layerStack);
             t.setDisplayProjection(mVirtualDisplay, mMainDisplayState.orientation,
-                                   Rect(layerStackSize), Rect(mMainDisplayConfig.resolution));
+                                   Rect(layerStackSize), Rect(mMainDisplayMode.resolution));
         });
     }
 
@@ -81,7 +81,7 @@
     }
 
     ui::DisplayState mMainDisplayState;
-    DisplayConfig mMainDisplayConfig;
+    ui::DisplayMode mMainDisplayMode;
     sp<IBinder> mMainDisplay;
     sp<IBinder> mVirtualDisplay;
     sp<IGraphicBufferProducer> mProducer;
diff --git a/services/surfaceflinger/tests/ScreenCapture_test.cpp b/services/surfaceflinger/tests/ScreenCapture_test.cpp
index 51ce1d3..4598f9d 100644
--- a/services/surfaceflinger/tests/ScreenCapture_test.cpp
+++ b/services/surfaceflinger/tests/ScreenCapture_test.cpp
@@ -33,9 +33,9 @@
         const auto display = SurfaceComposerClient::getInternalDisplayToken();
         ASSERT_FALSE(display == nullptr);
 
-        DisplayConfig config;
-        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
-        const ui::Size& resolution = config.resolution;
+        ui::DisplayMode mode;
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+        const ui::Size& resolution = mode.resolution;
 
         // Background surface
         mBGSurfaceControl = createLayer(String8("BG Test Surface"), resolution.getWidth(),
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index fa88ca5..a20d5c6 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -27,7 +27,7 @@
 #include <gui/Surface.h>
 #include <gui/SurfaceComposerClient.h>
 #include <private/gui/ComposerService.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 
 #include <fstream>
 #include <random>
@@ -267,9 +267,9 @@
     const auto display = SurfaceComposerClient::getInternalDisplayToken();
     ASSERT_FALSE(display == nullptr);
 
-    DisplayConfig config;
-    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
-    const ui::Size& resolution = config.resolution;
+    ui::DisplayMode mode;
+    ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+    const ui::Size& resolution = mode.resolution;
 
     // Background surface
     mBGSurfaceControl =
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
index 33823d7..89f6086 100644
--- a/services/surfaceflinger/tests/TransactionTestHarnesses.h
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -40,9 +40,9 @@
                 ui::DisplayState displayState;
                 SurfaceComposerClient::getDisplayState(displayToken, &displayState);
 
-                DisplayConfig displayConfig;
-                SurfaceComposerClient::getActiveDisplayConfig(displayToken, &displayConfig);
-                const ui::Size& resolution = displayConfig.resolution;
+                ui::DisplayMode displayMode;
+                SurfaceComposerClient::getActiveDisplayMode(displayToken, &displayMode);
+                const ui::Size& resolution = displayMode.resolution;
 
                 sp<IBinder> vDisplay;
                 sp<IGraphicBufferProducer> producer;
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 4d7b396..56e1ae9 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -43,7 +43,7 @@
 #include <hwbinder/ProcessState.h>
 #include <log/log.h>
 #include <private/gui/ComposerService.h>
-#include <ui/DisplayConfig.h>
+#include <ui/DisplayMode.h>
 #include <utils/Looper.h>
 
 #include <gmock/gmock.h>
@@ -63,9 +63,7 @@
 
 // Mock test helpers
 using ::testing::_;
-using ::testing::AtLeast;
 using ::testing::DoAll;
-using ::testing::Invoke;
 using ::testing::Return;
 using ::testing::SetArgPointee;
 
@@ -74,9 +72,11 @@
 using Display = V2_1::Display;
 
 ///////////////////////////////////////////////
-
-constexpr PhysicalDisplayId kPrimaryDisplayId = PhysicalDisplayId::fromPort(PRIMARY_DISPLAY);
-constexpr PhysicalDisplayId kExternalDisplayId = PhysicalDisplayId::fromPort(EXTERNAL_DISPLAY);
+constexpr PhysicalDisplayId physicalIdFromHwcDisplayId(Display hwcId) {
+    return PhysicalDisplayId::fromPort(hwcId);
+}
+constexpr PhysicalDisplayId kPrimaryDisplayId = physicalIdFromHwcDisplayId(PRIMARY_DISPLAY);
+constexpr PhysicalDisplayId kExternalDisplayId = physicalIdFromHwcDisplayId(EXTERNAL_DISPLAY);
 
 struct TestColor {
 public:
@@ -158,7 +158,7 @@
                 self->mReceivedDisplayEvents.push_back(buffer[i]);
             }
         }
-        ALOGD_IF(n < 0, "Error reading events (%s)\n", strerror(-n));
+        ALOGD_IF(n < 0, "Error reading events (%s)", strerror(-n));
         return 1;
     }
 
@@ -174,7 +174,7 @@
     void setExpectationsForConfigs(Display display, std::vector<TestConfig> testConfigs,
                                    Config activeConfig, V2_4::VsyncPeriodNanos defaultVsyncPeriod) {
         std::vector<Config> configIds;
-        for (int i = 0; i < testConfigs.size(); i++) {
+        for (size_t i = 0; i < testConfigs.size(); i++) {
             configIds.push_back(testConfigs[i].id);
 
             EXPECT_CALL(*mMockComposer,
@@ -243,9 +243,8 @@
         mComposerClient = new SurfaceComposerClient;
         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
 
-        mReceiver.reset(
-                new DisplayEventReceiver(ISurfaceComposer::eVsyncSourceApp,
-                                         ISurfaceComposer::EventRegistration::configChanged));
+        mReceiver.reset(new DisplayEventReceiver(ISurfaceComposer::eVsyncSourceApp,
+                                                 ISurfaceComposer::EventRegistration::modeChanged));
         mLooper = new Looper(false);
         mLooper->addFd(mReceiver->getFd(), 0, ALOOPER_EVENT_INPUT, processDisplayEvents, this);
     }
@@ -269,10 +268,10 @@
         mMockComposer = nullptr;
     }
 
-    void waitForDisplayTransaction() {
+    void waitForDisplayTransaction(Display display) {
         // Both a refresh and a vsync event are needed to apply pending display
         // transactions.
-        mFakeComposerClient->refreshDisplay(EXTERNAL_DISPLAY);
+        mFakeComposerClient->refreshDisplay(display);
         mFakeComposerClient->runVSyncAndWait();
 
         // Extra vsync and wait to avoid a 10% flake due to a race.
@@ -291,7 +290,7 @@
                 mReceivedDisplayEvents.pop_front();
 
                 ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG,
-                         "event hotplug: displayId %s, connected %d\t",
+                         "event hotplug: displayId %s, connected %d",
                          to_string(event.header.displayId).c_str(), event.hotplug.connected);
 
                 if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG &&
@@ -305,7 +304,7 @@
         return false;
     }
 
-    bool waitForConfigChangedEvent(Display display, int32_t configId) {
+    bool waitForModeChangedEvent(Display display, int32_t modeId) {
         PhysicalDisplayId displayId(display);
         int waitCount = 20;
         while (waitCount--) {
@@ -313,12 +312,12 @@
                 auto event = mReceivedDisplayEvents.front();
                 mReceivedDisplayEvents.pop_front();
 
-                ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED,
-                         "event config: displayId %s, configId %d\t",
-                         to_string(event.header.displayId).c_str(), event.config.configId);
+                ALOGV_IF(event.header.type == DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE,
+                         "event mode: displayId %s, modeId %d",
+                         to_string(event.header.displayId).c_str(), event.modeChange.modeId);
 
-                if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED &&
-                    event.header.displayId == displayId && event.config.configId == configId) {
+                if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE &&
+                    event.header.displayId == displayId && event.modeChange.modeId == modeId) {
                     return true;
                 }
             }
@@ -341,18 +340,18 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::CONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
 
         {
             const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId);
             EXPECT_FALSE(display == nullptr);
 
-            DisplayConfig config;
-            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
-            const ui::Size& resolution = config.resolution;
+            ui::DisplayMode mode;
+            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+            const ui::Size& resolution = mode.resolution;
             EXPECT_EQ(ui::Size(200, 400), resolution);
-            EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
+            EXPECT_EQ(1e9f / 16'666'666, mode.refreshRate);
 
             auto surfaceControl =
                     mComposerClient->createSurface(String8("Display Test Surface Foo"),
@@ -372,7 +371,7 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::DISCONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         mFakeComposerClient->clearFrames();
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
 
@@ -380,8 +379,8 @@
             const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId);
             EXPECT_TRUE(display == nullptr);
 
-            DisplayConfig config;
-            EXPECT_NE(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+            ui::DisplayMode mode;
+            EXPECT_NE(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
         }
     }
 
@@ -403,20 +402,20 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::CONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
 
         const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId);
         EXPECT_FALSE(display == nullptr);
 
-        DisplayConfig config;
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
-        EXPECT_EQ(ui::Size(200, 400), config.resolution);
-        EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
+        ui::DisplayMode mode;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+        EXPECT_EQ(ui::Size(200, 400), mode.resolution);
+        EXPECT_EQ(1e9f / 16'666'666, mode.refreshRate);
 
         mFakeComposerClient->clearFrames();
         {
-            const ui::Size& resolution = config.resolution;
+            const ui::Size& resolution = mode.resolution;
             auto surfaceControl =
                     mComposerClient->createSurface(String8("Display Test Surface Foo"),
                                                    resolution.getWidth(), resolution.getHeight(),
@@ -433,11 +432,11 @@
             }
         }
 
-        Vector<DisplayConfig> configs;
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
-        EXPECT_EQ(configs.size(), 2);
+        Vector<ui::DisplayMode> modes;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes));
+        EXPECT_EQ(modes.size(), 2);
 
-        // change active config
+        // change active mode
 
         if (mIs2_4Client) {
             EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 2, _, _))
@@ -447,28 +446,28 @@
                     .WillOnce(Return(V2_1::Error::NONE));
         }
 
-        for (int i = 0; i < configs.size(); i++) {
-            const auto& config = configs[i];
-            if (config.resolution.getWidth() == 800) {
+        for (int i = 0; i < modes.size(); i++) {
+            const auto& mode = modes[i];
+            if (mode.resolution.getWidth() == 800) {
                 EXPECT_EQ(NO_ERROR,
-                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
-                                                                              config.refreshRate,
-                                                                              config.refreshRate,
-                                                                              config.refreshRate,
-                                                                              config.refreshRate));
-                waitForDisplayTransaction();
-                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                          SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate));
+                waitForDisplayTransaction(EXTERNAL_DISPLAY);
+                EXPECT_TRUE(waitForModeChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
             }
         }
 
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
-        EXPECT_EQ(ui::Size(800, 1600), config.resolution);
-        EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+        EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
+        EXPECT_EQ(1e9f / 11'111'111, mode.refreshRate);
 
         mFakeComposerClient->clearFrames();
         {
-            const ui::Size& resolution = config.resolution;
+            const ui::Size& resolution = mode.resolution;
             auto surfaceControl =
                     mComposerClient->createSurface(String8("Display Test Surface Foo"),
                                                    resolution.getWidth(), resolution.getHeight(),
@@ -487,7 +486,7 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::DISCONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         mFakeComposerClient->clearFrames();
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
     }
@@ -510,20 +509,20 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::CONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
 
         const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId);
         EXPECT_FALSE(display == nullptr);
 
-        DisplayConfig config;
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
-        EXPECT_EQ(ui::Size(800, 1600), config.resolution);
-        EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
+        ui::DisplayMode mode;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+        EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
+        EXPECT_EQ(1e9f / 16'666'666, mode.refreshRate);
 
         mFakeComposerClient->clearFrames();
         {
-            const ui::Size& resolution = config.resolution;
+            const ui::Size& resolution = mode.resolution;
             auto surfaceControl =
                     mComposerClient->createSurface(String8("Display Test Surface Foo"),
                                                    resolution.getWidth(), resolution.getHeight(),
@@ -540,11 +539,11 @@
             }
         }
 
-        Vector<DisplayConfig> configs;
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
-        EXPECT_EQ(configs.size(), 2);
+        Vector<ui::DisplayMode> modes;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes));
+        EXPECT_EQ(modes.size(), 2);
 
-        // change active config
+        // change active mode
         if (mIs2_4Client) {
             EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 3, _, _))
                     .WillOnce(Return(V2_4::Error::NONE));
@@ -553,28 +552,28 @@
                     .WillOnce(Return(V2_1::Error::NONE));
         }
 
-        for (int i = 0; i < configs.size(); i++) {
-            const auto& config = configs[i];
-            if (config.refreshRate == 1e9f / 11'111'111) {
+        for (int i = 0; i < modes.size(); i++) {
+            const auto& mode = modes[i];
+            if (mode.refreshRate == 1e9f / 11'111'111) {
                 EXPECT_EQ(NO_ERROR,
-                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
-                                                                              config.refreshRate,
-                                                                              config.refreshRate,
-                                                                              config.refreshRate,
-                                                                              config.refreshRate));
-                waitForDisplayTransaction();
-                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                          SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate));
+                waitForDisplayTransaction(EXTERNAL_DISPLAY);
+                EXPECT_TRUE(waitForModeChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
             }
         }
 
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
-        EXPECT_EQ(ui::Size(800, 1600), config.resolution);
-        EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+        EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
+        EXPECT_EQ(1e9f / 11'111'111, mode.refreshRate);
 
         mFakeComposerClient->clearFrames();
         {
-            const ui::Size& resolution = config.resolution;
+            const ui::Size& resolution = mode.resolution;
             auto surfaceControl =
                     mComposerClient->createSurface(String8("Display Test Surface Foo"),
                                                    resolution.getWidth(), resolution.getHeight(),
@@ -593,7 +592,7 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::DISCONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         mFakeComposerClient->clearFrames();
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
     }
@@ -626,20 +625,20 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::CONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, true));
 
         const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kExternalDisplayId);
         EXPECT_FALSE(display == nullptr);
 
-        DisplayConfig config;
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
-        EXPECT_EQ(ui::Size(800, 1600), config.resolution);
-        EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
+        ui::DisplayMode mode;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+        EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
+        EXPECT_EQ(1e9f / 16'666'666, mode.refreshRate);
 
         mFakeComposerClient->clearFrames();
         {
-            const ui::Size& resolution = config.resolution;
+            const ui::Size& resolution = mode.resolution;
             auto surfaceControl =
                     mComposerClient->createSurface(String8("Display Test Surface Foo"),
                                                    resolution.getWidth(), resolution.getHeight(),
@@ -656,11 +655,11 @@
             }
         }
 
-        Vector<DisplayConfig> configs;
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayConfigs(display, &configs));
-        EXPECT_EQ(configs.size(), 4);
+        Vector<ui::DisplayMode> modes;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes));
+        EXPECT_EQ(modes.size(), 4);
 
-        // change active config to 800x1600@90Hz
+        // change active mode to 800x1600@90Hz
         if (mIs2_4Client) {
             EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 3, _, _))
                     .WillOnce(Return(V2_4::Error::NONE));
@@ -669,29 +668,28 @@
                     .WillOnce(Return(V2_1::Error::NONE));
         }
 
-        for (int i = 0; i < configs.size(); i++) {
-            const auto& config = configs[i];
-            if (config.resolution.getWidth() == 800 && config.refreshRate == 1e9f / 11'111'111) {
+        for (size_t i = 0; i < modes.size(); i++) {
+            const auto& mode = modes[i];
+            if (mode.resolution.getWidth() == 800 && mode.refreshRate == 1e9f / 11'111'111) {
                 EXPECT_EQ(NO_ERROR,
-                          SurfaceComposerClient::
-                                  setDesiredDisplayConfigSpecs(display, i, false,
-                                                               configs[i].refreshRate,
-                                                               configs[i].refreshRate,
-                                                               configs[i].refreshRate,
-                                                               configs[i].refreshRate));
-                waitForDisplayTransaction();
-                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                          SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
+                                                                            modes[i].refreshRate,
+                                                                            modes[i].refreshRate,
+                                                                            modes[i].refreshRate,
+                                                                            modes[i].refreshRate));
+                waitForDisplayTransaction(EXTERNAL_DISPLAY);
+                EXPECT_TRUE(waitForModeChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
             }
         }
 
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
-        EXPECT_EQ(ui::Size(800, 1600), config.resolution);
-        EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+        EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
+        EXPECT_EQ(1e9f / 11'111'111, mode.refreshRate);
 
         mFakeComposerClient->clearFrames();
         {
-            const ui::Size& resolution = config.resolution;
+            const ui::Size& resolution = mode.resolution;
             auto surfaceControl =
                     mComposerClient->createSurface(String8("Display Test Surface Foo"),
                                                    resolution.getWidth(), resolution.getHeight(),
@@ -708,7 +706,7 @@
             }
         }
 
-        // change active config to 1600x3200@120Hz
+        // change active mode to 1600x3200@120Hz
         if (mIs2_4Client) {
             EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 4, _, _))
                     .WillOnce(Return(V2_4::Error::NONE));
@@ -717,28 +715,28 @@
                     .WillOnce(Return(V2_1::Error::NONE));
         }
 
-        for (int i = 0; i < configs.size(); i++) {
-            const auto& config = configs[i];
-            if (config.refreshRate == 1e9f / 8'333'333) {
+        for (int i = 0; i < modes.size(); i++) {
+            const auto& mode = modes[i];
+            if (mode.refreshRate == 1e9f / 8'333'333) {
                 EXPECT_EQ(NO_ERROR,
-                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
-                                                                              config.refreshRate,
-                                                                              config.refreshRate,
-                                                                              config.refreshRate,
-                                                                              config.refreshRate));
-                waitForDisplayTransaction();
-                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                          SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate));
+                waitForDisplayTransaction(EXTERNAL_DISPLAY);
+                EXPECT_TRUE(waitForModeChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
             }
         }
 
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
-        EXPECT_EQ(ui::Size(1600, 3200), config.resolution);
-        EXPECT_EQ(1e9f / 8'333'333, config.refreshRate);
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+        EXPECT_EQ(ui::Size(1600, 3200), mode.resolution);
+        EXPECT_EQ(1e9f / 8'333'333, mode.refreshRate);
 
         mFakeComposerClient->clearFrames();
         {
-            const ui::Size& resolution = config.resolution;
+            const ui::Size& resolution = mode.resolution;
             auto surfaceControl =
                     mComposerClient->createSurface(String8("Display Test Surface Foo"),
                                                    resolution.getWidth(), resolution.getHeight(),
@@ -755,7 +753,7 @@
             }
         }
 
-        // change active config to 1600x3200@90Hz
+        // change active mode to 1600x3200@90Hz
         if (mIs2_4Client) {
             EXPECT_CALL(*mMockComposer, setActiveConfigWithConstraints(EXTERNAL_DISPLAY, 5, _, _))
                     .WillOnce(Return(V2_4::Error::NONE));
@@ -764,28 +762,28 @@
                     .WillOnce(Return(V2_1::Error::NONE));
         }
 
-        for (int i = 0; i < configs.size(); i++) {
-            const auto& config = configs[i];
-            if (config.resolution.getWidth() == 1600 && config.refreshRate == 1e9f / 11'111'111) {
+        for (int i = 0; i < modes.size(); i++) {
+            const auto& mode = modes[i];
+            if (mode.resolution.getWidth() == 1600 && mode.refreshRate == 1e9f / 11'111'111) {
                 EXPECT_EQ(NO_ERROR,
-                          SurfaceComposerClient::setDesiredDisplayConfigSpecs(display, i, false,
-                                                                              config.refreshRate,
-                                                                              config.refreshRate,
-                                                                              config.refreshRate,
-                                                                              config.refreshRate));
-                waitForDisplayTransaction();
-                EXPECT_TRUE(waitForConfigChangedEvent(EXTERNAL_DISPLAY, i));
+                          SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate,
+                                                                            mode.refreshRate));
+                waitForDisplayTransaction(EXTERNAL_DISPLAY);
+                EXPECT_TRUE(waitForModeChangedEvent(EXTERNAL_DISPLAY, i));
                 break;
             }
         }
 
-        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
-        EXPECT_EQ(ui::Size(1600, 3200), config.resolution);
-        EXPECT_EQ(1e9f / 11'111'111, config.refreshRate);
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+        EXPECT_EQ(ui::Size(1600, 3200), mode.resolution);
+        EXPECT_EQ(1e9f / 11'111'111, mode.refreshRate);
 
         mFakeComposerClient->clearFrames();
         {
-            const ui::Size& resolution = config.resolution;
+            const ui::Size& resolution = mode.resolution;
             auto surfaceControl =
                     mComposerClient->createSurface(String8("Display Test Surface Foo"),
                                                    resolution.getWidth(), resolution.getHeight(),
@@ -804,7 +802,7 @@
 
         mFakeComposerClient->hotplugDisplay(EXTERNAL_DISPLAY,
                                             V2_1::IComposerCallback::Connection::DISCONNECTED);
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(EXTERNAL_DISPLAY);
         mFakeComposerClient->clearFrames();
         EXPECT_TRUE(waitForHotplugEvent(EXTERNAL_DISPLAY, false));
     }
@@ -815,15 +813,15 @@
         mFakeComposerClient->hotplugDisplay(PRIMARY_DISPLAY,
                                             V2_1::IComposerCallback::Connection::DISCONNECTED);
 
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(PRIMARY_DISPLAY);
 
         EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, false));
         {
             const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kPrimaryDisplayId);
             EXPECT_TRUE(display == nullptr);
 
-            DisplayConfig config;
-            auto result = SurfaceComposerClient::getActiveDisplayConfig(display, &config);
+            ui::DisplayMode mode;
+            auto result = SurfaceComposerClient::getActiveDisplayMode(display, &mode);
             EXPECT_NE(NO_ERROR, result);
         }
 
@@ -840,7 +838,7 @@
         mFakeComposerClient->hotplugDisplay(PRIMARY_DISPLAY,
                                             V2_1::IComposerCallback::Connection::CONNECTED);
 
-        waitForDisplayTransaction();
+        waitForDisplayTransaction(PRIMARY_DISPLAY);
 
         EXPECT_TRUE(waitForHotplugEvent(PRIMARY_DISPLAY, true));
 
@@ -848,11 +846,126 @@
             const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kPrimaryDisplayId);
             EXPECT_FALSE(display == nullptr);
 
-            DisplayConfig config;
-            auto result = SurfaceComposerClient::getActiveDisplayConfig(display, &config);
+            ui::DisplayMode mode;
+            auto result = SurfaceComposerClient::getActiveDisplayMode(display, &mode);
             EXPECT_EQ(NO_ERROR, result);
-            ASSERT_EQ(ui::Size(400, 200), config.resolution);
-            EXPECT_EQ(1e9f / 16'666'666, config.refreshRate);
+            ASSERT_EQ(ui::Size(400, 200), mode.resolution);
+            EXPECT_EQ(1e9f / 16'666'666, mode.refreshRate);
+        }
+    }
+
+    void Test_SubsequentHotplugConnectUpdatesDisplay(Display hwcDisplayId) {
+        ALOGD("DisplayTest::Test_SubsequentHotplugConnectUpdatesDisplay");
+
+        // Send a hotplug connected event to set up the initial display modes.
+        // The primary display is already connected so this will update it.
+        // If we're running the test of an external display this will create it.
+        setExpectationsForConfigs(hwcDisplayId,
+                                  {{.id = 1,
+                                    .w = 800,
+                                    .h = 1600,
+                                    .vsyncPeriod = 11'111'111,
+                                    .group = 1}},
+                                  /* activeConfig */ 1, 11'111'111);
+
+        mFakeComposerClient->hotplugDisplay(hwcDisplayId,
+                                            V2_1::IComposerCallback::Connection::CONNECTED);
+        waitForDisplayTransaction(hwcDisplayId);
+        EXPECT_TRUE(waitForHotplugEvent(hwcDisplayId, true));
+
+        const auto displayId = physicalIdFromHwcDisplayId(hwcDisplayId);
+        const auto display = SurfaceComposerClient::getPhysicalDisplayToken(displayId);
+        EXPECT_FALSE(display == nullptr);
+
+        // Verify that the active mode and the supported moded are updated
+        {
+            ui::DisplayMode mode;
+            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+            EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
+            EXPECT_EQ(1e9f / 11'111'111, mode.refreshRate);
+
+            Vector<ui::DisplayMode> modes;
+            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes));
+            EXPECT_EQ(modes.size(), 1);
+        }
+
+        // Send another hotplug connected event
+        setExpectationsForConfigs(hwcDisplayId,
+                                  {
+                                          {.id = 1,
+                                           .w = 800,
+                                           .h = 1600,
+                                           .vsyncPeriod = 16'666'666,
+                                           .group = 1},
+                                          {.id = 2,
+                                           .w = 800,
+                                           .h = 1600,
+                                           .vsyncPeriod = 11'111'111,
+                                           .group = 1},
+                                          {.id = 3,
+                                           .w = 800,
+                                           .h = 1600,
+                                           .vsyncPeriod = 8'333'333,
+                                           .group = 1},
+                                  },
+                                  /* activeConfig */ 1, 16'666'666);
+
+        mFakeComposerClient->hotplugDisplay(hwcDisplayId,
+                                            V2_1::IComposerCallback::Connection::CONNECTED);
+        waitForDisplayTransaction(hwcDisplayId);
+        EXPECT_TRUE(waitForHotplugEvent(hwcDisplayId, true));
+
+        // Verify that the active mode and the supported moded are updated
+        {
+            ui::DisplayMode mode;
+            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+            EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
+            EXPECT_EQ(1e9f / 16'666'666, mode.refreshRate);
+        }
+
+        Vector<ui::DisplayMode> modes;
+        EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayModes(display, &modes));
+        EXPECT_EQ(modes.size(), 3);
+
+        EXPECT_EQ(ui::Size(800, 1600), modes[0].resolution);
+        EXPECT_EQ(1e9f / 16'666'666, modes[0].refreshRate);
+
+        EXPECT_EQ(ui::Size(800, 1600), modes[1].resolution);
+        EXPECT_EQ(1e9f / 11'111'111, modes[1].refreshRate);
+
+        EXPECT_EQ(ui::Size(800, 1600), modes[2].resolution);
+        EXPECT_EQ(1e9f / 8'333'333, modes[2].refreshRate);
+
+        // Verify that we are able to switch to any of the modes
+        for (int i = modes.size() - 1; i >= 0; i--) {
+            const auto hwcId = i + 1;
+            // Set up HWC expectations for the mode change
+            if (mIs2_4Client) {
+                EXPECT_CALL(*mMockComposer,
+                            setActiveConfigWithConstraints(hwcDisplayId, hwcId, _, _))
+                        .WillOnce(Return(V2_4::Error::NONE));
+            } else {
+                EXPECT_CALL(*mMockComposer, setActiveConfig(hwcDisplayId, hwcId))
+                        .WillOnce(Return(V2_1::Error::NONE));
+            }
+
+            EXPECT_EQ(NO_ERROR,
+                      SurfaceComposerClient::setDesiredDisplayModeSpecs(display, i, false,
+                                                                        modes[i].refreshRate,
+                                                                        modes[i].refreshRate,
+                                                                        modes[i].refreshRate,
+                                                                        modes[i].refreshRate));
+            // We need to refresh twice - once to apply the pending mode change request,
+            // and once to process the change.
+            waitForDisplayTransaction(hwcDisplayId);
+            waitForDisplayTransaction(hwcDisplayId);
+            EXPECT_TRUE(waitForModeChangedEvent(hwcDisplayId, i))
+                    << "Failure while switching to mode " << i;
+
+            ui::DisplayMode mode;
+            EXPECT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
+            EXPECT_EQ(ui::Size(800, 1600), mode.resolution);
+            EXPECT_EQ(modes[i].refreshRate, mode.refreshRate);
         }
     }
 
@@ -911,6 +1024,14 @@
     Test_HotplugPrimaryDisplay();
 }
 
+TEST_F(DisplayTest_2_1, SubsequentHotplugConnectUpdatesPrimaryDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY);
+}
+
+TEST_F(DisplayTest_2_1, SubsequentHotplugConnectUpdatesExternalDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY);
+}
+
 using DisplayTest_2_2 = DisplayTest<FakeComposerService_2_2>;
 
 TEST_F(DisplayTest_2_2, HotplugOneConfig) {
@@ -933,6 +1054,14 @@
     Test_HotplugPrimaryDisplay();
 }
 
+TEST_F(DisplayTest_2_2, SubsequentHotplugConnectUpdatesPrimaryDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY);
+}
+
+TEST_F(DisplayTest_2_2, SubsequentHotplugConnectUpdatesExternalDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY);
+}
+
 using DisplayTest_2_3 = DisplayTest<FakeComposerService_2_3>;
 
 TEST_F(DisplayTest_2_3, HotplugOneConfig) {
@@ -955,6 +1084,14 @@
     Test_HotplugPrimaryDisplay();
 }
 
+TEST_F(DisplayTest_2_3, SubsequentHotplugConnectUpdatesPrimaryDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY);
+}
+
+TEST_F(DisplayTest_2_3, SubsequentHotplugConnectUpdatesExternalDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY);
+}
+
 using DisplayTest_2_4 = DisplayTest<FakeComposerService_2_4>;
 
 TEST_F(DisplayTest_2_4, HotplugOneConfig) {
@@ -977,6 +1114,14 @@
     Test_HotplugPrimaryDisplay();
 }
 
+TEST_F(DisplayTest_2_4, SubsequentHotplugConnectUpdatesPrimaryDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(PRIMARY_DISPLAY);
+}
+
+TEST_F(DisplayTest_2_4, SubsequentHotplugConnectUpdatesExternalDisplay) {
+    Test_SubsequentHotplugConnectUpdatesDisplay(EXTERNAL_DISPLAY);
+}
+
 ////////////////////////////////////////////////
 
 template <typename FakeComposerService>
@@ -1021,10 +1166,10 @@
         const auto display = SurfaceComposerClient::getPhysicalDisplayToken(kPrimaryDisplayId);
         ASSERT_FALSE(display == nullptr);
 
-        DisplayConfig config;
-        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayConfig(display, &config));
+        ui::DisplayMode mode;
+        ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getActiveDisplayMode(display, &mode));
 
-        const ui::Size& resolution = config.resolution;
+        const ui::Size& resolution = mode.resolution;
         mDisplayWidth = resolution.getWidth();
         mDisplayHeight = resolution.getHeight();
 
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 13b26fc..17928a0 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -73,6 +73,7 @@
         "FrameTracerTest.cpp",
         "TimerTest.cpp",
         "TransactionApplicationTest.cpp",
+        "TransactionSurfaceFrameTest.cpp",
         "StrongTypingTest.cpp",
         "VSyncDispatchTimerQueueTest.cpp",
         "VSyncDispatchRealtimeTest.cpp",
@@ -124,7 +125,7 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.common@1.2",
-        "android.hardware.power-cpp",
+        "android.hardware.power-V1-cpp",
         "libbase",
         "libbinder",
         "libcutils",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index f2051d9..b696a6d 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -62,15 +62,9 @@
 
 using testing::_;
 using testing::AtLeast;
-using testing::Between;
-using testing::ByMove;
 using testing::DoAll;
-using testing::Field;
-using testing::Invoke;
 using testing::IsNull;
 using testing::Mock;
-using testing::NotNull;
-using testing::Ref;
 using testing::Return;
 using testing::ReturnRef;
 using testing::SetArgPointee;
@@ -86,7 +80,6 @@
 constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
 constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
 
-constexpr int DEFAULT_CONFIG_ID = 0;
 constexpr int DEFAULT_TEXTURE_ID = 6000;
 constexpr int DEFAULT_LAYER_STACK = 7000;
 
@@ -147,7 +140,7 @@
 
         EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
         EXPECT_CALL(*vsyncTracker, currentPeriod())
-                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
         EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
 
         constexpr ISchedulerCallback* kCallback = nullptr;
@@ -548,12 +541,6 @@
         setupLatchedBuffer(test, layer);
     }
 
-    static void setupBufferLayerPostFrameCallExpectations(CompositionTest* test) {
-        // BufferLayer::onPostComposition(), when there is no present fence
-        EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY, _))
-                .WillOnce(DoAll(SetArgPointee<1>(DEFAULT_CONFIG_ID), Return(Error::NONE)));
-    }
-
     static void setupHwcSetGeometryCallExpectations(CompositionTest* test) {
         if (!test->mDisplayOff) {
             // TODO: Coverage of other values
@@ -632,8 +619,6 @@
                     .Times(1);
             EXPECT_CALL(*test->mComposer, setLayerBuffer(HWC_DISPLAY, HWC_LAYER, _, _, _)).Times(1);
         }
-
-        setupBufferLayerPostFrameCallExpectations(test);
     }
 
     static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
@@ -793,7 +778,6 @@
 
     static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
         setupInsecureREBufferCompositionCommonCallExpectations(test);
-        Base::setupBufferLayerPostFrameCallExpectations(test);
     }
 
     static void setupInsecureREBufferScreenshotCompositionCallExpectations(CompositionTest* test) {
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 45bc29c..7cc0032 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -141,10 +141,10 @@
 
     createThread(std::move(vsyncSource));
     mConnection = createConnection(mConnectionEventCallRecorder,
-                                   ISurfaceComposer::EventRegistration::configChanged |
+                                   ISurfaceComposer::EventRegistration::modeChanged |
                                            ISurfaceComposer::EventRegistration::frameRateOverride);
     mThrottledConnection = createConnection(mThrottledConnectionEventCallRecorder,
-                                            ISurfaceComposer::EventRegistration::configChanged,
+                                            ISurfaceComposer::EventRegistration::modeChanged,
                                             mThrottledConnectionUid);
 
     // A display must be connected for VSYNC events to be delivered.
@@ -257,10 +257,10 @@
     auto args = mConnectionEventCallRecorder.waitForCall();
     ASSERT_TRUE(args.has_value());
     const auto& event = std::get<0>(args.value());
-    EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, event.header.type);
+    EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE, event.header.type);
     EXPECT_EQ(expectedDisplayId, event.header.displayId);
-    EXPECT_EQ(expectedConfigId, event.config.configId);
-    EXPECT_EQ(expectedVsyncPeriod, event.config.vsyncPeriod);
+    EXPECT_EQ(expectedConfigId, event.modeChange.modeId);
+    EXPECT_EQ(expectedVsyncPeriod, event.modeChange.vsyncPeriod);
 }
 
 void EventThreadTest::expectUidFrameRateMappingEventReceivedByConnection(
@@ -540,17 +540,17 @@
 }
 
 TEST_F(EventThreadTest, postConfigChangedPrimary) {
-    mThread->onConfigChanged(INTERNAL_DISPLAY_ID, DisplayModeId(7), 16666666);
+    mThread->onModeChanged(INTERNAL_DISPLAY_ID, DisplayModeId(7), 16666666);
     expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 7, 16666666);
 }
 
 TEST_F(EventThreadTest, postConfigChangedExternal) {
-    mThread->onConfigChanged(EXTERNAL_DISPLAY_ID, DisplayModeId(5), 16666666);
+    mThread->onModeChanged(EXTERNAL_DISPLAY_ID, DisplayModeId(5), 16666666);
     expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5, 16666666);
 }
 
 TEST_F(EventThreadTest, postConfigChangedPrimary64bit) {
-    mThread->onConfigChanged(DISPLAY_ID_64BIT, DisplayModeId(7), 16666666);
+    mThread->onModeChanged(DISPLAY_ID_64BIT, DisplayModeId(7), 16666666);
     expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7, 16666666);
 }
 
@@ -559,7 +559,7 @@
     sp<MockEventThreadConnection> suppressConnection =
             createConnection(suppressConnectionEventRecorder);
 
-    mThread->onConfigChanged(INTERNAL_DISPLAY_ID, DisplayModeId(9), 16666666);
+    mThread->onModeChanged(INTERNAL_DISPLAY_ID, DisplayModeId(9), 16666666);
     expectConfigChangedEventReceivedByConnection(INTERNAL_DISPLAY_ID, 9, 16666666);
 
     auto args = suppressConnectionEventRecorder.waitForCall();
diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
index 1e24c0a..6b82170 100644
--- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp
@@ -175,90 +175,5 @@
     EXPECT_EQ(hal::Error::UNSUPPORTED, result);
 }
 
-class HWComposerConfigsTest : public testing::Test {
-public:
-    Hwc2::mock::Composer* mHal = new StrictMock<Hwc2::mock::Composer>();
-    MockHWC2ComposerCallback mCallback;
-
-    void setActiveConfig(Config config) {
-        EXPECT_CALL(*mHal, getActiveConfig(_, _))
-                .WillRepeatedly(DoAll(SetArgPointee<1>(config), Return(V2_1::Error::NONE)));
-    }
-
-    void setDisplayConfigs(std::vector<Config> configs) {
-        EXPECT_CALL(*mHal, getDisplayConfigs(_, _))
-                .WillOnce(DoAll(SetArgPointee<1>(configs), Return(V2_1::Error::NONE)));
-        EXPECT_CALL(*mHal, getDisplayAttribute(_, _, _, _))
-                .WillRepeatedly(DoAll(SetArgPointee<3>(1), Return(V2_1::Error::NONE)));
-    }
-
-    void testSetActiveModeWithConstraintsCommon(bool isVsyncPeriodSwitchSupported);
-};
-
-void HWComposerConfigsTest::testSetActiveModeWithConstraintsCommon(
-        bool isVsyncPeriodSwitchSupported) {
-    EXPECT_CALL(*mHal, getMaxVirtualDisplayCount()).WillOnce(Return(0));
-    EXPECT_CALL(*mHal, getCapabilities()).WillOnce(Return(std::vector<hal::Capability>{}));
-    EXPECT_CALL(*mHal, getLayerGenericMetadataKeys(_)).WillOnce(Return(V2_4::Error::UNSUPPORTED));
-    EXPECT_CALL(*mHal, registerCallback(_));
-    EXPECT_CALL(*mHal, setVsyncEnabled(_, _)).WillRepeatedly(Return(V2_1::Error::NONE));
-    EXPECT_CALL(*mHal, getDisplayIdentificationData(_, _, _))
-            .WillRepeatedly(Return(V2_1::Error::UNSUPPORTED));
-    EXPECT_CALL(*mHal, setClientTargetSlotCount(_)).WillRepeatedly(Return(V2_1::Error::NONE));
-
-    EXPECT_CALL(*mHal, isVsyncPeriodSwitchSupported())
-            .WillRepeatedly(Return(isVsyncPeriodSwitchSupported));
-
-    if (isVsyncPeriodSwitchSupported) {
-        EXPECT_CALL(*mHal, setActiveConfigWithConstraints(_, _, _, _))
-                .WillRepeatedly(Return(V2_4::Error::NONE));
-    } else {
-        EXPECT_CALL(*mHal, setActiveConfig(_, _)).WillRepeatedly(Return(V2_1::Error::NONE));
-    }
-
-    impl::HWComposer hwc{std::unique_ptr<Hwc2::Composer>(mHal)};
-    hwc.setConfiguration(&mCallback, 123);
-
-    setDisplayConfigs({15});
-    setActiveConfig(15);
-
-    const auto physicalId = PhysicalDisplayId::fromPort(0);
-    const hal::HWDisplayId hwcId = 0;
-    hwc.allocatePhysicalDisplay(hwcId, physicalId);
-
-    hal::VsyncPeriodChangeConstraints constraints;
-    constraints.desiredTimeNanos = systemTime();
-    constraints.seamlessRequired = false;
-
-    hal::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
-    constexpr Config kConfigIndex = 0;
-    const auto status =
-            hwc.setActiveModeWithConstraints(physicalId, kConfigIndex, constraints, &timeline);
-    EXPECT_EQ(NO_ERROR, status);
-
-    const std::vector<Config> kConfigs{7, 8, 9, 10, 11};
-    // Change the set of supported modes.
-    setDisplayConfigs(kConfigs);
-    setActiveConfig(11);
-    hwc.onHotplug(hwcId, hal::Connection::CONNECTED);
-    hwc.allocatePhysicalDisplay(hwcId, physicalId);
-
-    for (size_t configIndex = 0; configIndex < kConfigs.size(); configIndex++) {
-        const auto status =
-                hwc.setActiveModeWithConstraints(physicalId,
-                                                 static_cast<hal::HWConfigId>(configIndex),
-                                                 constraints, &timeline);
-        EXPECT_EQ(NO_ERROR, status) << "Error when switching to config " << configIndex;
-    }
-}
-
-TEST_F(HWComposerConfigsTest, setActiveModeWithConstraintsWithVsyncSwitchingSupported) {
-    testSetActiveModeWithConstraintsCommon(/*supported=*/true);
-}
-
-TEST_F(HWComposerConfigsTest, setActiveModeWithConstraintsWithVsyncSwitchingNotSupported) {
-    testSetActiveModeWithConstraintsCommon(/*supported=*/false);
-}
-
 } // namespace
 } // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index 04cafbc..fec590e 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -113,12 +113,12 @@
     RefreshRateConfigs mConfigs{{DisplayMode::Builder(0)
                                          .setId(DisplayModeId(0))
                                          .setVsyncPeriod(int32_t(LO_FPS_PERIOD))
-                                         .setConfigGroup(0)
+                                         .setGroup(0)
                                          .build(),
                                  DisplayMode::Builder(1)
                                          .setId(DisplayModeId(1))
                                          .setVsyncPeriod(int32_t(HI_FPS_PERIOD))
-                                         .setConfigGroup(0)
+                                         .setGroup(0)
                                          .build()},
                                 DisplayModeId(0)};
 
diff --git a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
index d5c9b57..be76e8f 100644
--- a/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerInfoTest.cpp
@@ -53,7 +53,7 @@
     for (int i = 1; i <= kNumFrames; i++) {
         frameTimes.push_back(FrameTimeData{.presentTime = kPeriod * i,
                                            .queueTime = 0,
-                                           .pendingConfigChange = false});
+                                           .pendingModeChange = false});
     }
     setFrameTimes(frameTimes);
     const auto averageFrameTime = calculateAverageFrameTime();
@@ -71,7 +71,7 @@
     for (int i = 1; i <= kNumFrames; i++) {
         frameTimes.push_back(FrameTimeData{.presentTime = 0,
                                            .queueTime = kPeriod * i,
-                                           .pendingConfigChange = false});
+                                           .pendingModeChange = false});
     }
     setFrameTimes(frameTimes);
     setLastRefreshRate(Fps(20.0f)); // Set to some valid value
@@ -89,7 +89,7 @@
     for (int i = 1; i <= kNumFrames; i++) {
         frameTimesWithoutConfigChange.push_back(FrameTimeData{.presentTime = period * i,
                                                               .queueTime = period * i,
-                                                              .pendingConfigChange = false});
+                                                              .pendingModeChange = false});
     }
 
     setFrameTimes(frameTimesWithoutConfigChange);
@@ -98,7 +98,7 @@
     {
         // Config change in the first record
         auto frameTimes = frameTimesWithoutConfigChange;
-        frameTimes[0].pendingConfigChange = true;
+        frameTimes[0].pendingModeChange = true;
         setFrameTimes(frameTimes);
         ASSERT_FALSE(calculateAverageFrameTime().has_value());
     }
@@ -106,7 +106,7 @@
     {
         // Config change in the last record
         auto frameTimes = frameTimesWithoutConfigChange;
-        frameTimes[frameTimes.size() - 1].pendingConfigChange = true;
+        frameTimes[frameTimes.size() - 1].pendingModeChange = true;
         setFrameTimes(frameTimes);
         ASSERT_FALSE(calculateAverageFrameTime().has_value());
     }
@@ -114,7 +114,7 @@
     {
         // Config change in the middle
         auto frameTimes = frameTimesWithoutConfigChange;
-        frameTimes[frameTimes.size() / 2].pendingConfigChange = true;
+        frameTimes[frameTimes.size() / 2].pendingModeChange = true;
         setFrameTimes(frameTimes);
         ASSERT_FALSE(calculateAverageFrameTime().has_value());
     }
@@ -131,12 +131,12 @@
     for (int i = 1; i <= kNumIterations; i++) {
         frameTimes.push_back(FrameTimeData{.presentTime = kExpectedPeriod * i,
                                            .queueTime = 0,
-                                           .pendingConfigChange = false});
+                                           .pendingModeChange = false});
 
         // A duplicate frame
         frameTimes.push_back(FrameTimeData{.presentTime = kExpectedPeriod * i + kSmallPeriod,
                                            .queueTime = 0,
-                                           .pendingConfigChange = false});
+                                           .pendingModeChange = false});
     }
     setFrameTimes(frameTimes);
     const auto averageFrameTime = calculateAverageFrameTime();
@@ -156,7 +156,7 @@
 
     auto record = [&](nsecs_t time) {
         frameTimes.push_back(
-                FrameTimeData{.presentTime = time, .queueTime = 0, .pendingConfigChange = false});
+                FrameTimeData{.presentTime = time, .queueTime = 0, .pendingModeChange = false});
     };
 
     auto time = kExpectedPeriod; // Start with non-zero time.
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 738ded1..376995f 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -81,24 +81,25 @@
     static inline const DisplayModeId HWC_CONFIG_ID_50 = DisplayModeId(6);
 
     // Test configs
-    DisplayModePtr mConfig60 = createConfig(HWC_CONFIG_ID_60, 0, Fps(60.0f).getPeriodNsecs());
-    DisplayModePtr mConfig90 = createConfig(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs());
+    DisplayModePtr mConfig60 = createDisplayMode(HWC_CONFIG_ID_60, 0, Fps(60.0f).getPeriodNsecs());
+    DisplayModePtr mConfig90 = createDisplayMode(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs());
     DisplayModePtr mConfig90DifferentGroup =
-            createConfig(HWC_CONFIG_ID_90, 1, Fps(90.0f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_90, 1, Fps(90.0f).getPeriodNsecs());
     DisplayModePtr mConfig90DifferentResolution =
-            createConfig(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs(), ui::Size(111, 222));
-    DisplayModePtr mConfig72 = createConfig(HWC_CONFIG_ID_72, 0, Fps(72.0f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_90, 0, Fps(90.0f).getPeriodNsecs(), ui::Size(111, 222));
+    DisplayModePtr mConfig72 = createDisplayMode(HWC_CONFIG_ID_72, 0, Fps(72.0f).getPeriodNsecs());
     DisplayModePtr mConfig72DifferentGroup =
-            createConfig(HWC_CONFIG_ID_72, 1, Fps(72.0f).getPeriodNsecs());
-    DisplayModePtr mConfig120 = createConfig(HWC_CONFIG_ID_120, 0, Fps(120.0f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_72, 1, Fps(72.0f).getPeriodNsecs());
+    DisplayModePtr mConfig120 =
+            createDisplayMode(HWC_CONFIG_ID_120, 0, Fps(120.0f).getPeriodNsecs());
     DisplayModePtr mConfig120DifferentGroup =
-            createConfig(HWC_CONFIG_ID_120, 1, Fps(120.0f).getPeriodNsecs());
-    DisplayModePtr mConfig30 = createConfig(HWC_CONFIG_ID_30, 0, Fps(30.0f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_120, 1, Fps(120.0f).getPeriodNsecs());
+    DisplayModePtr mConfig30 = createDisplayMode(HWC_CONFIG_ID_30, 0, Fps(30.0f).getPeriodNsecs());
     DisplayModePtr mConfig30DifferentGroup =
-            createConfig(HWC_CONFIG_ID_30, 1, Fps(30.0f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_30, 1, Fps(30.0f).getPeriodNsecs());
     DisplayModePtr mConfig25DifferentGroup =
-            createConfig(HWC_CONFIG_ID_25, 1, Fps(25.0f).getPeriodNsecs());
-    DisplayModePtr mConfig50 = createConfig(HWC_CONFIG_ID_50, 0, Fps(50.0f).getPeriodNsecs());
+            createDisplayMode(HWC_CONFIG_ID_25, 1, Fps(25.0f).getPeriodNsecs());
+    DisplayModePtr mConfig50 = createDisplayMode(HWC_CONFIG_ID_50, 0, Fps(50.0f).getPeriodNsecs());
 
     // Test device configurations
     // The positions of the configs in the arrays below MUST match their IDs. For example,
@@ -128,8 +129,8 @@
     RefreshRate mExpected60Config = {HWC_CONFIG_ID_60, mConfig60, Fps(60),
                                      RefreshRate::ConstructorTag(0)};
     RefreshRate mExpectedAlmost60Config = {HWC_CONFIG_ID_60,
-                                           createConfig(HWC_CONFIG_ID_60, 0, 16666665), Fps(60),
-                                           RefreshRate::ConstructorTag(0)};
+                                           createDisplayMode(HWC_CONFIG_ID_60, 0, 16666665),
+                                           Fps(60), RefreshRate::ConstructorTag(0)};
     RefreshRate mExpected90Config = {HWC_CONFIG_ID_90, mConfig90, Fps(90),
                                      RefreshRate::ConstructorTag(0)};
     RefreshRate mExpected90DifferentGroupConfig = {HWC_CONFIG_ID_90, mConfig90DifferentGroup,
@@ -144,8 +145,8 @@
     RefreshRate mExpected120Config = {HWC_CONFIG_ID_120, mConfig120, Fps(120),
                                       RefreshRate::ConstructorTag(0)};
 private:
-    DisplayModePtr createConfig(DisplayModeId configId, int32_t configGroup, int64_t vsyncPeriod,
-                                ui::Size resolution = ui::Size());
+    DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod,
+                                     ui::Size resolution = ui::Size());
 };
 
 using Builder = DisplayMode::Builder;
@@ -162,12 +163,12 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
-DisplayModePtr RefreshRateConfigsTest::createConfig(DisplayModeId configId, int32_t configGroup,
-                                                    int64_t vsyncPeriod, ui::Size resolution) {
-    return DisplayMode::Builder(hal::HWConfigId(configId.value()))
-            .setId(configId)
+DisplayModePtr RefreshRateConfigsTest::createDisplayMode(DisplayModeId modeId, int32_t group,
+                                                         int64_t vsyncPeriod, ui::Size resolution) {
+    return DisplayMode::Builder(hal::HWConfigId(modeId.value()))
+            .setId(modeId)
             .setVsyncPeriod(int32_t(vsyncPeriod))
-            .setConfigGroup(configGroup)
+            .setGroup(group)
             .setHeight(resolution.height)
             .setWidth(resolution.width)
             .build();
@@ -226,7 +227,7 @@
 
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(60), Fps(90)}}),
               0);
-    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+    refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
 
     const auto& minRate90 = getMinRefreshRateByPolicy(*refreshRateConfigs);
     const auto& performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -252,7 +253,7 @@
 
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(60), Fps(90)}}),
               0);
-    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+    refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
 
     const auto& minRate90 = getMinRefreshRateByPolicy(*refreshRateConfigs);
     const auto& performanceRate90 = refreshRateConfigs->getMaxRefreshRateByPolicy();
@@ -288,20 +289,20 @@
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
     {
         auto current = refreshRateConfigs->getCurrentRefreshRate();
-        EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_60);
+        EXPECT_EQ(current.getModeId(), HWC_CONFIG_ID_60);
     }
 
-    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+    refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
     {
         auto current = refreshRateConfigs->getCurrentRefreshRate();
-        EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
+        EXPECT_EQ(current.getModeId(), HWC_CONFIG_ID_90);
     }
 
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy({HWC_CONFIG_ID_90, {Fps(90), Fps(90)}}),
               0);
     {
         auto current = refreshRateConfigs->getCurrentRefreshRate();
-        EXPECT_EQ(current.getConfigId(), HWC_CONFIG_ID_90);
+        EXPECT_EQ(current.getModeId(), HWC_CONFIG_ID_90);
     }
 }
 
@@ -1196,30 +1197,30 @@
 
     ASSERT_EQ(HWC_CONFIG_ID_60,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getConfigId());
+                      .getModeId());
 
     RefreshRateConfigs::Policy policy;
-    policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig;
+    policy.defaultMode = refreshRateConfigs->getCurrentPolicy().defaultMode;
     policy.allowGroupSwitching = true;
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
     ASSERT_EQ(HWC_CONFIG_ID_90,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getConfigId());
+                      .getModeId());
 
     // Verify that we won't change the group if seamless switch is required.
     layer.seamlessness = Seamlessness::OnlySeamless;
     ASSERT_EQ(HWC_CONFIG_ID_60,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getConfigId());
+                      .getModeId());
 
     // Verify that we won't do a seamless switch if we request the same mode as the default
-    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+    refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
     layer.desiredRefreshRate = Fps(60.0f);
     layer.name = "60Hz ExplicitDefault";
     layer.seamlessness = Seamlessness::OnlySeamless;
     ASSERT_EQ(HWC_CONFIG_ID_90,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getConfigId());
+                      .getModeId());
 
     // Verify that if the current config is in another group and there are no layers with
     // seamlessness=SeamedAndSeamless we'll go back to the default group.
@@ -1228,11 +1229,11 @@
     layer.seamlessness = Seamlessness::Default;
     ASSERT_EQ(HWC_CONFIG_ID_60,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getConfigId());
+                      .getModeId());
 
     // If there's a layer with seamlessness=SeamedAndSeamless, another layer with
-    // seamlessness=OnlySeamless can't change the config group.
-    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+    // seamlessness=OnlySeamless can't change the mode group.
+    refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
     layer.seamlessness = Seamlessness::OnlySeamless;
 
     layers.push_back(LayerRequirement{.weight = 0.5f});
@@ -1245,14 +1246,14 @@
 
     ASSERT_EQ(HWC_CONFIG_ID_90,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getConfigId());
+                      .getModeId());
 
     // If there's a layer with seamlessness=SeamedAndSeamless, another layer with
-    // seamlessness=Default can't change the config group.
+    // seamlessness=Default can't change the mode group.
     layers[0].seamlessness = Seamlessness::Default;
     ASSERT_EQ(HWC_CONFIG_ID_90,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getConfigId());
+                      .getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, nonSeamlessVotePrefersSeamlessSwitches) {
@@ -1262,7 +1263,7 @@
 
     // Allow group switching.
     RefreshRateConfigs::Policy policy;
-    policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig;
+    policy.defaultMode = refreshRateConfigs->getCurrentPolicy().defaultMode;
     policy.allowGroupSwitching = true;
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
 
@@ -1276,12 +1277,12 @@
 
     ASSERT_EQ(HWC_CONFIG_ID_60,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getConfigId());
+                      .getModeId());
 
-    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_120);
+    refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_120);
     ASSERT_EQ(HWC_CONFIG_ID_120,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getConfigId());
+                      .getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, nonSeamlessExactAndSeamlessMultipleLayers) {
@@ -1291,7 +1292,7 @@
 
     // Allow group switching.
     RefreshRateConfigs::Policy policy;
-    policy.defaultConfig = refreshRateConfigs->getCurrentPolicy().defaultConfig;
+    policy.defaultMode = refreshRateConfigs->getCurrentPolicy().defaultMode;
     policy.allowGroupSwitching = true;
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(policy), 0);
 
@@ -1312,14 +1313,14 @@
 
     ASSERT_EQ(HWC_CONFIG_ID_50,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getConfigId());
+                      .getModeId());
 
     seamedLayer.name = "30Hz ExplicitDefault", seamedLayer.desiredRefreshRate = Fps(30.0f);
-    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_30);
+    refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_30);
 
     ASSERT_EQ(HWC_CONFIG_ID_25,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false})
-                      .getConfigId());
+                      .getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, primaryVsAppRequestPolicy) {
@@ -1338,7 +1339,7 @@
         layers[0].desiredRefreshRate = fps;
         layers[0].focused = focused;
         return refreshRateConfigs->getBestRefreshRate(layers, {.touch = touchActive, .idle = false})
-                .getConfigId();
+                .getModeId();
     };
 
     ASSERT_GE(refreshRateConfigs->setDisplayManagerPolicy(
@@ -1346,7 +1347,7 @@
               0);
     EXPECT_EQ(HWC_CONFIG_ID_60,
               refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = false})
-                      .getConfigId());
+                      .getModeId());
     EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::NoVote, Fps(90.f)));
     EXPECT_EQ(HWC_CONFIG_ID_30, getFrameRate(LayerVoteType::Min, Fps(90.f)));
     EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, Fps(90.f)));
@@ -1398,7 +1399,7 @@
                 refreshRateConfigs
                         ->getBestRefreshRate(layers, {.touch = touchActive, .idle = true},
                                              &consideredSignals)
-                        .getConfigId();
+                        .getModeId();
         // Refresh rate will be chosen by either touch state or idle state
         EXPECT_EQ(!touchActive, consideredSignals.idle);
         return configId;
@@ -1421,10 +1422,10 @@
     // With no layers, idle should still be lower priority than touch boost.
     EXPECT_EQ(HWC_CONFIG_ID_90,
               refreshRateConfigs->getBestRefreshRate({}, {.touch = true, .idle = true})
-                      .getConfigId());
+                      .getModeId());
 
     // Idle should be higher precedence than other layer frame rate considerations.
-    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+    refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
     EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::NoVote, /*touchActive=*/false));
     EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::Min, /*touchActive=*/false));
     EXPECT_EQ(HWC_CONFIG_ID_60, getIdleFrameRate(LayerVoteType::Max, /*touchActive=*/false));
@@ -1437,7 +1438,7 @@
     // Idle should be applied rather than the current config when there are no layers.
     EXPECT_EQ(HWC_CONFIG_ID_60,
               refreshRateConfigs->getBestRefreshRate({}, {.touch = false, .idle = true})
-                      .getConfigId());
+                      .getModeId());
 }
 
 TEST_F(RefreshRateConfigsTest, findClosestKnownFrameRate) {
@@ -1628,19 +1629,19 @@
     const auto frameRate = Fps(30.f);
     EXPECT_EQ(1, refreshRateConfigs->getRefreshRateDivider(frameRate));
 
-    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_60);
+    refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_60);
     EXPECT_EQ(2, refreshRateConfigs->getRefreshRateDivider(frameRate));
 
-    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_72);
+    refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_72);
     EXPECT_EQ(0, refreshRateConfigs->getRefreshRateDivider(frameRate));
 
-    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+    refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
     EXPECT_EQ(3, refreshRateConfigs->getRefreshRateDivider(frameRate));
 
-    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_120);
+    refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_120);
     EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDivider(frameRate));
 
-    refreshRateConfigs->setCurrentConfigId(HWC_CONFIG_ID_90);
+    refreshRateConfigs->setCurrentModeId(HWC_CONFIG_ID_90);
     EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDivider(Fps(22.5f)));
     EXPECT_EQ(4, refreshRateConfigs->getRefreshRateDivider(Fps(22.6f)));
 }
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
index c5deb7c..abecd4b 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateSelectionTest.cpp
@@ -144,7 +144,7 @@
 
     EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
     EXPECT_CALL(*vsyncTracker, currentPeriod())
-            .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+            .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
     EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
     mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
                             std::move(eventThread), std::move(sfEventThread));
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index ceccd81..bf07106 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -53,7 +53,7 @@
         mRefreshRateConfigs =
                 std::make_unique<RefreshRateConfigs>(configs, /*currentConfig=*/CONFIG_ID_0);
 
-        const auto currFps = mRefreshRateConfigs->getRefreshRateFromConfigId(CONFIG_ID_0).getFps();
+        const auto currFps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps();
         mRefreshRateStats = std::make_unique<RefreshRateStats>(mTimeStats, currFps,
                                                                /*currentPowerMode=*/PowerMode::OFF);
     }
@@ -62,7 +62,7 @@
     std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
     std::unique_ptr<RefreshRateStats> mRefreshRateStats;
 
-    DisplayModePtr createConfig(DisplayModeId configId, int32_t configGroup, int64_t vsyncPeriod);
+    DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod);
 };
 
 RefreshRateStatsTest::RefreshRateStatsTest() {
@@ -77,12 +77,12 @@
     ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
 }
 
-DisplayModePtr RefreshRateStatsTest::createConfig(DisplayModeId configId, int32_t configGroup,
-                                                  int64_t vsyncPeriod) {
-    return DisplayMode::Builder(static_cast<hal::HWConfigId>(configId.value()))
-            .setId(configId)
+DisplayModePtr RefreshRateStatsTest::createDisplayMode(DisplayModeId modeId, int32_t group,
+                                                       int64_t vsyncPeriod) {
+    return DisplayMode::Builder(static_cast<hal::HWConfigId>(modeId.value()))
+            .setId(modeId)
             .setVsyncPeriod(static_cast<int32_t>(vsyncPeriod))
-            .setConfigGroup(configGroup)
+            .setGroup(group)
             .build();
 }
 
@@ -91,7 +91,7 @@
  * Test cases
  */
 TEST_F(RefreshRateStatsTest, oneConfigTest) {
-    init({createConfig(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90)});
+    init({createDisplayMode(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90)});
 
     EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
     EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
@@ -110,7 +110,7 @@
     EXPECT_LT(screenOff, times["ScreenOff"]);
     EXPECT_EQ(0u, times.count("90.00fps"));
 
-    const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromConfigId(CONFIG_ID_0).getFps();
+    const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps();
     mRefreshRateStats->setRefreshRate(config0Fps);
     mRefreshRateStats->setPowerMode(PowerMode::ON);
     screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
@@ -138,8 +138,8 @@
 }
 
 TEST_F(RefreshRateStatsTest, twoConfigsTest) {
-    init({createConfig(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90),
-          createConfig(CONFIG_ID_1, CONFIG_GROUP_0, VSYNC_60)});
+    init({createDisplayMode(CONFIG_ID_0, CONFIG_GROUP_0, VSYNC_90),
+          createDisplayMode(CONFIG_ID_1, CONFIG_GROUP_0, VSYNC_60)});
 
     EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
     EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1));
@@ -158,8 +158,8 @@
     times = mRefreshRateStats->getTotalTimes();
     EXPECT_LT(screenOff, times["ScreenOff"]);
 
-    const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromConfigId(CONFIG_ID_0).getFps();
-    const auto config1Fps = mRefreshRateConfigs->getRefreshRateFromConfigId(CONFIG_ID_1).getFps();
+    const auto config0Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_0).getFps();
+    const auto config1Fps = mRefreshRateConfigs->getRefreshRateFromModeId(CONFIG_ID_1).getFps();
     mRefreshRateStats->setRefreshRate(config0Fps);
     mRefreshRateStats->setPowerMode(PowerMode::ON);
     screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index e688e10..e46a270 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -52,7 +52,7 @@
     SchedulerTest();
 
     const scheduler::RefreshRateConfigs
-            mConfigs{{DisplayMode::Builder(0).setVsyncPeriod(16'666'667).setConfigGroup(0).build()},
+            mConfigs{{DisplayMode::Builder(0).setVsyncPeriod(16'666'667).setGroup(0).build()},
                      DisplayModeId(0)};
 
     mock::SchedulerCallback mSchedulerCallback;
@@ -69,6 +69,8 @@
     Scheduler::ConnectionHandle mConnectionHandle;
     mock::EventThread* mEventThread;
     sp<MockEventThreadConnection> mEventThreadConnection;
+
+    TestableSurfaceFlinger mFlinger;
 };
 
 SchedulerTest::SchedulerTest() {
@@ -166,25 +168,35 @@
     mScheduler.chooseRefreshRateForContent();
 }
 
-TEST_F(SchedulerTest, testDispatchCachedReportedConfig) {
+TEST_F(SchedulerTest, testDispatchCachedReportedMode) {
     // If the optional fields are cleared, the function should return before
-    // onConfigChange is called.
+    // onModeChange is called.
     mScheduler.clearOptionalFieldsInFeatures();
-    EXPECT_NO_FATAL_FAILURE(mScheduler.dispatchCachedReportedConfig());
-    EXPECT_CALL(*mEventThread, onConfigChanged(_, _, _)).Times(0);
+    EXPECT_NO_FATAL_FAILURE(mScheduler.dispatchCachedReportedMode());
+    EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0);
 }
 
-TEST_F(SchedulerTest, onNonPrimaryDisplayConfigChanged_invalidParameters) {
-    DisplayModeId configId = DisplayModeId(111);
+TEST_F(SchedulerTest, onNonPrimaryDisplayModeChanged_invalidParameters) {
+    DisplayModeId modeId = DisplayModeId(111);
     nsecs_t vsyncPeriod = 111111;
 
     // If the handle is incorrect, the function should return before
-    // onConfigChange is called.
+    // onModeChange is called.
     Scheduler::ConnectionHandle invalidHandle = {.id = 123};
-    EXPECT_NO_FATAL_FAILURE(mScheduler.onNonPrimaryDisplayConfigChanged(invalidHandle,
-                                                                        PHYSICAL_DISPLAY_ID,
-                                                                        configId, vsyncPeriod));
-    EXPECT_CALL(*mEventThread, onConfigChanged(_, _, _)).Times(0);
+    EXPECT_NO_FATAL_FAILURE(mScheduler.onNonPrimaryDisplayModeChanged(invalidHandle,
+                                                                      PHYSICAL_DISPLAY_ID, modeId,
+                                                                      vsyncPeriod));
+    EXPECT_CALL(*mEventThread, onModeChanged(_, _, _)).Times(0);
+}
+
+TEST_F(SchedulerTest, calculateExtraBufferCount) {
+    EXPECT_EQ(0, mFlinger.calculateExtraBufferCount(Fps(60), 30ms));
+    EXPECT_EQ(1, mFlinger.calculateExtraBufferCount(Fps(90), 30ms));
+    EXPECT_EQ(2, mFlinger.calculateExtraBufferCount(Fps(120), 30ms));
+
+    EXPECT_EQ(1, mFlinger.calculateExtraBufferCount(Fps(60), 40ms));
+
+    EXPECT_EQ(0, mFlinger.calculateExtraBufferCount(Fps(60), 10ms));
 }
 
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
index e060df2..a6d07d0 100644
--- a/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SetFrameRateTest.cpp
@@ -185,7 +185,7 @@
 
     EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
     EXPECT_CALL(*vsyncTracker, currentPeriod())
-            .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+            .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
     EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
     mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
                             std::move(eventThread), std::move(sfEventThread));
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
index 8552e15..b713334 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_HandleTransactionLockedTest.cpp
@@ -669,7 +669,7 @@
     // --------------------------------------------------------------------
     // Call Expectations
 
-    EXPECT_CALL(*displaySurface, resizeBuffers(newWidth, oldHeight)).Times(1);
+    EXPECT_CALL(*displaySurface, resizeBuffers(ui::Size(newWidth, oldHeight))).Times(1);
 
     // --------------------------------------------------------------------
     // Invocation
@@ -714,7 +714,7 @@
     // --------------------------------------------------------------------
     // Call Expectations
 
-    EXPECT_CALL(*displaySurface, resizeBuffers(oldWidth, newHeight)).Times(1);
+    EXPECT_CALL(*displaySurface, resizeBuffers(ui::Size(oldWidth, newHeight))).Times(1);
 
     // --------------------------------------------------------------------
     // Invocation
@@ -764,7 +764,7 @@
     // --------------------------------------------------------------------
     // Call Expectations
 
-    EXPECT_CALL(*displaySurface, resizeBuffers(kNewWidth, kNewHeight)).Times(1);
+    EXPECT_CALL(*displaySurface, resizeBuffers(kNewSize.getSize())).Times(1);
 
     // --------------------------------------------------------------------
     // Invocation
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index 2b5cb77..e32c4bf 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -246,7 +246,7 @@
                                             .setVsyncPeriod(DEFAULT_VSYNC_PERIOD)
                                             .setDpiX(DEFAULT_DPI)
                                             .setDpiY(DEFAULT_DPI)
-                                            .setConfigGroup(0)
+                                            .setGroup(0)
                                             .build();
         DisplayModes modes{activeMode};
         state.physical = {.id = *displayId,
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index d3e90e3..3f9dd01 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -80,20 +80,19 @@
         return mFeatures.touch == Scheduler::TouchState::Active;
     }
 
-    void dispatchCachedReportedConfig() {
+    void dispatchCachedReportedMode() {
         std::lock_guard<std::mutex> lock(mFeatureStateLock);
-        return Scheduler::dispatchCachedReportedConfig();
+        return Scheduler::dispatchCachedReportedMode();
     }
 
     void clearOptionalFieldsInFeatures() {
         std::lock_guard<std::mutex> lock(mFeatureStateLock);
-        mFeatures.cachedConfigChangedParams.reset();
+        mFeatures.cachedModeChangedParams.reset();
     }
 
-    void onNonPrimaryDisplayConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
-                                          DisplayModeId configId, nsecs_t vsyncPeriod) {
-        return Scheduler::onNonPrimaryDisplayConfigChanged(handle, displayId, configId,
-                                                           vsyncPeriod);
+    void onNonPrimaryDisplayModeChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
+                                        DisplayModeId modeId, nsecs_t vsyncPeriod) {
+        return Scheduler::onNonPrimaryDisplayModeChanged(handle, displayId, modeId, vsyncPeriod);
     }
 
     ~TestableScheduler() {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 6b5109f..ce2bfef 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -41,6 +41,7 @@
 #include "SurfaceFlingerDefaultFactory.h"
 #include "SurfaceInterceptor.h"
 #include "TestableScheduler.h"
+#include "mock/DisplayHardware/MockComposer.h"
 #include "mock/MockDisplayIdGenerator.h"
 #include "mock/MockFrameTimeline.h"
 #include "mock/MockFrameTracer.h"
@@ -209,26 +210,26 @@
                         std::unique_ptr<scheduler::VSyncTracker> vsyncTracker,
                         std::unique_ptr<EventThread> appEventThread,
                         std::unique_ptr<EventThread> sfEventThread,
-                        ISchedulerCallback* callback = nullptr, bool hasMultipleConfigs = false) {
-        DisplayModes configs{DisplayMode::Builder(0)
-                                     .setId(DisplayModeId(0))
-                                     .setVsyncPeriod(16'666'667)
-                                     .setConfigGroup(0)
-                                     .build()};
+                        ISchedulerCallback* callback = nullptr, bool hasMultipleModes = false) {
+        DisplayModes modes{DisplayMode::Builder(0)
+                                   .setId(DisplayModeId(0))
+                                   .setVsyncPeriod(16'666'667)
+                                   .setGroup(0)
+                                   .build()};
 
-        if (hasMultipleConfigs) {
-            configs.emplace_back(DisplayMode::Builder(1)
-                                         .setId(DisplayModeId(1))
-                                         .setVsyncPeriod(11'111'111)
-                                         .setConfigGroup(0)
-                                         .build());
+        if (hasMultipleModes) {
+            modes.emplace_back(DisplayMode::Builder(1)
+                                       .setId(DisplayModeId(1))
+                                       .setVsyncPeriod(11'111'111)
+                                       .setGroup(0)
+                                       .build());
         }
 
-        const auto currConfig = DisplayModeId(0);
+        const auto currMode = DisplayModeId(0);
         mFlinger->mRefreshRateConfigs =
-                std::make_unique<scheduler::RefreshRateConfigs>(configs, currConfig);
+                std::make_unique<scheduler::RefreshRateConfigs>(modes, currMode);
         const auto currFps =
-                mFlinger->mRefreshRateConfigs->getRefreshRateFromConfigId(currConfig).getFps();
+                mFlinger->mRefreshRateConfigs->getRefreshRateFromModeId(currMode).getFps();
         mFlinger->mRefreshRateStats =
                 std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mTimeStats, currFps,
                                                               /*powerMode=*/hal::PowerMode::OFF);
@@ -390,6 +391,11 @@
 
     auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); }
 
+    auto calculateExtraBufferCount(Fps maxSupportedRefreshRate,
+                                   std::chrono::nanoseconds presentLatency) const {
+        return SurfaceFlinger::calculateExtraBufferCount(maxSupportedRefreshRate, presentLatency);
+    }
+
     /* ------------------------------------------------------------------------
      * Read-only access to private data to assert post-conditions.
      */
@@ -478,7 +484,7 @@
         static constexpr hal::HWDisplayId DEFAULT_HWC_DISPLAY_ID = 1000;
         static constexpr int32_t DEFAULT_WIDTH = 1920;
         static constexpr int32_t DEFAULT_HEIGHT = 1280;
-        static constexpr int32_t DEFAULT_REFRESH_RATE = 16'666'666;
+        static constexpr int32_t DEFAULT_VSYNC_PERIOD = 16'666'666;
         static constexpr int32_t DEFAULT_CONFIG_GROUP = 7;
         static constexpr int32_t DEFAULT_DPI = 320;
         static constexpr hal::HWConfigId DEFAULT_ACTIVE_CONFIG = 0;
@@ -503,8 +509,8 @@
             return *this;
         }
 
-        auto& setRefreshRate(int32_t refreshRate) {
-            mRefreshRate = refreshRate;
+        auto& setVsyncPeriod(int32_t vsyncPeriod) {
+            mVsyncPeriod = vsyncPeriod;
             return *this;
         }
 
@@ -533,7 +539,12 @@
             return *this;
         }
 
-        void inject(TestableSurfaceFlinger* flinger, Hwc2::Composer* composer) {
+        void inject(TestableSurfaceFlinger* flinger, Hwc2::mock::Composer* composer) {
+            using ::testing::_;
+            using ::testing::DoAll;
+            using ::testing::Return;
+            using ::testing::SetArgPointee;
+
             static const std::unordered_set<hal::Capability> defaultCapabilities;
             if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities;
 
@@ -548,15 +559,39 @@
             display->setPowerMode(mPowerMode);
             flinger->mutableHwcDisplayData()[mDisplayId].hwcDisplay = std::move(display);
 
-            auto config = DisplayMode::Builder(mActiveConfig)
-                                  .setWidth(mWidth)
-                                  .setHeight(mHeight)
-                                  .setVsyncPeriod(mRefreshRate)
-                                  .setDpiX(mDpiX)
-                                  .setDpiY(mDpiY)
-                                  .setConfigGroup(mConfigGroup)
-                                  .build();
-            flinger->mutableHwcDisplayData()[mDisplayId].modes.push_back(config);
+            EXPECT_CALL(*composer, getDisplayConfigs(mHwcDisplayId, _))
+                    .WillRepeatedly(
+                            DoAll(SetArgPointee<1>(std::vector<hal::HWConfigId>{mActiveConfig}),
+                                  Return(hal::Error::NONE)));
+
+            EXPECT_CALL(*composer,
+                        getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::WIDTH, _))
+                    .WillRepeatedly(DoAll(SetArgPointee<3>(mWidth), Return(hal::Error::NONE)));
+
+            EXPECT_CALL(*composer,
+                        getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::HEIGHT,
+                                            _))
+                    .WillRepeatedly(DoAll(SetArgPointee<3>(mHeight), Return(hal::Error::NONE)));
+
+            EXPECT_CALL(*composer,
+                        getDisplayAttribute(mHwcDisplayId, mActiveConfig,
+                                            hal::Attribute::VSYNC_PERIOD, _))
+                    .WillRepeatedly(
+                            DoAll(SetArgPointee<3>(mVsyncPeriod), Return(hal::Error::NONE)));
+
+            EXPECT_CALL(*composer,
+                        getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::DPI_X, _))
+                    .WillRepeatedly(DoAll(SetArgPointee<3>(mDpiX), Return(hal::Error::NONE)));
+
+            EXPECT_CALL(*composer,
+                        getDisplayAttribute(mHwcDisplayId, mActiveConfig, hal::Attribute::DPI_Y, _))
+                    .WillRepeatedly(DoAll(SetArgPointee<3>(mDpiY), Return(hal::Error::NONE)));
+
+            EXPECT_CALL(*composer,
+                        getDisplayAttribute(mHwcDisplayId, mActiveConfig,
+                                            hal::Attribute::CONFIG_GROUP, _))
+                    .WillRepeatedly(
+                            DoAll(SetArgPointee<3>(mConfigGroup), Return(hal::Error::NONE)));
 
             if (mHwcDisplayType == hal::DisplayType::PHYSICAL) {
                 const auto physicalId = PhysicalDisplayId::tryCast(mDisplayId);
@@ -582,10 +617,10 @@
         hal::HWDisplayId mHwcDisplayId = DEFAULT_HWC_DISPLAY_ID;
         int32_t mWidth = DEFAULT_WIDTH;
         int32_t mHeight = DEFAULT_HEIGHT;
-        int32_t mRefreshRate = DEFAULT_REFRESH_RATE;
+        int32_t mVsyncPeriod = DEFAULT_VSYNC_PERIOD;
         int32_t mDpiX = DEFAULT_DPI;
-        int32_t mConfigGroup = DEFAULT_CONFIG_GROUP;
         int32_t mDpiY = DEFAULT_DPI;
+        int32_t mConfigGroup = DEFAULT_CONFIG_GROUP;
         hal::HWConfigId mActiveConfig = DEFAULT_ACTIVE_CONFIG;
         hal::PowerMode mPowerMode = DEFAULT_POWER_MODE;
         const std::unordered_set<hal::Capability>* mCapabilities = nullptr;
@@ -603,6 +638,21 @@
                 mHwcDisplayId(hwcDisplayId) {
             mCreationArgs.connectionType = connectionType;
             mCreationArgs.isPrimary = isPrimary;
+
+            mActiveModeId = DisplayModeId(0);
+            DisplayModePtr activeMode =
+                    DisplayMode::Builder(FakeHwcDisplayInjector::DEFAULT_ACTIVE_CONFIG)
+                            .setId(mActiveModeId)
+                            .setWidth(FakeHwcDisplayInjector::DEFAULT_WIDTH)
+                            .setHeight(FakeHwcDisplayInjector::DEFAULT_HEIGHT)
+                            .setVsyncPeriod(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD)
+                            .setDpiX(FakeHwcDisplayInjector::DEFAULT_DPI)
+                            .setDpiY(FakeHwcDisplayInjector::DEFAULT_DPI)
+                            .setGroup(0)
+                            .build();
+
+            DisplayModes modes{activeMode};
+            mCreationArgs.supportedModes = modes;
         }
 
         sp<IBinder> token() const { return mDisplayToken; }
@@ -625,6 +675,16 @@
 
         auto& mutableDisplayDevice() { return mFlinger.mutableDisplays()[mDisplayToken]; }
 
+        auto& setActiveMode(DisplayModeId mode) {
+            mActiveModeId = mode;
+            return *this;
+        }
+
+        auto& setSupportedModes(DisplayModes mode) {
+            mCreationArgs.supportedModes = mode;
+            return *this;
+        }
+
         auto& setNativeWindow(const sp<ANativeWindow>& nativeWindow) {
             mCreationArgs.nativeWindow = nativeWindow;
             return *this;
@@ -677,6 +737,9 @@
             state.isSecure = mCreationArgs.isSecure;
 
             sp<DisplayDevice> device = new DisplayDevice(mCreationArgs);
+            if (!device->isVirtual()) {
+                device->setActiveMode(mActiveModeId);
+            }
             mFlinger.mutableDisplays().emplace(mDisplayToken, device);
             mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
             mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
@@ -693,11 +756,12 @@
         sp<BBinder> mDisplayToken = new BBinder();
         DisplayDeviceCreationArgs mCreationArgs;
         const std::optional<hal::HWDisplayId> mHwcDisplayId;
+        DisplayModeId mActiveModeId;
     };
 
 private:
     void setVsyncEnabled(bool) override {}
-    void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ConfigEvent) override {}
+    void changeRefreshRate(const Scheduler::RefreshRate&, Scheduler::ModeEvent) override {}
     void repaintEverythingForHWC() override {}
     void kernelTimerChanged(bool) override {}
     void triggerOnFrameRateOverridesChanged() {}
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 0ac5845..eb2c1ba 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -72,7 +72,7 @@
 
         EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
         EXPECT_CALL(*mVSyncTracker, currentPeriod())
-                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
 
         mFlinger.setupScheduler(std::unique_ptr<mock::VsyncController>(mVsyncController),
                                 std::unique_ptr<mock::VSyncTracker>(mVSyncTracker),
diff --git a/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
new file mode 100644
index 0000000..aa6798d
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/TransactionSurfaceFrameTest.cpp
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/SurfaceComposerClient.h>
+#include <log/log.h>
+#include <utils/String8.h>
+
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockVsyncController.h"
+
+namespace android {
+
+using testing::_;
+using testing::Mock;
+using testing::Return;
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using PresentState = frametimeline::SurfaceFrame::PresentState;
+
+class TransactionSurfaceFrameTest : public testing::Test {
+public:
+    TransactionSurfaceFrameTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+        setupScheduler();
+        setupComposer(0);
+    }
+
+    ~TransactionSurfaceFrameTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+
+    sp<BufferStateLayer> createBufferStateLayer() {
+        sp<Client> client;
+        LayerCreationArgs args(mFlinger.flinger(), client, "buffer-state-layer", 100, 100, 0,
+                               LayerMetadata());
+        return new BufferStateLayer(args);
+    }
+
+    void commitTransaction(Layer* layer) {
+        layer->pushPendingState();
+        // After pushing the state, the currentState should not store any BufferlessSurfaceFrames
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        auto c = layer->getCurrentState();
+        if (layer->applyPendingStates(&c)) {
+            layer->commitTransaction(c);
+        }
+    }
+
+    void setupScheduler() {
+        auto eventThread = std::make_unique<mock::EventThread>();
+        auto sfEventThread = std::make_unique<mock::EventThread>();
+
+        EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*eventThread, createEventConnection(_, _))
+                .WillOnce(Return(new EventThreadConnection(eventThread.get(), /*callingUid=*/0,
+                                                           ResyncCallback())));
+
+        EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+        EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+                .WillOnce(Return(new EventThreadConnection(sfEventThread.get(), /*callingUid=*/0,
+                                                           ResyncCallback())));
+
+        auto vsyncController = std::make_unique<mock::VsyncController>();
+        auto vsyncTracker = std::make_unique<mock::VSyncTracker>();
+
+        EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+        EXPECT_CALL(*vsyncTracker, currentPeriod())
+                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_VSYNC_PERIOD));
+        EXPECT_CALL(*vsyncTracker, nextAnticipatedVSyncTimeFrom(_)).WillRepeatedly(Return(0));
+        mFlinger.setupScheduler(std::move(vsyncController), std::move(vsyncTracker),
+                                std::move(eventThread), std::move(sfEventThread));
+    }
+
+    void setupComposer(uint32_t virtualDisplayCount) {
+        mComposer = new Hwc2::mock::Composer();
+        EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+        mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+        Mock::VerifyAndClear(mComposer);
+    }
+
+    TestableSurfaceFlinger mFlinger;
+    Hwc2::mock::Composer* mComposer = nullptr;
+    FenceToFenceTimeMap fenceFactory;
+    client_cache_t mClientCache;
+
+    void PresentedSurfaceFrameForBufferlessTransaction() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
+                                                             10);
+        EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_TRUE(layer->mCurrentState.bufferSurfaceFrameTX == nullptr);
+        const auto surfaceFrame = layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
+        commitTransaction(layer.get());
+        EXPECT_EQ(1, surfaceFrame->getToken());
+        EXPECT_EQ(PresentState::Presented, surfaceFrame->getPresentState());
+    }
+
+    void PresentedSurfaceFrameForBufferTransaction() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+        sp<Fence> fence(new Fence());
+        auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
+        sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+        layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        acquireFence->signalForTest(12);
+
+        commitTransaction(layer.get());
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto& surfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+        // Buffers are presented only at latch time.
+        EXPECT_EQ(PresentState::Unknown, surfaceFrame->getPresentState());
+
+        bool computeVisisbleRegions;
+        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+
+        EXPECT_EQ(1, surfaceFrame->getToken());
+        EXPECT_EQ(PresentState::Presented, surfaceFrame->getPresentState());
+    }
+
+    void DroppedSurfaceFrameForBufferTransaction() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+
+        sp<Fence> fence1(new Fence());
+        auto acquireFence1 = fenceFactory.createFenceTimeForTest(fence1);
+        sp<GraphicBuffer> buffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+        layer->setBuffer(buffer1, fence1, 10, 20, false, mClientCache, 1, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto droppedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+
+        sp<Fence> fence2(new Fence());
+        auto acquireFence2 = fenceFactory.createFenceTimeForTest(fence2);
+        sp<GraphicBuffer> buffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+        layer->setBuffer(buffer2, fence2, 10, 20, false, mClientCache, 1, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        acquireFence2->signalForTest(12);
+
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto& presentedSurfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+
+        commitTransaction(layer.get());
+        bool computeVisisbleRegions;
+        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+
+        EXPECT_EQ(1, droppedSurfaceFrame->getToken());
+        EXPECT_EQ(PresentState::Dropped, droppedSurfaceFrame->getPresentState());
+
+        EXPECT_EQ(1, presentedSurfaceFrame->getToken());
+        EXPECT_EQ(PresentState::Presented, presentedSurfaceFrame->getPresentState());
+    }
+
+    void BufferlessSurfaceFramePromotedToBufferSurfaceFrame() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
+                                                             10);
+
+        EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+
+        sp<Fence> fence(new Fence());
+        auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
+        sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+
+        layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        acquireFence->signalForTest(12);
+
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto& surfaceFrame = layer->mCurrentState.bufferSurfaceFrameTX;
+
+        commitTransaction(layer.get());
+        EXPECT_EQ(1, surfaceFrame->getToken());
+        // Buffers are presented only at latch time.
+        EXPECT_EQ(PresentState::Unknown, surfaceFrame->getPresentState());
+
+        bool computeVisisbleRegions;
+        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+
+        EXPECT_EQ(PresentState::Presented, surfaceFrame->getPresentState());
+    }
+
+    void BufferlessSurfaceFrameNotCreatedIfBufferSufaceFrameExists() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+        sp<Fence> fence(new Fence());
+        auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
+        sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+
+        layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
+                         {/*vsyncId*/ 1, /*inputEventId*/ 0});
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
+                                                             10);
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+    }
+
+    void MultipleSurfaceFramesPresentedTogether() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
+                                                             10);
+        EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto bufferlessSurfaceFrame1 =
+                layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
+
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 4, /*inputEventId*/ 0},
+                                                             10);
+        EXPECT_EQ(2u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto bufferlessSurfaceFrame2 = layer->mCurrentState.bufferlessSurfaceFramesTX[4];
+
+        sp<Fence> fence(new Fence());
+        auto acquireFence = fenceFactory.createFenceTimeForTest(fence);
+        sp<GraphicBuffer> buffer{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
+
+        layer->setBuffer(buffer, fence, 10, 20, false, mClientCache, 1, std::nullopt,
+                         {/*vsyncId*/ 3, /*inputEventId*/ 0});
+        EXPECT_EQ(2u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_NE(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto& bufferSurfaceFrameTX = layer->mCurrentState.bufferSurfaceFrameTX;
+
+        acquireFence->signalForTest(12);
+
+        commitTransaction(layer.get());
+
+        EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken());
+        EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame1->getPresentState());
+
+        EXPECT_EQ(4, bufferlessSurfaceFrame2->getToken());
+        EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState());
+
+        EXPECT_EQ(3, bufferSurfaceFrameTX->getToken());
+        // Buffers are presented only at latch time.
+        EXPECT_EQ(PresentState::Unknown, bufferSurfaceFrameTX->getPresentState());
+
+        bool computeVisisbleRegions;
+        layer->updateTexImage(computeVisisbleRegions, 15, 0);
+
+        EXPECT_EQ(PresentState::Presented, bufferSurfaceFrameTX->getPresentState());
+    }
+
+    void MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
+                                                             10);
+        EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto bufferlessSurfaceFrame1 =
+                layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
+
+        layer->pushPendingState();
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 2, /*inputEventId*/ 0},
+                                                             12);
+        EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto bufferlessSurfaceFrame2 =
+                layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 2);
+
+        commitTransaction(layer.get());
+
+        EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken());
+        EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame1->getPresentState());
+        EXPECT_EQ(10, bufferlessSurfaceFrame1->getActuals().endTime);
+
+        EXPECT_EQ(2, bufferlessSurfaceFrame2->getToken());
+        EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState());
+        EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime);
+    }
+
+    void MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken() {
+        sp<BufferStateLayer> layer = createBufferStateLayer();
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
+                                                             10);
+        EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto bufferlessSurfaceFrame1 =
+                layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
+
+        layer->pushPendingState();
+        EXPECT_EQ(0u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+
+        layer->setFrameTimelineVsyncForBufferlessTransaction({/*vsyncId*/ 1, /*inputEventId*/ 0},
+                                                             12);
+        EXPECT_EQ(1u, layer->mCurrentState.bufferlessSurfaceFramesTX.size());
+        ASSERT_EQ(nullptr, layer->mCurrentState.bufferSurfaceFrameTX);
+        const auto bufferlessSurfaceFrame2 =
+                layer->mCurrentState.bufferlessSurfaceFramesTX.at(/*token*/ 1);
+
+        commitTransaction(layer.get());
+
+        EXPECT_EQ(1, bufferlessSurfaceFrame1->getToken());
+        EXPECT_EQ(PresentState::Unknown, bufferlessSurfaceFrame1->getPresentState());
+
+        EXPECT_EQ(1, bufferlessSurfaceFrame2->getToken());
+        EXPECT_EQ(PresentState::Presented, bufferlessSurfaceFrame2->getPresentState());
+        EXPECT_EQ(12, bufferlessSurfaceFrame2->getActuals().endTime);
+    }
+};
+
+TEST_F(TransactionSurfaceFrameTest, PresentedBufferlessSurfaceFrame) {
+    PresentedSurfaceFrameForBufferlessTransaction();
+}
+
+TEST_F(TransactionSurfaceFrameTest, PresentedBufferSurfaceFrame) {
+    PresentedSurfaceFrameForBufferTransaction();
+}
+
+TEST_F(TransactionSurfaceFrameTest, DroppedBufferSurfaceFrame) {
+    DroppedSurfaceFrameForBufferTransaction();
+}
+
+TEST_F(TransactionSurfaceFrameTest, BufferlessSurfaceFramePromotedToBufferSurfaceFrame) {
+    BufferlessSurfaceFramePromotedToBufferSurfaceFrame();
+}
+
+TEST_F(TransactionSurfaceFrameTest, BufferlessSurfaceFrameNotCreatedIfBufferSufaceFrameExists) {
+    BufferlessSurfaceFrameNotCreatedIfBufferSufaceFrameExists();
+}
+
+TEST_F(TransactionSurfaceFrameTest, MultipleSurfaceFramesPresentedTogether) {
+    MultipleSurfaceFramesPresentedTogether();
+}
+
+TEST_F(TransactionSurfaceFrameTest,
+       MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken) {
+    MergePendingStates_BufferlessSurfaceFramesWithoutOverlappingToken();
+}
+
+TEST_F(TransactionSurfaceFrameTest,
+       MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken) {
+    MergePendingStates_BufferlessSurfaceFramesWithOverlappingToken();
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index 40437bf..485b4ac 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -33,7 +33,7 @@
     MOCK_METHOD0(onScreenReleased, void());
     MOCK_METHOD0(onScreenAcquired, void());
     MOCK_METHOD2(onHotplugReceived, void(PhysicalDisplayId, bool));
-    MOCK_METHOD3(onConfigChanged, void(PhysicalDisplayId, DisplayModeId, nsecs_t));
+    MOCK_METHOD3(onModeChanged, void(PhysicalDisplayId, DisplayModeId, nsecs_t));
     MOCK_METHOD2(onFrameRateOverridesChanged,
                  void(PhysicalDisplayId, std::vector<FrameRateOverride>));
     MOCK_CONST_METHOD1(dump, void(std::string&));
diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp
index c18bf18..4f89353 100644
--- a/services/vibratorservice/Android.bp
+++ b/services/vibratorservice/Android.bp
@@ -36,7 +36,7 @@
         "libhidlbase",
         "liblog",
         "libutils",
-        "android.hardware.vibrator-unstable-cpp",
+        "android.hardware.vibrator-V2-cpp",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
diff --git a/services/vibratorservice/benchmarks/Android.bp b/services/vibratorservice/benchmarks/Android.bp
index d3130f4..7b4cc19 100644
--- a/services/vibratorservice/benchmarks/Android.bp
+++ b/services/vibratorservice/benchmarks/Android.bp
@@ -23,7 +23,7 @@
         "liblog",
         "libutils",
         "libvibratorservice",
-        "android.hardware.vibrator-unstable-cpp",
+        "android.hardware.vibrator-V2-cpp",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp
index 9af1b7b..ad85990 100644
--- a/services/vibratorservice/test/Android.bp
+++ b/services/vibratorservice/test/Android.bp
@@ -39,7 +39,7 @@
         "liblog",
         "libvibratorservice",
         "libutils",
-        "android.hardware.vibrator-unstable-cpp",
+        "android.hardware.vibrator-V2-cpp",
         "android.hardware.vibrator@1.0",
         "android.hardware.vibrator@1.1",
         "android.hardware.vibrator@1.2",
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 48090af..cb845a0 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -606,44 +606,9 @@
 VKAPI_ATTR
 VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice /*pdev*/,
                                             uint32_t /*queue_family*/,
-                                            VkSurfaceKHR surface_handle,
+                                            VkSurfaceKHR /*surface_handle*/,
                                             VkBool32* supported) {
-    ATRACE_CALL();
-
-    const Surface* surface = SurfaceFromHandle(surface_handle);
-    if (!surface) {
-        return VK_ERROR_SURFACE_LOST_KHR;
-    }
-    const ANativeWindow* window = surface->window.get();
-
-    int query_value;
-    int err = window->query(window, NATIVE_WINDOW_FORMAT, &query_value);
-    if (err != android::OK || query_value < 0) {
-        ALOGE("NATIVE_WINDOW_FORMAT query failed: %s (%d) value=%d",
-              strerror(-err), err, query_value);
-        return VK_ERROR_SURFACE_LOST_KHR;
-    }
-
-    android_pixel_format native_format =
-        static_cast<android_pixel_format>(query_value);
-
-    bool format_supported = false;
-    switch (native_format) {
-        case HAL_PIXEL_FORMAT_RGBA_8888:
-        case HAL_PIXEL_FORMAT_RGB_565:
-        case HAL_PIXEL_FORMAT_RGBA_FP16:
-        case HAL_PIXEL_FORMAT_RGBA_1010102:
-            format_supported = true;
-            break;
-        default:
-            break;
-    }
-
-    *supported = static_cast<VkBool32>(
-        format_supported || (surface->consumer_usage &
-                             (AHARDWAREBUFFER_USAGE_CPU_READ_MASK |
-                              AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) == 0);
-
+    *supported = VK_TRUE;
     return VK_SUCCESS;
 }